You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
11 KiB
325 lines
11 KiB
"use strict"; |
|
var __importDefault = (this && this.__importDefault) || function (mod) { |
|
return (mod && mod.__esModule) ? mod : { "default": mod }; |
|
}; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.genExpr = exports.genBabelExpr = exports.generate = void 0; |
|
const shared_1 = require("@vue/shared"); |
|
const compiler_core_1 = require("@vue/compiler-core"); |
|
const generator_1 = __importDefault(require("@babel/generator")); |
|
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared"); |
|
function generate(ast, options) { |
|
const context = createCodegenContext(ast, options); |
|
const { mode, push, indent, deindent, newline, prefixIdentifiers } = context; |
|
const helpers = Array.from(ast.helpers); |
|
const hasHelpers = helpers.length > 0; |
|
const useWithBlock = !prefixIdentifiers && mode !== 'module'; |
|
const isSetupInlined = !!options.inline; |
|
// preambles |
|
// in setup() inline mode, the preamble is generated in a sub context |
|
// and returned separately. |
|
const preambleContext = isSetupInlined |
|
? createCodegenContext(ast, options) |
|
: context; |
|
if (mode === 'module') { |
|
genModulePreamble(ast, preambleContext, isSetupInlined); |
|
} |
|
else { |
|
genFunctionPreamble(ast, preambleContext); |
|
} |
|
// enter render function |
|
const functionName = `render`; |
|
const args = ['_ctx', '_cache']; |
|
if (options.bindingMetadata && !options.inline) { |
|
// binding optimization args |
|
args.push('$props', '$setup', '$data', '$options'); |
|
} |
|
const signature = options.isTS |
|
? args.map((arg) => `${arg}: any`).join(',') |
|
: args.join(', '); |
|
if (isSetupInlined) { |
|
push(`(${signature}) => {`); |
|
} |
|
else { |
|
push(`function ${functionName}(${signature}) {`); |
|
} |
|
indent(); |
|
if (useWithBlock) { |
|
push(`with (_ctx) {`); |
|
indent(); |
|
if (hasHelpers) { |
|
push(`const { ${helpers |
|
.map((s) => `${compiler_core_1.helperNameMap[s]}: _${compiler_core_1.helperNameMap[s]}`) |
|
.join(', ')} } = _Vue`); |
|
push(`\n`); |
|
newline(); |
|
} |
|
} |
|
push(`return `); |
|
push(genBabelExpr(ast.renderData, options.generatorOpts)); |
|
if (useWithBlock) { |
|
deindent(); |
|
push(`}`); |
|
} |
|
deindent(); |
|
push(`}`); |
|
return { |
|
code: context.code, |
|
preamble: isSetupInlined ? preambleContext.code : ``, |
|
// SourceMapGenerator does have toJSON() method but it's not in the types |
|
map: context.map ? context.map.toJSON() : undefined, |
|
}; |
|
} |
|
exports.generate = generate; |
|
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', filename = `template.vue.html`, scopeId = null, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, isTS = false, sourceMap = false, }) { |
|
const context = { |
|
mode, |
|
prefixIdentifiers, |
|
filename, |
|
scopeId, |
|
runtimeGlobalName, |
|
runtimeModuleName, |
|
bindingComponents: ast.bindingComponents, |
|
isTS, |
|
source: ast.loc.source, |
|
code: ``, |
|
column: 1, |
|
line: 1, |
|
offset: 0, |
|
indentLevel: 0, |
|
push(code, node) { |
|
context.code += code; |
|
if (context.map) { |
|
if (node) { |
|
let name; |
|
if (node.type === 4 /* NodeTypes.SIMPLE_EXPRESSION */ && !node.isStatic) { |
|
const content = node.content.replace(/^_ctx\./, ''); |
|
if (content !== node.content && (0, compiler_core_1.isSimpleIdentifier)(content)) { |
|
name = content; |
|
} |
|
} |
|
addMapping(node.loc.start, name); |
|
} |
|
(0, compiler_core_1.advancePositionWithMutation)(context, code); |
|
if (node && node.loc !== compiler_core_1.locStub) { |
|
addMapping(node.loc.end); |
|
} |
|
} |
|
}, |
|
indent() { |
|
newline(++context.indentLevel); |
|
}, |
|
deindent(withoutNewLine = false) { |
|
if (withoutNewLine) { |
|
--context.indentLevel; |
|
} |
|
else { |
|
newline(--context.indentLevel); |
|
} |
|
}, |
|
newline() { |
|
newline(context.indentLevel); |
|
}, |
|
}; |
|
function newline(n) { |
|
context.push('\n' + ` `.repeat(n)); |
|
} |
|
function addMapping(loc, name) { |
|
context.map.addMapping({ |
|
name, |
|
source: context.filename || '', |
|
original: { |
|
line: loc.line, |
|
column: loc.column - 1, // source-map column is 0 based |
|
}, |
|
generated: { |
|
line: context.line, |
|
column: context.column - 1, |
|
}, |
|
}); |
|
} |
|
// 暂时无需提供 sourcemap 支持 |
|
// if (sourceMap) { |
|
// // lazy require source-map implementation |
|
// context.map = new SourceMapGenerator() |
|
// context.map!.setSourceContent(filename, context.source) |
|
// } |
|
return context; |
|
} |
|
function genComponentImports(bindingComponents, { push, newline }) { |
|
const tags = Object.keys(bindingComponents); |
|
const importDeclarations = []; |
|
// 仅记录easycom和setup组件 |
|
const components = []; |
|
tags.forEach((tag) => { |
|
const { name, type } = bindingComponents[tag]; |
|
if (type === "unknown" /* BindingComponentTypes.UNKNOWN */) { |
|
const source = (0, uni_cli_shared_1.matchEasycom)(tag); |
|
if (source) { |
|
// 调整为easycom命名 |
|
const easycomName = name.replace('component', 'easycom'); |
|
bindingComponents[tag].name = easycomName; |
|
components.push(easycomName); |
|
(0, uni_cli_shared_1.addImportDeclaration)(importDeclarations, easycomName, source); |
|
} |
|
} |
|
else if (type === "setup" /* BindingComponentTypes.SETUP */) { |
|
components.push(name); |
|
} |
|
}); |
|
if (tags.length) { |
|
push(`const __BINDING_COMPONENTS__ = '` + |
|
JSON.stringify(bindingComponents) + |
|
`'`); |
|
const resolveComponents = []; |
|
const names = []; |
|
Object.keys(bindingComponents).forEach((id) => { |
|
const { type, name } = bindingComponents[id]; |
|
if (type === "unknown" /* BindingComponentTypes.UNKNOWN */) { |
|
resolveComponents.push(`const ${name} = _${compiler_core_1.helperNameMap[compiler_core_1.RESOLVE_COMPONENT]}("${id}");`); |
|
names.push(name); |
|
} |
|
}); |
|
if (resolveComponents.length) { |
|
newline(); |
|
push(`if (!Array) {`); |
|
resolveComponents.forEach((code) => { |
|
push(code); |
|
}); |
|
push(`(${names.join('+')})()`); |
|
push(`}`); |
|
} |
|
newline(); |
|
importDeclarations.forEach((str) => push(str)); |
|
if (importDeclarations.length) { |
|
newline(); |
|
} |
|
if (components.length) { |
|
push(`if (!Math) {`); |
|
push(` (${components.map((name) => name).join('+')})() `); |
|
push(`}`); |
|
newline(); |
|
} |
|
} |
|
} |
|
function genFunctionPreamble(ast, context) { |
|
const { prefixIdentifiers, push, newline, runtimeGlobalName, bindingComponents, } = context; |
|
const VueBinding = runtimeGlobalName; |
|
const aliasHelper = (s) => `${compiler_core_1.helperNameMap[s]}: _${compiler_core_1.helperNameMap[s]}`; |
|
const helpers = Array.from(ast.helpers); |
|
if (helpers.length > 0) { |
|
if (prefixIdentifiers) { |
|
push(`const { ${helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`); |
|
} |
|
else { |
|
push(`const _Vue = ${VueBinding}\n`); |
|
} |
|
} |
|
genComponentImports(bindingComponents, context); |
|
newline(); |
|
push(`return `); |
|
} |
|
function genModulePreamble(ast, context, inline) { |
|
const { push, newline, runtimeModuleName, bindingComponents } = context; |
|
const helpers = Array.from(ast.helpers); |
|
if (helpers.length) { |
|
push(`import { ${helpers |
|
.map((s) => `${compiler_core_1.helperNameMap[s]} as _${compiler_core_1.helperNameMap[s]}`) |
|
.join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`); |
|
} |
|
if (ast.imports.length) { |
|
genImports(ast.imports, context); |
|
} |
|
genComponentImports(bindingComponents, context); |
|
newline(); |
|
if (!inline) { |
|
push(`export `); |
|
} |
|
} |
|
function genImports(importsOptions, { push, newline }) { |
|
if (!importsOptions.length) { |
|
return; |
|
} |
|
importsOptions.forEach((imports) => { |
|
push(`import `); |
|
push(genExpr(imports.exp)); |
|
push(` from '${imports.path}'`); |
|
newline(); |
|
}); |
|
} |
|
function createGenNodeContext() { |
|
const context = { |
|
code: '', |
|
helper(key) { |
|
return `_${compiler_core_1.helperNameMap[key]}`; |
|
}, |
|
push(code) { |
|
context.code += code; |
|
}, |
|
}; |
|
return context; |
|
} |
|
function genBabelExpr(expr, opts = {}) { |
|
if (!(0, shared_1.hasOwn)(opts, 'jsescOption')) { |
|
opts.jsescOption = {}; |
|
} |
|
opts.jsescOption.quotes = 'single'; |
|
return (0, generator_1.default)(expr, opts).code; |
|
} |
|
exports.genBabelExpr = genBabelExpr; |
|
function genExpr(node, context) { |
|
return genNode(node, context).code; |
|
} |
|
exports.genExpr = genExpr; |
|
function genNode(node, context) { |
|
if (!context) { |
|
context = createGenNodeContext(); |
|
} |
|
if ((0, shared_1.isString)(node)) { |
|
context.push(node); |
|
return context; |
|
} |
|
if ((0, shared_1.isSymbol)(node)) { |
|
context.push(context.helper(node)); |
|
return context; |
|
} |
|
switch (node.type) { |
|
case 2 /* NodeTypes.TEXT */: |
|
genText(node, context); |
|
break; |
|
case 4 /* NodeTypes.SIMPLE_EXPRESSION */: |
|
genExpression(node, context); |
|
break; |
|
case 5 /* NodeTypes.INTERPOLATION */: |
|
genInterpolation(node, context); |
|
break; |
|
case 8 /* NodeTypes.COMPOUND_EXPRESSION */: |
|
genCompoundExpression(node, context); |
|
break; |
|
} |
|
return context; |
|
} |
|
function genText(node, context) { |
|
context.push(JSON.stringify(node.content), node); |
|
} |
|
function genExpression(node, context) { |
|
const { content, isStatic } = node; |
|
context.push(isStatic ? JSON.stringify(content) : content, node); |
|
} |
|
function genInterpolation(node, context) { |
|
const { push, helper } = context; |
|
push(`${helper(compiler_core_1.TO_DISPLAY_STRING)}(`); |
|
genExpr(node.content, context); |
|
push(`)`); |
|
} |
|
function genCompoundExpression(node, context) { |
|
for (let i = 0; i < node.children.length; i++) { |
|
const child = node.children[i]; |
|
if ((0, shared_1.isString)(child)) { |
|
context.push(child); |
|
} |
|
else { |
|
genExpr(child, context); |
|
} |
|
} |
|
}
|
|
|