版博士V2.0程序
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

885 linhas
23 KiB

  1. const $ = require('../index');
  2. // const $ = require('../umd/gogocode')
  3. const config = require('./config');
  4. const jc1 = require('./code/simple1');
  5. const jc2 = require('./code/simple2');
  6. const hc1 = require('./code/simple1.html');
  7. test('$:first input is empty string should not throw error', () => {
  8. expect(() => {
  9. const G = $('')
  10. }).not.toThrow();
  11. })
  12. test('$: first input is empty object should throw error', () => {
  13. expect(() => {
  14. const G = $({});
  15. }).toThrow();
  16. })
  17. test('$: first input is undefined should not throw error', () => {
  18. expect(() => {
  19. const G = $(undefined);
  20. }).not.toThrow();
  21. })
  22. test('$: first input is null should not throw error ', () => {
  23. expect(() => {
  24. const G = $(null);
  25. }).not.toThrow();
  26. })
  27. test('$: second input is undefined should throw error ', () => {
  28. expect(() => {
  29. const G = $('var a = 1;', undefined);
  30. }).not.toThrow();
  31. })
  32. test('$: second input is null should throw error ', () => {
  33. expect(() => {
  34. const G = $('var a = 1;', null);
  35. }).toThrow();
  36. })
  37. test('$: second input is empty object should not throw error ', () => {
  38. expect(() => {
  39. const G = $('var a = 1;', {});
  40. }).not.toThrow();
  41. })
  42. test('$: second input is {isProgram: true} should not throw error ', () => {
  43. expect(() => {
  44. const G = $('var a = 1;', {isProgram: true});
  45. }).not.toThrow();
  46. })
  47. test('$: second input astFragment is empty should not throw error ', () => {
  48. expect(() => {
  49. const G = $('var a = 1;', { astFragment: '' });
  50. }).not.toThrow();
  51. })
  52. test('$: second input astFragment is empty should not throw error ', () => {
  53. expect(() => {
  54. const G = $('var a = 1;', { astFragment: 'test' });
  55. }).not.toThrow();
  56. })
  57. test('$: simple js code', () => {
  58. expect(() => {
  59. const G = $('var a = 1;');
  60. }).not.toThrow();
  61. })
  62. test('$: first input is AST object', () => {
  63. expect(() => {
  64. const node = $('var a = 1;').rootNode.node
  65. const G = $(node);
  66. }).not.toThrow();
  67. })
  68. test('$: first input is AST object result should be ok', () => {
  69. const node = $('var a = 1;').rootNode.node
  70. const G = $(node);
  71. const code = G.generate();
  72. expect(code).toBe('var a = 1;')
  73. })
  74. test('$: first input is $ object', () => {
  75. expect(() => {
  76. const node = $('var a = 1;')
  77. const G = $(node);
  78. }).not.toThrow();
  79. })
  80. test('$: first input is $ object result should be ok', () => {
  81. const node = $('var a = 1;')
  82. const G = $(node);
  83. const code = G.generate();
  84. expect(code).toBe('var a = 1;')
  85. })
  86. test('$: simple js code', () => {
  87. code = `
  88. var a = 1;
  89. function test(){
  90. a = b;
  91. }
  92. var obj = {
  93. a: 'a'
  94. };
  95. `
  96. expect(() => {
  97. const G = $(code);
  98. }).not.toThrow();
  99. })
  100. test('$: simple js object code', () => {
  101. code = `{
  102. a: 'a'
  103. };
  104. `
  105. expect(() => {
  106. const G = $(code);
  107. }).not.toThrow();
  108. })
  109. test('$: comments code', () => {
  110. code = `//test`
  111. expect(() => {
  112. const G = $(code);
  113. }).not.toThrow();
  114. })
  115. test('$: comments code', () => {
  116. code = `{a}`
  117. expect(() => {
  118. const G = $(code);
  119. }).not.toThrow();
  120. })
  121. test('$: input is found code ', () => {
  122. code = `
  123. var a = 1;
  124. function test(){
  125. a = b;
  126. }
  127. var obj = {
  128. a: 'a'
  129. };
  130. `
  131. expect(() => {
  132. const G = $(code).find('var a = $_$;');
  133. $(G);
  134. }).not.toThrow();
  135. })
  136. test('$: nodeType ', () => {
  137. code = { nodeType: 'test' };
  138. expect(() => {
  139. const G = $(code);
  140. }).not.toThrow();
  141. })
  142. test('$: isProgram is true', () => {
  143. code = { nodeType: 'test' };
  144. expect(() => {
  145. const G = $('var a = 1;', { isProgram: true });
  146. }).not.toThrow();
  147. })
  148. test('$: astFragment', () => {
  149. expect(() => {
  150. const code = `const $_$a$_$ = 'test'`;
  151. const option = {
  152. astFragment: {
  153. a: 'a'
  154. }
  155. };
  156. const G = $(code, option);
  157. }).not.toThrow();
  158. })
  159. test('$: astFragment', () => {
  160. const code = `const $_$a$_$ = 'test'`;
  161. const option = {
  162. astFragment: {
  163. a: 'a'
  164. }
  165. };
  166. const G = $(code, option);
  167. const compareCode = G.generate();
  168. expect(compareCode).toBe(`const a = 'test'`);
  169. })
  170. test('$: wrong code', () => {
  171. const code = `
  172. function test(){
  173. `
  174. expect(() => {
  175. const G = $(code);
  176. }).not.toThrow();
  177. })
  178. test('$: jsx code', () => {
  179. const code = `<div>test</div>`;
  180. expect(() => {
  181. const G = $(code);
  182. }).not.toThrow();
  183. })
  184. test('$: simple1 code should not throw error', () => {
  185. expect(() => {
  186. const G = $(jc1);
  187. }).not.toThrow();
  188. })
  189. test('$: simple2 code should not throw error', () => {
  190. expect(() => {
  191. const G = $(jc2);
  192. }).not.toThrow();
  193. })
  194. test('$: html empty string should not throw error', () => {
  195. const code = ``;
  196. expect(() => {
  197. const G = $(code, config.html);
  198. }).not.toThrow();
  199. })
  200. test('$: html DOCTYPE code', () => {
  201. const code = `<!DOCTYPE html>`;
  202. expect(() => {
  203. const G = $(code, config.html);
  204. }).not.toThrow();
  205. })
  206. test('$: html DOCTYPE code', () => {
  207. const code = `<!DOCTYPE html>`;
  208. const G = $(code, config.html);
  209. const result = G.generate();
  210. expect(result).toBe('<!doctype html>');
  211. })
  212. test('$: simple html code', () => {
  213. const code = `<div>test</div>`;
  214. expect(() => {
  215. const G = $(code, config.html);
  216. }).not.toThrow();
  217. })
  218. test('$: simple html code result should be ok', () => {
  219. const code = `<div>test</div>`;
  220. const G = $(code, config.html);
  221. const result = G.generate();
  222. expect(result).toBe(code);
  223. })
  224. test('$: simple1 html code', () => {
  225. expect(() => {
  226. const G = $(hc1, config.html);
  227. }).not.toThrow();
  228. })
  229. test('$: simple1 html code, isProgram option config', () => {
  230. expect(() => {
  231. const G = $(hc1, { isProgram: true, ...config.html });
  232. }).not.toThrow();
  233. })
  234. test('$: simple1 html code result should be ok', () => {
  235. const G = $(hc1, config.html);
  236. const result = G.generate();
  237. expect(result.indexOf('<html>') > -1).toBeTruthy();
  238. })
  239. test('$: simple1 html code', () => {
  240. const G = $(hc1, config.html).find('<span>$_$</span>');
  241. const code = G.generate();
  242. expect(code).toBe('<span>test</span>');
  243. })
  244. // todo 而且astFragment的value必须是ast节点
  245. // test('$: simple1 html code use fragment', () => {
  246. // const option = {
  247. // astFragment: {
  248. // a: 'a'
  249. // },
  250. // ...config.html
  251. // };
  252. // const code = `<span>$_$a$_$</span>`
  253. // const G = $(code, option);
  254. // const compareCode = G.generate();
  255. // expect(compareCode).toBe('<span>test</span>');
  256. // })
  257. test('getfunction', () => {
  258. expect(() => {
  259. $(`function greet() {
  260. a
  261. function greet() {
  262. b
  263. }
  264. }`)
  265. .find(`function greet() {}`)
  266. .each(item => {
  267. $(item.attr('body')).generate()
  268. })
  269. }).not.toThrow()
  270. })
  271. test('getfunctionbody', () => {
  272. expect(() => {
  273. $(code)
  274. .find(`function greet() {}`)
  275. .each(item => {
  276. $(item.attr('body')).generate() // 函数内容
  277. item.attr('body') // 函数内容对应的ast节点
  278. })
  279. .root()
  280. .find(`function greet() {
  281. $_$
  282. }`)
  283. .each(item => {
  284. item.match[0][0].value // 函数内容
  285. item.match[0][0].node // 函数内容对应的ast节点
  286. })
  287. }).not.toThrow()
  288. })
  289. test('getif', () => {
  290. expect(() => {
  291. $(`if (a && 1 || 0) { b } else { c; dosth() }`)
  292. .find(`if ($_$1) { $_$2 } else { $_$3 }`)
  293. .each(item => {
  294. console.log(item.match)
  295. })
  296. }).not.toThrow()
  297. })
  298. test('getclass', () => {
  299. expect(() => {
  300. $(`class Car {
  301. color = c
  302. a = 1
  303. size = s
  304. }`)
  305. .find(`class Car {
  306. color = $_$c
  307. size = $_$s
  308. }`)
  309. .each(item => {
  310. console.log(item.match)
  311. })
  312. }).not.toThrow()
  313. })
  314. test('get obj property', () => {
  315. expect(() => {
  316. $(`const car = {
  317. x: 2,
  318. greet() {
  319. this.g = '';
  320. },
  321. a: '1'
  322. }`)
  323. // `greet() {}` parse 抛异常
  324. .find(`greet() {}`)
  325. .each(item => {
  326. console.log(item.match)
  327. })
  328. .root()
  329. .find(`{ a: '1' }`)
  330. .each(item => {
  331. console.log(item.match)
  332. })
  333. .root()
  334. .find(`const car = $_$`)
  335. .each(item => {
  336. // item.match是被通配符匹配到的节点
  337. if (item.match[0][0].node.type == 'ObjectExpression') {
  338. // 找到car被赋值的节点,判断是不是对象类型
  339. }
  340. })
  341. }).not.toThrow()
  342. })
  343. test('get type', () => {
  344. expect(() => {
  345. $(`const c:CheckBoxProps = {};
  346. CheckBoxProps.prop = null;
  347. (a, b: CheckBoxProps, CheckBoxProps) => {
  348. console.log()
  349. }
  350. `)
  351. .find('CheckBoxProps') // 找到的有可能是变量名,也有可能是类型定义
  352. .each(item => {
  353. if (item.parent().node.type == 'TSTypeReference') {
  354. // 判断其父节点是类型定义TSTypeReference,就找到了
  355. }
  356. })
  357. .root()
  358. .find('const $_$1:CheckBoxProps = $_$2')
  359. .each(item => {
  360. item.match
  361. })
  362. .root()
  363. .find(`($_$: CheckBoxProps) => {}`)
  364. .each(item => {
  365. item.match
  366. })
  367. }).not.toThrow()
  368. })
  369. test('get import', () => {
  370. expect(() => {
  371. $(`import '@ali/sd'
  372. import a from '@ali/sd'
  373. import('@ali/sd').then()
  374. export * from '@path/sth'
  375. export {a, b} from 'path/sth'
  376. `)
  377. .find(`import($_$)`) // 找到的有可能是变量名,也有可能是类型定义
  378. .each(item => {
  379. item.match
  380. })
  381. .root()
  382. .find(`export $_$ from '@path/sth'`)
  383. .each(item => {
  384. item.match
  385. })
  386. .root()
  387. .find(`export * from '@path/sth'`)
  388. .each(item => {
  389. item.match
  390. })
  391. .root()
  392. .find(`import $_$1 from '$_$2'`)
  393. .each(item => {
  394. item.match
  395. })
  396. }).not.toThrow()
  397. })
  398. test('replaceimport', () => {
  399. expect(() => {
  400. const res = $(`import a from 'bb/bb-plugin'
  401. import { useContext, userLogger } from '@as/mdw-hk'
  402. `)
  403. .find(`import $_$1 from '$_$2'`)
  404. .each(item => {
  405. const source = item.match[2][0].value;
  406. item.match[2][0].node.value = source.replace('bb/', 'bb/gogocode/');
  407. })
  408. .root()
  409. .replace(`import { useContext, $$$ } from '@as/mdw-hk'`, `import { useFContext, $$$ } from '@as/mdw-hk'`)
  410. // .replace(`import $_$ from 'bb/bb-plugin'`, `import $_$ from 'gogocode'`)
  411. .generate()
  412. }).not.toThrow()
  413. })
  414. test('findcall', () => {
  415. expect(() => {
  416. const res = $(`callfunc(am,b)`)
  417. .find('$_$()')
  418. .each(item => {
  419. item.match // 函数名
  420. item.node // 函数对应的ast节点
  421. item.attr('arguments') // 调用函数的入参
  422. })
  423. }).not.toThrow()
  424. })
  425. test('replacemethodname', () => {
  426. expect(() => {
  427. const res = $(`Page({
  428. onShow() { },
  429. data: { }
  430. })`)
  431. .replace(`Page({
  432. onShow() {
  433. $$$1
  434. },
  435. $$$2
  436. })`, `Page({
  437. render() {
  438. $$$1
  439. },
  440. $$$2
  441. })`)
  442. .generate()
  443. }).not.toThrow()
  444. })
  445. test('insert method', () => {
  446. expect(() => {
  447. const res = $(`Page({
  448. onShow() { },
  449. data: { }
  450. })`)
  451. .find(`Page({})`)
  452. .each(item => {
  453. $(item.attr('arguments.0')).append('properties', `init() {}`)
  454. // page的arguments[0]是第一个入参对象,通过attr获取到这个节点之后用$()转为AST实例,
  455. // 就可以链式调用进行后续操作,append第一个参数是第二个参数指定插入的位置
  456. })
  457. .root()
  458. .generate()
  459. }).not.toThrow()
  460. })
  461. test('modify jsx attr', () => {
  462. expect(() => {
  463. const res = $(`<View>
  464. <View name="1" class="active" />
  465. <View name="1" t="2">sd</View>
  466. </View>`)
  467. .replace(`<View name="1" $$$1>$$$2</View>`,`<View type="input" $$$1>$$$2</View>`)
  468. .generate()
  469. }).not.toThrow()
  470. })
  471. test('declaration', () => {
  472. expect(() => {
  473. const res = $(`const {a,b = {b1},c = 3} = d`)
  474. .find('const { $_$1 = $_$2 } = $_$3')
  475. .each(item => {
  476. const keyList = item.match[1].filter((item, i) => i%2 == 0)
  477. const obj = item.match[3][0].value
  478. const newkeyList = keyList.map((key, i) => {
  479. let dec = `${key.value} = ${obj}.${key.value}`
  480. if (item.match[2][i].value != key.value) {
  481. dec += ('||' + item.match[2][i].value)
  482. }
  483. return dec
  484. })
  485. item.replaceBy(`const ${newkeyList.join(', ')}`)
  486. })
  487. }).not.toThrow()
  488. })
  489. test('append', () => {
  490. expect(() => {
  491. const res = $(`function create(aaa) { bbb
  492. ccc
  493. }`)
  494. .find(`function create() {}`)
  495. .each(item => {
  496. $(item.attr('body')).append('body', `
  497. let type = 'success'
  498. console.log('success')
  499. `)
  500. })
  501. .generate()
  502. }).not.toThrow()
  503. })
  504. test('replacefunction', () => {
  505. expect(() => {
  506. const map = { input: 'textarea' }
  507. const res = $(`
  508. const componentList = [{
  509. index: 1,
  510. component: 'input'
  511. }, {
  512. index: 2,
  513. component: 'radio'
  514. }, {
  515. index: 3,
  516. component: 'checkbox'
  517. }]`)
  518. .replace('component: $_$', (match => {
  519. if (map[match[0][0].value]) {
  520. return `component: ${map[match[0][0].value]}`
  521. } else {
  522. return 'component: $_$'
  523. }
  524. }))
  525. .generate()
  526. }).not.toThrow()
  527. })
  528. test('replacefetch', () => {
  529. expect(() => {
  530. const res = $(`const fetch = () => {}; const noModify = 'fetch'`)
  531. .find('fetch')
  532. .each(item => {
  533. item.attr('name', 'request')
  534. })
  535. .root()
  536. .generate()
  537. }).not.toThrow()
  538. })
  539. test('getidentifier', () => {
  540. expect(() => {
  541. const iden =
  542. $(`(a.b.c && b) || (c && d)`)
  543. .find('$_$')
  544. .each(item => {
  545. if (item.parent().node.type == 'MemberExpression' && item.parent(1).node.type != 'MemberExpression') {
  546. console.log(item.parent().generate())
  547. } else if (item.parent().node.type != 'MemberExpression') {
  548. console.log(item.generate())
  549. }
  550. })
  551. }).not.toThrow()
  552. })
  553. test('replaceattr', () => {
  554. expect(() => {
  555. const res = $(`var a = {visibility:iconVisibility('coupon')}`)
  556. .replace(`{$_$:$_$1}`, '$_$:$_$1')
  557. .generate()
  558. }).not.toThrow()
  559. })
  560. test('replacestring2ident', () => {
  561. expect(() => {
  562. const pres = $('<p class="title"></p>')
  563. .replace(`<p class="$_$"></p>`, (match => {
  564. return `<View style={styles.${match[0][0].value}}></View>`
  565. }))
  566. .generate()
  567. }).not.toThrow()
  568. })
  569. test('replacejsxfor', () => {
  570. expect(() => {
  571. const res = $('<View style={styles.listItem} v-for="(item,index) in list"><Text style={styles.title}>AAA</Text></View>')
  572. .replace(`<View v-for="$_$2" $$$1>$$$2</View>`, (match => {
  573. const expression = $(match[2][0].value, { isProgram: false }); // 这是v-for后面整个字符串 (item,index) in list 需要单独转为ast解析
  574. const listKey = expression.attr('expression.right.name')
  575. const itemKey = expression.attr('expression.left.expressions.0.name')
  576. return `
  577. { ${listKey}.map(${itemKey}=>{
  578. return (<View $$$1>$$$2</View>);
  579. }) }`
  580. }))
  581. .generate()
  582. var res1 = $('var a = 1').find('var $_$1 = $_$2')
  583. }).not.toThrow()
  584. })
  585. test('replaceimg', () => {
  586. expect(() => {
  587. var code = $(`<View>
  588. <Image class="angle"/>
  589. <Image/>
  590. </View>`)
  591. .replace(`<Image/>`, (match, path) => {
  592. if (path.node.openingElement && path.node.openingElement.attributes.length) {
  593. }
  594. })
  595. }).not.toThrow()
  596. })
  597. test('selector not', () => {
  598. expect(() => {
  599. var code = $(`import A from 'a';
  600. import B from 'b';
  601. import C from 'c';`)
  602. .find(`import $_$1 from '$_$2'`)
  603. .each(item => {
  604. if (item.match[2][0].value != 'a') {
  605. return;
  606. }
  607. })
  608. }).not.toThrow()
  609. })
  610. test('parse decorator', () => {
  611. expect(() => {
  612. var code = $(`@Form.create()
  613. class Template extends React.PureComponent {
  614. render() {
  615. return (
  616. <div>
  617. Hello, Template!
  618. </div>
  619. );
  620. }
  621. }`)
  622. }).not.toThrow()
  623. })
  624. test('parse decorator', () => {
  625. const res = $(`function demo() { $_$content$_$ }`, {
  626. astFragment: {
  627. content: $('var a = 1', { isProgram: false }).node
  628. }
  629. }).generate()
  630. expect(res.match(`var a = 1`)).toBeTruthy()
  631. })
  632. test('parse html', () => {
  633. const res = $(`<div></div>`, {
  634. parseOptions: { language: 'html' }
  635. }).generate()
  636. expect(res.match(`<div></div>`)).toBeTruthy()
  637. })
  638. test('parse decorator', () => {
  639. expect(() => {
  640. const res = $(`
  641. @Form.create()
  642. class Template extends React.PureComponent {
  643. render() {
  644. return (
  645. <div>
  646. Hello, Template!
  647. </div>
  648. );
  649. }
  650. }`)
  651. // .find(`@Form.create()`)
  652. .generate()
  653. }).not.toThrow()
  654. })
  655. test('parse decorator 2', () => {
  656. expect(() => {
  657. const res = $(`
  658. import { Provide, Func, Inject } from '@midwayjs/decorator';
  659. import { FunctionHandler, FaaSContext } from '@ali/midway-faas';
  660. import render from '@ali/ice-faas-render';
  661. @Provide()
  662. @Func('render.handler', { event: 'HTTP', path: '/*' })
  663. export class RenderHandler implements FunctionHandler {
  664. @Inject()
  665. ctx: FaaSContext;
  666. @Inject('baseDir')
  667. baseDir: string;
  668. async handler() {
  669. await render(this.ctx, {
  670. title: 'ICE & Midway Hooks',
  671. g_config: {},
  672. baseDir: this.baseDir,
  673. favicon: 'https://img.alicdn.com/tfs/TB1.WE9xkL0gK0jSZFAXXcA9pXa-200-200.png',
  674. });
  675. }
  676. }
  677. `, {
  678. parseOptions: {
  679. ecmaVersion: 2015, ecmaFeatures: { legacyDecorators: true },
  680. plugins: [['decorators', { decoratorsBeforeExport: false }]] }
  681. })
  682. // .find(`@Form.create()`)
  683. }).not.toThrow()
  684. })
  685. test('parse decorator 3', () => {
  686. expect(() => {
  687. const res = $(`
  688. import { Component } from 'vue-class';
  689. import render from 'index.html';
  690. @Component({
  691. render,
  692. name: 'p',
  693. props: {}
  694. })
  695. export default class Posi extends Mask {
  696. value;
  697. get v(): string {
  698. return this.value
  699. }
  700. }
  701. `)
  702. // .replace(`import { $$$ } from 'vue-class'`, `import { $$$ } from 'vue-class1'`)
  703. // .generate();
  704. // .find(`@Form.create()`)
  705. }).not.toThrow()
  706. })
  707. test('parse html contains & ', () => {
  708. expect(() => {
  709. let res = $(`
  710. <template>
  711. <div>
  712. ss
  713. <div v-if="true && true">
  714. <a>wer{{ss}}qwre<i></i></a>
  715. </div>
  716. </div>
  717. </template>
  718. `, { parseOptions: { language: 'vue' } })
  719. .find('<template></template>')
  720. .find('<div></div>')
  721. .eq(1)
  722. .attr('content.attributes.0.value.content')
  723. var a = 1
  724. }).not.toThrow()
  725. })
  726. test('parse closing tag', () => {
  727. expect(() => {
  728. let res = $(`
  729. <template>
  730. <div class="todoList full-screen">
  731. <div class="todoList_tips" v-if="taskTotalInfo.noHandle > 0">
  732. <template v-if="searchType == 0">
  733. <span
  734. >还有<i>{{ taskTotalInfo.noHandle }}</i
  735. >笔工单尚未指派</span
  736. >
  737. </template>
  738. </div>
  739. </div>
  740. </template>
  741. `, { parseOptions: { language: 'vue' } })
  742. .find('<template></template>')
  743. .generate()
  744. res
  745. }).not.toThrow()
  746. })
  747. test('parse html contains > ', () => {
  748. let res = $(`
  749. <dd>1<5</dd> <view>我是打酱油</view>
  750. `, { parseOptions: { language: 'html' } })
  751. .replace(`<dd $$$1>$$$2</dd>`,
  752. `<dd test="zpzpzpzp" $$$1>$$$2</dd>`)
  753. .generate()
  754. console.log(res)
  755. expect(!!res.match('1<5</dd>')).toBeTruthy()
  756. })
  757. test('parse html attr contains > ', () => {
  758. let res = $(`
  759. <dd class="1<a">1<5</dd> <view>我是打酱油</view>
  760. `, { parseOptions: { language: 'html' } })
  761. .replace(`<dd $$$1>$$$2</dd>`,
  762. `<dd test="zpzpzpzp" $$$1>$$$2</dd>`)
  763. .generate()
  764. console.log(res)
  765. expect(!!res.match('1<5</dd>')).toBeTruthy()
  766. })
  767. test('parse html attr contains > ', () => {
  768. let res = $(`
  769. <dd class="1<5">1<5</dd> <view>我是打酱油</view>
  770. `, { parseOptions: { language: 'html' } })
  771. .replace(`<dd $$$1>$$$2</dd>`,
  772. `<dd test="zpzpzpzp" $$$1>$$$2</dd>`)
  773. .generate()
  774. console.log(res)
  775. expect(!!res.match('1<5</dd>')).toBeTruthy()
  776. })
  777. test('html attr generate', () => {
  778. const code = `
  779. <div class="a" @ok="
  780. getContractBookkeepingTaskList();
  781. stopBookTaskVisible = bookTaskVisible = taskVisible = false;
  782. $emit('refresh-product-list');
  783. ">1</div>
  784. <div class="a">2</div>
  785. `;
  786. const ast = $(code, { parseOptions: { language: 'html'}}).generate()
  787. expect(!!ast.match(`false;`)).toBeTruthy()
  788. })
  789. test('html opentag parse', () => {
  790. const code = `<a>{{i<b}}</a>`;
  791. const ast = $(code, { parseOptions: { language: 'html'}})
  792. .generate()
  793. expect(!ast.match(`<>`)).toBeTruthy()
  794. })
  795. test('html opentag parse', () => {
  796. const code = `<template>
  797. <div class="a">{{index<rule.length-1?'+':'-'}}</div>
  798. <div class="a">2</div>
  799. </template>`;
  800. const ast = $(code, { parseOptions: { language: 'html'}})
  801. .generate()
  802. expect(!ast.match(`<>`)).toBeTruthy()
  803. })