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.
326 lines
11 KiB
326 lines
11 KiB
8 months ago
|
"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);
|
||
|
}
|
||
|
}
|
||
|
}
|