index.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import fs from 'fs'
  2. import path from 'path'
  3. import * as Vue from '../../../packages/weex-vue-framework'
  4. import { compile } from '../../../packages/weex-template-compiler'
  5. import WeexRuntime from 'weex-js-runtime'
  6. import styler from 'weex-styler'
  7. const styleRE = /<\s*style\s*\w*>([^(<\/)]*)<\/\s*style\s*>/g
  8. const scriptRE = /<\s*script.*>([^]*)<\/\s*script\s*>/
  9. const templateRE = /<\s*template\s*([^>]*)>([^]*)<\/\s*template\s*>/
  10. export function readFile (filename) {
  11. return fs.readFileSync(path.resolve(__dirname, '../cases/', filename), 'utf8')
  12. }
  13. export function readObject (filename) {
  14. return (new Function(`return ${readFile(filename)}`))()
  15. }
  16. console.debug = () => {}
  17. // http://stackoverflow.com/a/35478115
  18. const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g
  19. export function strToRegExp (str) {
  20. return new RegExp(str.replace(matchOperatorsRe, '\\$&'))
  21. }
  22. function parseStatic (fns) {
  23. return '[' + fns.map(fn => `function () { ${fn} }`).join(',') + ']'
  24. }
  25. export function compileAndStringify (template) {
  26. const { render, staticRenderFns } = compile(template)
  27. return {
  28. render: `function () { ${render} }`,
  29. staticRenderFns: parseStatic(staticRenderFns)
  30. }
  31. }
  32. /**
  33. * Compile *.vue file into js code
  34. * @param {string} source raw text of *.vue file
  35. * @param {string} componentName whether compile to a component
  36. */
  37. export function compileVue (source, componentName) {
  38. return new Promise((resolve, reject) => {
  39. if (!templateRE.test(source)) {
  40. return reject('No Template!')
  41. }
  42. const scriptMatch = scriptRE.exec(source)
  43. const script = scriptMatch ? scriptMatch[1] : ''
  44. const templateMatch = templateRE.exec(source)
  45. const compileOptions = {}
  46. if (/\s*recyclable\=?/i.test(templateMatch[1])) {
  47. compileOptions.recyclable = true
  48. }
  49. const res = compile(templateMatch[2], compileOptions)
  50. const name = 'test_case_' + (Math.random() * 99999999).toFixed(0)
  51. const generateCode = styles => (`
  52. var ${name} = Object.assign({
  53. style: ${JSON.stringify(styles)},
  54. render: function () { ${res.render} },
  55. ${res['@render'] ? ('"@render": function () {' + res['@render'] + '},') : ''}
  56. staticRenderFns: ${parseStatic(res.staticRenderFns)},
  57. }, (function(){
  58. var module = { exports: {} };
  59. ${script};
  60. return module.exports;
  61. })());
  62. ` + (componentName
  63. ? `Vue.component('${componentName}', ${name});\n`
  64. : `${name}.el = 'body';new Vue(${name});`)
  65. )
  66. let cssText = ''
  67. let styleMatch = null
  68. while ((styleMatch = styleRE.exec(source))) {
  69. cssText += `\n${styleMatch[1]}\n`
  70. }
  71. styler.parse(cssText, (error, result) => {
  72. if (error) {
  73. return reject(error)
  74. }
  75. resolve(generateCode(result.jsonStyle))
  76. })
  77. resolve(generateCode({}))
  78. })
  79. }
  80. export function compileWithDeps (entryPath, deps) {
  81. return new Promise((resolve, reject) => {
  82. if (Array.isArray(deps)) {
  83. Promise.all(deps.map(dep => {
  84. return compileVue(readFile(dep.path), dep.name).catch(reject)
  85. })).then(depCodes => {
  86. compileVue(readFile(entryPath)).then(entryCode => {
  87. resolve(depCodes.join('\n') + entryCode)
  88. }).catch(reject)
  89. }).catch(reject)
  90. }
  91. })
  92. }
  93. function isObject (object) {
  94. return object !== null && typeof object === 'object'
  95. }
  96. function isEmptyObject (object) {
  97. return isObject(object) && Object.keys(object).length < 1
  98. }
  99. function omitUseless (object) {
  100. if (isObject(object)) {
  101. delete object.ref
  102. for (const key in object) {
  103. if (key.charAt(0) !== '@' && (isEmptyObject(object[key]) || object[key] === undefined)) {
  104. delete object[key]
  105. }
  106. omitUseless(object[key])
  107. }
  108. }
  109. return object
  110. }
  111. export function getRoot (instance) {
  112. return omitUseless(instance.$getRoot())
  113. }
  114. // Get all binding events in the instance
  115. export function getEvents (instance) {
  116. const events = []
  117. const recordEvent = node => {
  118. if (!node) { return }
  119. if (Array.isArray(node.event)) {
  120. node.event.forEach(type => {
  121. events.push({ ref: node.ref, type })
  122. })
  123. }
  124. if (Array.isArray(node.children)) {
  125. node.children.forEach(recordEvent)
  126. }
  127. }
  128. recordEvent(instance.$getRoot())
  129. return events
  130. }
  131. export function fireEvent (instance, ref, type, event = {}) {
  132. const el = instance.document.getRef(ref)
  133. if (el) {
  134. instance.document.fireEvent(el, type, event = {})
  135. }
  136. }
  137. export function createInstance (id, code, ...args) {
  138. WeexRuntime.config.frameworks = { Vue }
  139. const context = WeexRuntime.init(WeexRuntime.config)
  140. context.registerModules({
  141. timer: ['setTimeout', 'setInterval']
  142. })
  143. const instance = context.createInstance(id, `// { "framework": "Vue" }\n${code}`, ...args) || {}
  144. instance.document = context.getDocument(id)
  145. instance.$getRoot = () => context.getRoot(id)
  146. instance.$refresh = (data) => context.refreshInstance(id, data)
  147. instance.$destroy = () => {
  148. delete instance.document
  149. context.destroyInstance(id)
  150. }
  151. instance.$triggerHook = (id, hook, args) => {
  152. instance.document.taskCenter.triggerHook(id, 'lifecycle', hook, { args })
  153. }
  154. return instance
  155. }
  156. export function compileAndExecute (template, additional = '') {
  157. return new Promise(resolve => {
  158. const id = String(Date.now() * Math.random())
  159. const { render, staticRenderFns } = compile(template)
  160. const instance = createInstance(id, `
  161. new Vue({
  162. el: '#whatever',
  163. render: function () { ${render} },
  164. staticRenderFns: ${parseStatic(staticRenderFns)},
  165. ${additional}
  166. })
  167. `)
  168. setTimeout(() => resolve(instance), 10)
  169. })
  170. }
  171. export function syncPromise (arr) {
  172. let p = Promise.resolve()
  173. arr.forEach(item => {
  174. p = p.then(item)
  175. })
  176. return p
  177. }
  178. export function checkRefresh (instance, data, checker) {
  179. return () => new Promise(res => {
  180. instance.$refresh(data)
  181. setTimeout(() => {
  182. checker(getRoot(instance))
  183. res()
  184. })
  185. })
  186. }
  187. export function addTaskHook (hook) {
  188. global.callNative = function callNative (id, tasks) {
  189. if (Array.isArray(tasks) && typeof hook === 'function') {
  190. tasks.forEach(task => {
  191. hook(id, {
  192. module: task.module,
  193. method: task.method,
  194. args: Array.from(task.args)
  195. })
  196. })
  197. }
  198. }
  199. }
  200. export function resetTaskHook () {
  201. delete global.callNative
  202. }