import fs from 'fs' import path from 'path' import * as Vue from '../../../packages/weex-vue-framework' import { compile } from '../../../packages/weex-template-compiler' import WeexRuntime from 'weex-js-runtime' import styler from 'weex-styler' const styleRE = /<\s*style\s*\w*>([^(<\/)]*)<\/\s*style\s*>/g const scriptRE = /<\s*script.*>([^]*)<\/\s*script\s*>/ const templateRE = /<\s*template\s*([^>]*)>([^]*)<\/\s*template\s*>/ export function readFile (filename) { return fs.readFileSync(path.resolve(__dirname, '../cases/', filename), 'utf8') } export function readObject (filename) { return (new Function(`return ${readFile(filename)}`))() } console.debug = () => {} // http://stackoverflow.com/a/35478115 const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g export function strToRegExp (str) { return new RegExp(str.replace(matchOperatorsRe, '\\$&')) } function parseStatic (fns) { return '[' + fns.map(fn => `function () { ${fn} }`).join(',') + ']' } export function compileAndStringify (template) { const { render, staticRenderFns } = compile(template) return { render: `function () { ${render} }`, staticRenderFns: parseStatic(staticRenderFns) } } /** * Compile *.vue file into js code * @param {string} source raw text of *.vue file * @param {string} componentName whether compile to a component */ export function compileVue (source, componentName) { return new Promise((resolve, reject) => { if (!templateRE.test(source)) { return reject('No Template!') } const scriptMatch = scriptRE.exec(source) const script = scriptMatch ? scriptMatch[1] : '' const templateMatch = templateRE.exec(source) const compileOptions = {} if (/\s*recyclable\=?/i.test(templateMatch[1])) { compileOptions.recyclable = true } const res = compile(templateMatch[2], compileOptions) const name = 'test_case_' + (Math.random() * 99999999).toFixed(0) const generateCode = styles => (` try { weex.document.registerStyleSheets("${name}", [${JSON.stringify(styles)}]) } catch(e) {}; var ${name} = Object.assign({ _scopeId: "${name}", style: ${JSON.stringify(styles)}, render: function () { ${res.render} }, ${res['@render'] ? ('"@render": function () {' + res['@render'] + '},') : ''} staticRenderFns: ${parseStatic(res.staticRenderFns)}, }, (function(){ var module = { exports: {} }; ${script}; return module.exports; })()); ` + (componentName ? `Vue.component('${componentName}', ${name});\n` : `${name}.el = 'body';new Vue(${name});`) ) let cssText = '' let styleMatch = null while ((styleMatch = styleRE.exec(source))) { cssText += `\n${styleMatch[1]}\n` } styler.parse(cssText, (error, result) => { if (error) { return reject(error) } resolve(generateCode(result.jsonStyle)) }) resolve(generateCode({})) }) } export function compileWithDeps (entryPath, deps) { return new Promise((resolve, reject) => { if (Array.isArray(deps)) { Promise.all(deps.map(dep => { return compileVue(readFile(dep.path), dep.name).catch(reject) })).then(depCodes => { compileVue(readFile(entryPath)).then(entryCode => { resolve(depCodes.join('\n') + entryCode) }).catch(reject) }).catch(reject) } }) } function isObject (object) { return object !== null && typeof object === 'object' } function isEmptyObject (object) { return isObject(object) && Object.keys(object).length < 1 } function omitUseless (object) { if (isObject(object)) { delete object.ref for (const key in object) { omitUseless(object[key]) if (key === '@styleScope' || key === '@templateId' || key === 'bindingExpression') { delete object[key] } if (key.charAt(0) !== '@' && (isEmptyObject(object[key]) || object[key] === undefined)) { delete object[key] } } } return object } export function getRoot (instance) { return omitUseless(instance.$getRoot()) } // Get all binding events in the instance export function getEvents (instance) { const events = [] const recordEvent = node => { if (!node) { return } if (Array.isArray(node.event)) { node.event.forEach(type => { events.push({ ref: node.ref, type }) }) } if (Array.isArray(node.children)) { node.children.forEach(recordEvent) } } recordEvent(instance.$getRoot()) return events } export function fireEvent (instance, ref, type, event = {}) { const el = instance.document.getRef(ref) if (el) { instance.document.fireEvent(el, type, event) } } export function createInstance (id, code, ...args) { WeexRuntime.config.frameworks = { Vue } const context = WeexRuntime.init(WeexRuntime.config) context.registerModules({ timer: ['setTimeout', 'setInterval'] }) const instance = context.createInstance(id, `// { "framework": "Vue" }\n${code}`, ...args) || {} instance.document = context.getDocument(id) instance.$getRoot = () => context.getRoot(id) instance.$refresh = (data) => context.refreshInstance(id, data) instance.$destroy = () => { delete instance.document context.destroyInstance(id) } instance.$triggerHook = (id, hook, args) => { instance.document.taskCenter.triggerHook(id, 'lifecycle', hook, { args }) } return instance } export function compileAndExecute (template, additional = '') { return new Promise(resolve => { const id = String(Date.now() * Math.random()) const { render, staticRenderFns } = compile(template) const instance = createInstance(id, ` new Vue({ el: '#whatever', render: function () { ${render} }, staticRenderFns: ${parseStatic(staticRenderFns)}, ${additional} }) `) setTimeout(() => resolve(instance), 10) }) } export function syncPromise (arr) { let p = Promise.resolve() arr.forEach(item => { p = p.then(item) }) return p } export function checkRefresh (instance, data, checker) { return () => new Promise(res => { instance.$refresh(data) setTimeout(() => { checker(getRoot(instance)) res() }) }) } export function addTaskHook (hook) { global.callNative = function callNative (id, tasks) { if (Array.isArray(tasks) && typeof hook === 'function') { tasks.forEach(task => { hook(id, { module: task.module, method: task.method, args: Array.from(task.args) }) }) } } } export function resetTaskHook () { delete global.callNative }