提交 4740191c 编写于 作者: fxy060608's avatar fxy060608

wip(mp): init

上级 beb77ebc
......@@ -44,7 +44,7 @@ module.exports = {
// Packages targeting Node
{
files: [
'packages/{uni-cli-shared,uni-cli-nvue,uni-app-vite,uni-h5-vite,vite-plugin-uni}/**',
'packages/{uni-cli-shared,uni-cli-nvue,uni-app-vite,uni-h5-vite,uni-mp-vite,uni-mp-compiler,vite-plugin-uni}/**',
'packages/*/vite.config.ts',
],
rules: {
......
......@@ -23,7 +23,7 @@
"chokidar": "^3.5.2",
"compare-versions": "^3.6.0",
"debug": "^4.3.1",
"estree-walker": "^2.0.2",
"estree-walker": "^3.0.0",
"fast-glob": "^3.2.7",
"fs-extra": "^10.0.0",
"hash-sum": "^2.0.0",
......
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
import { compile } from '../src/index'
function assert(template: string, templateCode: string, renderCode: string) {
const res = compile(template, {
filename: 'foo.vue',
prefixIdentifiers: true,
inline: true,
emitFile({ source }) {
// console.log(source)
expect(source).toBe(templateCode)
return ''
},
})
// expect(res.template).toBe(templateCode)
// expect(res.code).toBe(renderCode)
// console.log(require('util').inspect(res.code, { colors: true, depth: null }))
// console.log(require('util').inspect(res, { colors: true, depth: null }))
expect(res.code).toBe(renderCode)
}
describe('compiler', () => {
test(`v-for directive`, () => {
assert(
`<view><view v-for="item in items" :key="item.uid" :data-title="data.title" :data-id="item.id">{{item.title}}</view></view>`,
`<view><view wx:for="{{b}}" wx:for-item="item" wx:key="b" data-title="{{a}}" data-id="{{item.c}}">{{item.a}}</view></view>`,
`(_ctx, _cache) => {
return {
a: _ctx.data.title,
b: vFor(_ctx.items, item => {
return {
a: item.title,
b: item.uid,
c: item.id
};
})
}
}`
)
})
test(`v-for directive with key`, () => {
assert(
`<view><view v-for="(item, i) in items" :data-id="item.id">{{item.title}}</view></view>`,
`<view><view wx:for="{{a}}" wx:for-item="item" wx:for-index="i" data-id="{{item.b}}">{{item.a}}</view></view>`,
`(_ctx, _cache) => {
return {
a: vFor(_ctx.items, (item, i) => {
return {
a: item.title,
b: item.id
};
})
}
}`
)
})
test(`generate v-for with v-if`, () => {
assert(
`<view v-for="item in items"><view v-if="item.show">{{item.title}}</view></view>`,
`<view wx:for="{{a}}" wx:for-item="item"><view wx:if="{{item.b}}">{{item.a}}</view></view>`,
`(_ctx, _cache) => {
return {
a: vFor(_ctx.items, item => {
return {
b: item.show,
...(item.show ? {
a: item.title
} : {})
};
})
}
}`
)
})
test(`generate v-if directive`, () => {
assert(
`<view v-if="show">hello</view>`,
`<view wx:if="{{a}}">hello</view>`,
`(_ctx, _cache) => {
return {
a: _ctx.show,
...(_ctx.show ? {} : {})
}
}`
)
})
test(`generate v-else directive`, () => {
assert(
`<view><view v-if="show">hello</view><view v-else>world</view></view>`,
`<view><view wx:if="{{a}}">hello</view><view wx:else>world</view></view>`,
`(_ctx, _cache) => {
return {
a: _ctx.show,
...(_ctx.show ? {} : {})
}
}`
)
})
test(`generate v-else-if directive`, () => {
assert(
`<view><view v-if="show">hello</view><view v-else-if="hide">world</view></view>`,
`<view><view wx:if="{{a}}">hello</view><view wx:elif="{{b}}">world</view></view>`,
`(_ctx, _cache) => {
return {
a: _ctx.show,
...(_ctx.show ? {} : _ctx.hide ? {} : {}),
b: _ctx.hide
}
}`
)
})
test(`generate v-else-if with v-else directive`, () => {
assert(
`<view><view v-if="show">hello</view><view v-else-if="hide">world</view><view v-else>bye</view></view>`,
`<view><view wx:if="{{a}}">hello</view><view wx:elif="{{b}}">world</view><view wx:else>bye</view></view>`,
`(_ctx, _cache) => {
return {
a: _ctx.show,
...(_ctx.show ? {} : _ctx.hide ? {} : {}),
b: _ctx.hide
}
}`
)
})
test(`generate multi v-else-if with v-else directive`, () => {
assert(
`<view><view v-if="show">hello</view><view v-else-if="hide">world</view><view v-else-if="3">elseif</view><view v-else>bye</view></view>`,
`<view><view wx:if="{{a}}">hello</view><view wx:elif="{{b}}">world</view><view wx:elif="{{3}}">elseif</view><view wx:else>bye</view></view>`,
`(_ctx, _cache) => {
return {
a: _ctx.show,
...(_ctx.show ? {} : _ctx.hide ? {} : 3 ? {} : {}),
b: _ctx.hide
}
}`
)
})
})
import IdentifierGenerator from '../src/identifier'
const ids = new IdentifierGenerator()
describe('identifier', () => {
test('id', () => {
expect(ids.next()).toBe('a')
expect(ids.next()).toBe('b')
for (let i = 0; i < 50; i++) {
ids.next()
}
expect(ids.next()).toBe('aa')
expect(ids.next()).toBe('ab')
for (let i = 0; i < 52 * 52 - 2; i++) {
ids.next()
}
expect(ids.next()).toBe('aaa')
expect(ids.next()).toBe('aab')
})
})
import { compile } from '../src/index'
function assert(template: string, templateCode: string, renderCode: string) {
const res = compile(template, {
filename: 'foo.vue',
prefixIdentifiers: true,
inline: true,
emitFile({ source }) {
console.log(source)
expect(source).toBe(templateCode)
return ''
},
})
// expect(res.template).toBe(templateCode)
// expect(res.code).toBe(renderCode)
// console.log(require('util').inspect(res.code, { colors: true, depth: null }))
// console.log(require('util').inspect(res, { colors: true, depth: null }))
console.log(res.code)
expect(res.code).toBe(renderCode)
}
describe('compiler', () => {
test(`generate v-for with v-if`, () => {
assert(
`<view v-for="item in items"><view v-if="item.show">{{item.title}}</view></view>`,
`<view wx:for="{{a}}" wx:for-item="item"><view wx:if="{{item.b}}">{{item.a}}</view></view>`,
`(_ctx, _cache) => {
return {
a: vFor(_ctx.items, item => {
return {
a: item.title,
b: item.show,
...(item.show ? {} : {})
};
})
}
}`
)
})
})
export declare function createVariableDeclaration(name: string, init: string): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createVariableDeclaration = void 0;
function createVariableDeclaration(name, init) {
return `const ${name} = ${init}`;
}
exports.createVariableDeclaration = createVariableDeclaration;
import { RootNode, CodegenContext, CodegenResult, CompoundExpressionNode, SimpleExpressionNode, InterpolationNode, TextNode } from '@vue/compiler-core';
import { CodegenOptions, CodegenVForScope } from './options';
interface MPCodegenContext extends Omit<CodegenContext, 'sourceMap' | 'optimizeImports' | 'ssrRuntimeModuleName' | 'ssr' | 'inSSR'> {
}
export declare function generate(ast: RootNode, options?: CodegenOptions & {
onContextCreated?: (context: MPCodegenContext) => void;
}): CodegenResult;
export declare function genVForScope(vForScope: CodegenVForScope): string;
declare type CodegenNode = SimpleExpressionNode | CompoundExpressionNode | InterpolationNode | TextNode | string | symbol;
interface GenNodeContext {
code: string;
helper(key: symbol): string;
push(code: string, node?: CodegenNode): void;
}
export declare function genNode(node: CodegenNode | symbol | string, context?: GenNodeContext): GenNodeContext;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genNode = exports.genVForScope = exports.generate = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
function generate(ast, options = {}) {
const context = createCodegenContext(ast, options);
const { push, indent, deindent, mode } = context;
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();
push(genScope(options.scope));
deindent();
push(`}`);
return {
code: context.code,
preamble: '',
ast,
};
}
exports.generate = generate;
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', filename = `template.vue.html`, scopeId = null, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, isTS = false, }) {
const context = {
mode,
prefixIdentifiers,
filename,
scopeId,
runtimeGlobalName,
runtimeModuleName,
isTS,
source: ast.loc.source,
code: ``,
column: 1,
line: 1,
offset: 0,
indentLevel: 0,
pure: false,
map: undefined,
helper(key) {
return `_${compiler_core_1.helperNameMap[key]}`;
},
push(code, node) {
context.code += code;
},
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));
}
return context;
}
function genModulePreamble(ast, context, inline) {
const { push, newline, runtimeModuleName } = context;
// generate import statements for helpers
if (ast.helpers.length) {
push(`import { ${ast.helpers
.map((s) => `${compiler_core_1.helperNameMap[s]} as _${compiler_core_1.helperNameMap[s]}`)
.join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`);
}
newline();
if (!inline) {
push(`export `);
}
}
function genFunctionPreamble(ast, context) {
const { prefixIdentifiers, push, newline, runtimeGlobalName } = context;
const VueBinding = runtimeGlobalName;
const aliasHelper = (s) => `${compiler_core_1.helperNameMap[s]}: _${compiler_core_1.helperNameMap[s]}`;
// Generate const declaration for helpers
// In prefix mode, we place the const declaration at top so it's done
// only once; But if we not prefixing, we place the declaration inside the
// with block so it doesn't incur the `in` check cost for every helper access.
if (ast.helpers.length > 0) {
if (prefixIdentifiers) {
push(`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`);
}
else {
// "with" mode.
// save Vue in a separate variable to avoid collision
push(`const _Vue = ${VueBinding}\n`);
// in "with" mode, helpers are declared inside the with block to avoid
// has check cost, but hoists are lifted out of the function - we need
// to provide the helper here.
}
}
newline();
push(`return `);
}
function genScope(scope) {
return scope.body.join('\n');
}
function genVForScope(vForScope) {
return `renderListScope(${vForScope.source},(${vForScope.value},${vForScope.key},${vForScope.index})=>{
${genScope(vForScope)}
})`;
}
exports.genVForScope = genVForScope;
function createGenNodeContext() {
const context = {
code: '',
helper(key) {
return `_${compiler_core_1.helperNameMap[key]}`;
},
push(code) {
context.code += code;
},
};
return context;
}
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 /* TEXT */:
genText(node, context);
break;
case 4 /* SIMPLE_EXPRESSION */:
genExpression(node, context);
break;
case 5 /* INTERPOLATION */:
genInterpolation(node, context);
break;
case 8 /* COMPOUND_EXPRESSION */:
genCompoundExpression(node, context);
break;
}
return context;
}
exports.genNode = genNode;
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)}(`);
genNode(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 {
genNode(child, context);
}
}
}
import { CompilerOptions } from './options';
import { DirectiveTransform, NodeTransform } from './transform';
export declare type TransformPreset = [
NodeTransform[],
Record<string, DirectiveTransform>
];
export declare function getBaseTransformPreset(prefixIdentifiers?: boolean): TransformPreset;
export declare function baseCompile(template: string, options?: CompilerOptions): import("@vue/compiler-core").CodegenResult;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.baseCompile = exports.getBaseTransformPreset = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const codegen_1 = require("./codegen");
const transform_1 = require("./transform");
const transformExpression_1 = require("./transforms/transformExpression");
const transformIdentifier_1 = require("./transforms/transformIdentifier");
const vFor_1 = require("./transforms/vFor");
function getBaseTransformPreset(prefixIdentifiers) {
const nodeTransforms = [vFor_1.transformFor];
if (prefixIdentifiers) {
nodeTransforms.push(transformExpression_1.transformExpression);
}
return [nodeTransforms, {}];
}
exports.getBaseTransformPreset = getBaseTransformPreset;
function baseCompile(template, options = {}) {
const prefixIdentifiers = options.prefixIdentifiers === true || options.mode === 'module';
const ast = (0, shared_1.isString)(template) ? (0, compiler_core_1.baseParse)(template, options) : template;
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(prefixIdentifiers);
const context = (0, transform_1.transform)(ast, (0, shared_1.extend)({}, options, {
prefixIdentifiers,
nodeTransforms: [
...nodeTransforms,
...(options.nodeTransforms || []),
transformIdentifier_1.transformIdentifier,
],
directiveTransforms: (0, shared_1.extend)({}, directiveTransforms, options.directiveTransforms || {}),
}));
return (0, codegen_1.generate)(ast, (0, shared_1.extend)({ scope: context.scope }, options));
}
exports.baseCompile = baseCompile;
import { ParserOptions } from '@vue/compiler-core';
export declare const decodeHtml: ParserOptions['decodeEntities'];
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeHtml = void 0;
const namedChars_json_1 = __importDefault(require("./namedChars.json"));
// lazy compute this to make this file tree-shakable for browser
let maxCRNameLength;
const decodeHtml = (rawText, asAttr) => {
let offset = 0;
const end = rawText.length;
let decodedText = '';
function advance(length) {
offset += length;
rawText = rawText.slice(length);
}
while (offset < end) {
const head = /&(?:#x?)?/i.exec(rawText);
if (!head || offset + head.index >= end) {
const remaining = end - offset;
decodedText += rawText.slice(0, remaining);
advance(remaining);
break;
}
// Advance to the "&".
decodedText += rawText.slice(0, head.index);
advance(head.index);
if (head[0] === '&') {
// Named character reference.
let name = '';
let value = undefined;
if (/[0-9a-z]/i.test(rawText[1])) {
if (!maxCRNameLength) {
maxCRNameLength = Object.keys(namedChars_json_1.default).reduce((max, name) => Math.max(max, name.length), 0);
}
for (let length = maxCRNameLength; !value && length > 0; --length) {
name = rawText.substr(1, length);
value = namedChars_json_1.default[name];
}
if (value) {
const semi = name.endsWith(';');
if (asAttr &&
!semi &&
/[=a-z0-9]/i.test(rawText[name.length + 1] || '')) {
decodedText += '&' + name;
advance(1 + name.length);
}
else {
decodedText += value;
advance(1 + name.length);
}
}
else {
decodedText += '&' + name;
advance(1 + name.length);
}
}
else {
decodedText += '&';
advance(1);
}
}
else {
// Numeric character reference.
const hex = head[0] === '&#x';
const pattern = hex ? /^&#x([0-9a-f]+);?/i : /^&#([0-9]+);?/;
const body = pattern.exec(rawText);
if (!body) {
decodedText += head[0];
advance(head[0].length);
}
else {
// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
let cp = Number.parseInt(body[1], hex ? 16 : 10);
if (cp === 0) {
cp = 0xfffd;
}
else if (cp > 0x10ffff) {
cp = 0xfffd;
}
else if (cp >= 0xd800 && cp <= 0xdfff) {
cp = 0xfffd;
}
else if ((cp >= 0xfdd0 && cp <= 0xfdef) || (cp & 0xfffe) === 0xfffe) {
// noop
}
else if ((cp >= 0x01 && cp <= 0x08) ||
cp === 0x0b ||
(cp >= 0x0d && cp <= 0x1f) ||
(cp >= 0x7f && cp <= 0x9f)) {
cp = CCR_REPLACEMENTS[cp] || cp;
}
decodedText += String.fromCodePoint(cp);
advance(body[0].length);
}
}
}
return decodedText;
};
exports.decodeHtml = decodeHtml;
// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
const CCR_REPLACEMENTS = {
0x80: 0x20ac,
0x82: 0x201a,
0x83: 0x0192,
0x84: 0x201e,
0x85: 0x2026,
0x86: 0x2020,
0x87: 0x2021,
0x88: 0x02c6,
0x89: 0x2030,
0x8a: 0x0160,
0x8b: 0x2039,
0x8c: 0x0152,
0x8e: 0x017d,
0x91: 0x2018,
0x92: 0x2019,
0x93: 0x201c,
0x94: 0x201d,
0x95: 0x2022,
0x96: 0x2013,
0x97: 0x2014,
0x98: 0x02dc,
0x99: 0x2122,
0x9a: 0x0161,
0x9b: 0x203a,
0x9c: 0x0153,
0x9e: 0x017e,
0x9f: 0x0178,
};
export default class IdentifierGenerator {
private _chars;
private _nextIds;
next(): string;
_increment(): void;
[Symbol.iterator](): Generator<string, void, unknown>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class IdentifierGenerator {
constructor() {
this._chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
this._nextIds = [0];
}
next() {
const r = [];
for (const char of this._nextIds) {
r.unshift(this._chars[char]);
}
this._increment();
return r.join('');
}
_increment() {
for (let i = 0; i < this._nextIds.length; i++) {
const val = ++this._nextIds[i];
if (val >= this._chars.length) {
this._nextIds[i] = 0;
}
else {
return;
}
}
this._nextIds.push(0);
}
*[Symbol.iterator]() {
while (true) {
yield this.next();
}
}
}
exports.default = IdentifierGenerator;
import { CodegenResult, ParserOptions, RootNode } from '@vue/compiler-core';
import { CompilerOptions } from './options';
export declare function parse(template: string, options?: ParserOptions): RootNode;
export declare function compile(template: string, options?: CompilerOptions): CodegenResult;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compile = exports.parse = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const compile_1 = require("./compile");
const parserOptions_1 = require("./parserOptions");
function parse(template, options = {}) {
return (0, compiler_core_1.baseParse)(template, (0, shared_1.extend)({}, parserOptions_1.parserOptions, options));
}
exports.parse = parse;
function compile(template, options = {}) {
return (0, compile_1.baseCompile)(template, (0, shared_1.extend)({}, parserOptions_1.parserOptions, options, {
directiveTransforms: (0, shared_1.extend)({}, options.directiveTransforms || {}),
}));
}
exports.compile = compile;
此差异已折叠。
import { ParserPlugin } from '@babel/parser';
import { BindingMetadata, CompilerError } from '@vue/compiler-core';
import IdentifierGenerator from './identifier';
import { DirectiveTransform, NodeTransform } from './transform';
export interface ErrorHandlingOptions {
onWarn?: (warning: CompilerError) => void;
onError?: (error: CompilerError) => void;
}
interface SharedTransformCodegenOptions {
inline?: boolean;
isTS?: boolean;
filename?: string;
bindingMetadata?: BindingMetadata;
prefixIdentifiers?: boolean;
}
export interface TransformOptions extends SharedTransformCodegenOptions, ErrorHandlingOptions {
nodeTransforms?: NodeTransform[];
directiveTransforms?: Record<string, DirectiveTransform | undefined>;
isBuiltInComponent?: (tag: string) => symbol | void;
isCustomElement?: (tag: string) => boolean | void;
expressionPlugins?: ParserPlugin[];
}
export interface CodegenScope {
id: IdentifierGenerator;
identifiers: {
[name: string]: number | undefined;
};
body: string[];
scopes: CodegenVForScope[];
}
export interface CodegenVForScopeInit {
source: string;
value?: string;
key?: string;
index?: string;
identifiers: {
[name: string]: number | undefined;
};
}
export interface CodegenVForScope extends CodegenScope, CodegenVForScopeInit {
}
export interface CodegenOptions extends SharedTransformCodegenOptions {
mode?: 'module' | 'function';
scopeId?: string | null;
scope?: CodegenScope;
runtimeModuleName?: string;
runtimeGlobalName?: string;
}
export declare type CompilerOptions = TransformOptions & CodegenOptions;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
import { ParserOptions } from '@vue/compiler-core';
export declare const enum DOMNamespaces {
HTML = 0,
SVG = 1,
MATH_ML = 2
}
export declare const parserOptions: ParserOptions;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parserOptions = void 0;
const shared_1 = require("@vue/shared");
const decodeHtml_1 = require("./decodeHtml");
const isRawTextContainer = /*#__PURE__*/ (0, shared_1.makeMap)('style,iframe,script,noscript', true);
exports.parserOptions = {
isVoidTag: shared_1.isVoidTag,
isNativeTag: (tag) => (0, shared_1.isHTMLTag)(tag) || (0, shared_1.isSVGTag)(tag),
isPreTag: (tag) => tag === 'pre',
decodeEntities: decodeHtml_1.decodeHtml,
// https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher
getNamespace(tag, parent) {
let ns = parent ? parent.ns : 0 /* HTML */;
if (parent && ns === 2 /* MATH_ML */) {
if (parent.tag === 'annotation-xml') {
if (tag === 'svg') {
return 1 /* SVG */;
}
if (parent.props.some((a) => a.type === 6 /* ATTRIBUTE */ &&
a.name === 'encoding' &&
a.value != null &&
(a.value.content === 'text/html' ||
a.value.content === 'application/xhtml+xml'))) {
ns = 0 /* HTML */;
}
}
else if (/^m(?:[ions]|text)$/.test(parent.tag) &&
tag !== 'mglyph' &&
tag !== 'malignmark') {
ns = 0 /* HTML */;
}
}
else if (parent && ns === 1 /* SVG */) {
if (parent.tag === 'foreignObject' ||
parent.tag === 'desc' ||
parent.tag === 'title') {
ns = 0 /* HTML */;
}
}
if (ns === 0 /* HTML */) {
if (tag === 'svg') {
return 1 /* SVG */;
}
if (tag === 'math') {
return 2 /* MATH_ML */;
}
}
return ns;
},
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments
getTextMode({ tag, ns }) {
if (ns === 0 /* HTML */) {
if (tag === 'textarea' || tag === 'title') {
return 1 /* RCDATA */;
}
if (isRawTextContainer(tag)) {
return 2 /* RAWTEXT */;
}
}
return 0 /* DATA */;
},
};
import { DirectiveNode, ElementNode, Property, RootNode, ParentNode, TemplateChildNode, CompilerError, ExpressionNode } from '@vue/compiler-core';
import { CodegenScope, CodegenVForScope, CodegenVForScopeInit, TransformOptions } from './options';
export declare type NodeTransform = (node: RootNode | TemplateChildNode, context: TransformContext) => void | (() => void) | (() => void)[];
export declare type DirectiveTransform = (dir: DirectiveNode, node: ElementNode, context: TransformContext, augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult) => DirectiveTransformResult;
interface DirectiveTransformResult {
props: Property[];
needRuntime?: boolean | symbol;
}
export interface ErrorHandlingOptions {
onWarn?: (warning: CompilerError) => void;
onError?: (error: CompilerError) => void;
}
export interface TransformContext extends Required<Omit<TransformOptions, 'filename'>> {
currentNode: RootNode | TemplateChildNode | null;
parent: ParentNode | null;
childIndex: number;
helpers: Map<symbol, number>;
identifiers: {
[name: string]: number | undefined;
};
scopes: {
vFor: number;
};
scope: CodegenScope;
currentScope: CodegenScope | CodegenVForScope;
helper<T extends symbol>(name: T): T;
removeHelper<T extends symbol>(name: T): void;
helperString(name: symbol): string;
onNodeRemoved(): void;
addIdentifiers(exp: ExpressionNode | string): void;
removeIdentifiers(exp: ExpressionNode | string): void;
addVForScope(initScope: CodegenVForScopeInit): CodegenVForScope;
}
export declare function transform(root: RootNode, options: TransformOptions): TransformContext;
export declare function traverseNode(node: RootNode | TemplateChildNode, context: TransformContext): void;
export declare function traverseChildren(parent: ParentNode, context: TransformContext): void;
export declare function createTransformContext(root: RootNode, { isTS, inline, bindingMetadata, prefixIdentifiers, nodeTransforms, directiveTransforms, isBuiltInComponent, isCustomElement, expressionPlugins, onError, onWarn, }: TransformOptions): TransformContext;
export {};
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTransformContext = exports.traverseChildren = exports.traverseNode = exports.transform = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const identifier_1 = __importDefault(require("./identifier"));
function transform(root, options) {
const context = createTransformContext(root, options);
traverseNode(root, context);
return context;
}
exports.transform = transform;
function traverseNode(node, context) {
context.currentNode = node;
// apply transform plugins
const { nodeTransforms } = context;
const exitFns = [];
for (let i = 0; i < nodeTransforms.length; i++) {
const onExit = nodeTransforms[i](node, context);
if (onExit) {
if ((0, shared_1.isArray)(onExit)) {
exitFns.push(...onExit);
}
else {
exitFns.push(onExit);
}
}
if (!context.currentNode) {
// node was removed
return;
}
else {
// node may have been replaced
node = context.currentNode;
}
}
switch (node.type) {
case 3 /* COMMENT */:
context.helper(compiler_core_1.CREATE_COMMENT);
break;
case 5 /* INTERPOLATION */:
context.helper(compiler_core_1.TO_DISPLAY_STRING);
break;
// for container types, further traverse downwards
case 9 /* IF */:
for (let i = 0; i < node.branches.length; i++) {
traverseNode(node.branches[i], context);
}
break;
case 10 /* IF_BRANCH */:
case 11 /* FOR */:
case 1 /* ELEMENT */:
case 0 /* ROOT */:
traverseChildren(node, context);
break;
}
// exit transforms
context.currentNode = node;
let i = exitFns.length;
while (i--) {
exitFns[i]();
}
}
exports.traverseNode = traverseNode;
function traverseChildren(parent, context) {
let i = 0;
const nodeRemoved = () => {
i--;
};
for (; i < parent.children.length; i++) {
const child = parent.children[i];
if ((0, shared_1.isString)(child))
continue;
context.parent = parent;
context.childIndex = i;
context.onNodeRemoved = nodeRemoved;
traverseNode(child, context);
}
}
exports.traverseChildren = traverseChildren;
function defaultOnError(error) {
throw error;
}
function defaultOnWarn(msg) {
console.warn(`[Vue warn] ${msg.message}`);
}
function createTransformContext(root, { isTS = false, inline = false, bindingMetadata = shared_1.EMPTY_OBJ, prefixIdentifiers = false, nodeTransforms = [], directiveTransforms = {}, isBuiltInComponent = shared_1.NOOP, isCustomElement = shared_1.NOOP, expressionPlugins = [], onError = defaultOnError, onWarn = defaultOnWarn, }) {
const scope = {
id: new identifier_1.default(),
identifiers: Object.create(null),
body: [],
scopes: [],
};
const scopes = {
vFor: 0,
};
function getScope(depth) {
let currentScope = scope;
while (depth-- > 0) {
currentScope = currentScope.scopes[currentScope.scopes.length - 1];
}
return currentScope;
}
const context = {
// options
isTS,
inline,
bindingMetadata,
prefixIdentifiers,
nodeTransforms,
directiveTransforms,
expressionPlugins,
isBuiltInComponent,
isCustomElement,
onError,
onWarn,
// state
parent: null,
childIndex: 0,
helpers: new Map(),
identifiers: Object.create(null),
scope,
scopes,
get currentScope() {
return getScope(scopes.vFor);
},
currentNode: root,
// methods
addVForScope(initScope) {
const vForScope = (0, shared_1.extend)({
id: new identifier_1.default(),
body: [],
scopes: [],
}, initScope);
getScope(scopes.vFor - 1).scopes.push(vForScope);
return vForScope;
},
helper(name) {
const count = context.helpers.get(name) || 0;
context.helpers.set(name, count + 1);
return name;
},
removeHelper(name) {
const count = context.helpers.get(name);
if (count) {
const currentCount = count - 1;
if (!currentCount) {
context.helpers.delete(name);
}
else {
context.helpers.set(name, currentCount);
}
}
},
helperString(name) {
return `_${compiler_core_1.helperNameMap[context.helper(name)]}`;
},
onNodeRemoved: () => { },
addIdentifiers(exp) {
if ((0, shared_1.isString)(exp)) {
addId(exp);
}
else if (exp.identifiers) {
exp.identifiers.forEach(addId);
}
else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {
addId(exp.content);
}
},
removeIdentifiers(exp) {
if ((0, shared_1.isString)(exp)) {
removeId(exp);
}
else if (exp.identifiers) {
exp.identifiers.forEach(removeId);
}
else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {
removeId(exp.content);
}
},
};
function addId(id) {
const { identifiers } = context;
if (identifiers[id] === undefined) {
identifiers[id] = 0;
}
identifiers[id]++;
}
function removeId(id) {
context.identifiers[id]--;
}
return context;
}
exports.createTransformContext = createTransformContext;
import { ExpressionNode, SimpleExpressionNode } from '@vue/compiler-core';
import { NodeTransform, TransformContext } from '../transform';
export declare const transformExpression: NodeTransform;
export declare function processExpression(node: SimpleExpressionNode, context: TransformContext, asParams?: boolean, asRawStatements?: boolean, localVars?: Record<string, number>): ExpressionNode;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processExpression = exports.transformExpression = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const parser_1 = require("@babel/parser");
const isLiteralWhitelisted = /*#__PURE__*/ (0, shared_1.makeMap)('true,false,null,this');
const transformExpression = (node, context) => {
if (node.type === 5 /* INTERPOLATION */) {
node.content = processExpression(node.content, context);
}
else if (node.type === 1 /* ELEMENT */) {
// handle directives on element
for (let i = 0; i < node.props.length; i++) {
const dir = node.props[i];
// do not process for v-on & v-for since they are special handled
if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {
const exp = dir.exp;
const arg = dir.arg;
// do not process exp if this is v-on:arg - we need special handling
// for wrapping inline statements.
if (exp &&
exp.type === 4 /* SIMPLE_EXPRESSION */ &&
!(dir.name === 'on' && arg)) {
dir.exp = processExpression(exp, context,
// slot args must be processed as function params
dir.name === 'slot');
}
if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {
dir.arg = processExpression(arg, context);
}
}
}
}
};
exports.transformExpression = transformExpression;
function processExpression(node, context,
// some expressions like v-slot props & v-for aliases should be parsed as
// function params
asParams = false,
// v-on handler values may contain multiple statements
asRawStatements = false, localVars = Object.create(context.identifiers)) {
if (!node.content.trim()) {
return node;
}
const { inline, bindingMetadata } = context;
const rewriteIdentifier = (raw, parent, id) => {
const type = (0, shared_1.hasOwn)(bindingMetadata, raw) && bindingMetadata[raw];
if (inline) {
// x = y
const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id;
// x++
const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id;
// ({ x } = y)
const isDestructureAssignment = parent && (0, compiler_core_1.isInDestructureAssignment)(parent, parentStack);
if (type === "setup-const" /* SETUP_CONST */ || localVars[raw]) {
return raw;
}
else if (type === "setup-ref" /* SETUP_REF */) {
return `${raw}.value`;
}
else if (type === "setup-maybe-ref" /* SETUP_MAYBE_REF */) {
// const binding that may or may not be ref
// if it's not a ref, then assignments don't make sense -
// so we ignore the non-ref assignment case and generate code
// that assumes the value to be a ref for more efficiency
return isAssignmentLVal || isUpdateArg || isDestructureAssignment
? `${raw}.value`
: `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
else if (type === "setup-let" /* SETUP_LET */) {
if (isAssignmentLVal) {
// let binding.
// this is a bit more tricky as we need to cover the case where
// let is a local non-ref value, and we need to replicate the
// right hand side value.
// x = y --> isRef(x) ? x.value = y : x = y
const { right: rVal, operator } = parent;
const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1);
const rExpString = stringifyExpression(processExpression((0, compiler_core_1.createSimpleExpression)(rExp, false), context, false, false, knownIds));
return `${context.helperString(compiler_core_1.IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${raw}.value ${operator} ${rExpString} : ${raw}`;
}
else if (isUpdateArg) {
// make id replace parent in the code range so the raw update operator
// is removed
id.start = parent.start;
id.end = parent.end;
const { prefix: isPrefix, operator } = parent;
const prefix = isPrefix ? operator : ``;
const postfix = isPrefix ? `` : operator;
// let binding.
// x++ --> isRef(a) ? a.value++ : a++
return `${context.helperString(compiler_core_1.IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${prefix}${raw}.value${postfix} : ${prefix}${raw}${postfix}`;
}
else if (isDestructureAssignment) {
// TODO
// let binding in a destructure assignment - it's very tricky to
// handle both possible cases here without altering the original
// structure of the code, so we just assume it's not a ref here
// for now
return raw;
}
else {
return `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
}
else if (type === "props" /* PROPS */) {
// use __props which is generated by compileScript so in ts mode
// it gets correct type
return `__props.${raw}`;
}
}
else {
if (type && type.startsWith('setup')) {
// setup bindings in non-inline mode
return `$setup.${raw}`;
}
else if (type) {
return `$${type}.${raw}`;
}
}
// fallback to ctx
return `_ctx.${raw}`;
};
// fast path if expression is a simple identifier.
const rawExp = node.content;
// bail constant on parens (function invocation) and dot (member access)
const bailConstant = rawExp.indexOf(`(`) > -1 || rawExp.indexOf('.') > 0;
if ((0, compiler_core_1.isSimpleIdentifier)(rawExp)) {
const isScopeVarReference = context.identifiers[rawExp];
const isAllowedGlobal = (0, shared_1.isGloballyWhitelisted)(rawExp);
const isLiteral = isLiteralWhitelisted(rawExp);
if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) {
// const bindings exposed from setup can be skipped for patching but
// cannot be hoisted to module scope
if (bindingMetadata[node.content] === "setup-const" /* SETUP_CONST */) {
node.constType = 1 /* CAN_SKIP_PATCH */;
}
node.content = rewriteIdentifier(rawExp);
}
else if (!isScopeVarReference) {
if (isLiteral) {
node.constType = 3 /* CAN_STRINGIFY */;
}
else {
node.constType = 2 /* CAN_HOIST */;
}
}
return node;
}
let ast;
// exp needs to be parsed differently:
// 1. Multiple inline statements (v-on, with presence of `;`): parse as raw
// exp, but make sure to pad with spaces for consistent ranges
// 2. Expressions: wrap with parens (for e.g. object expressions)
// 3. Function arguments (v-for, v-slot): place in a function argument position
const source = asRawStatements
? ` ${rawExp} `
: `(${rawExp})${asParams ? `=>{}` : ``}`;
try {
ast = (0, parser_1.parse)(source, {
plugins: [...context.expressionPlugins, ...shared_1.babelParserDefaultPlugins],
}).program;
}
catch (e) {
context.onError((0, compiler_core_1.createCompilerError)(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, e.message));
return node;
}
const ids = [];
const parentStack = [];
const knownIds = Object.create(context.identifiers);
(0, compiler_core_1.walkIdentifiers)(ast, (node, parent, _, isReferenced, isLocal) => {
if ((0, compiler_core_1.isStaticPropertyKey)(node, parent)) {
return;
}
const needPrefix = isReferenced && canPrefix(node);
if (needPrefix && !isLocal) {
if ((0, compiler_core_1.isStaticProperty)(parent) && parent.shorthand) {
// property shorthand like { foo }, we need to add the key since
// we rewrite the value
;
node.prefix = `${node.name}: `;
}
node.name = rewriteIdentifier(node.name, parent, node);
ids.push(node);
}
else {
// The identifier is considered constant unless it's pointing to a
// local scope variable (a v-for alias, or a v-slot prop)
if (!(needPrefix && isLocal) && !bailConstant) {
;
node.isConstant = true;
}
// also generate sub-expressions for other identifiers for better
// source map support. (except for property keys which are static)
ids.push(node);
}
}, true, // invoke on ALL identifiers
parentStack, knownIds);
// We break up the compound expression into an array of strings and sub
// expressions (for identifiers that have been prefixed). In codegen, if
// an ExpressionNode has the `.children` property, it will be used instead of
// `.content`.
const children = [];
ids.sort((a, b) => a.start - b.start);
ids.forEach((id, i) => {
// range is offset by -1 due to the wrapping parens when parsed
const start = id.start - 1;
const end = id.end - 1;
const last = ids[i - 1];
const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);
if (leadingText.length || id.prefix) {
children.push(leadingText + (id.prefix || ``));
}
const source = rawExp.slice(start, end);
children.push((0, compiler_core_1.createSimpleExpression)(id.name, false, {
source,
start: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, start),
end: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, end),
}, id.isConstant ? 3 /* CAN_STRINGIFY */ : 0 /* NOT_CONSTANT */));
if (i === ids.length - 1 && end < rawExp.length) {
children.push(rawExp.slice(end));
}
});
let ret;
if (children.length) {
ret = (0, compiler_core_1.createCompoundExpression)(children, node.loc);
}
else {
ret = node;
ret.constType = bailConstant
? 0 /* NOT_CONSTANT */
: 3 /* CAN_STRINGIFY */;
}
ret.identifiers = Object.keys(knownIds);
return ret;
}
exports.processExpression = processExpression;
function canPrefix(id) {
// skip whitelisted globals
if ((0, shared_1.isGloballyWhitelisted)(id.name)) {
return false;
}
// special case for webpack compilation
if (id.name === 'require') {
return false;
}
return true;
}
function stringifyExpression(exp) {
if ((0, shared_1.isString)(exp)) {
return exp;
}
else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {
return exp.content;
}
else {
return exp.children
.map(stringifyExpression)
.join('');
}
}
import { NodeTransform } from '../transform';
export declare const transformIdentifier: NodeTransform;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformIdentifier = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const ast_1 = require("../ast");
const codegen_1 = require("../codegen");
const transformIdentifier = (node, context) => {
const { currentScope } = context;
return () => {
if (node.type === 5 /* INTERPOLATION */) {
const id = currentScope.id.next();
const genNodeContext = (0, codegen_1.genNode)(node.content);
currentScope.body.push((0, ast_1.createVariableDeclaration)(id, genNodeContext.code));
node.content = (0, compiler_core_1.createSimpleExpression)(id);
}
};
};
exports.transformIdentifier = transformIdentifier;
import { ExpressionNode, SimpleExpressionNode } from '@vue/compiler-core';
import { NodeTransform, TransformContext } from '../transform';
export declare const transformFor: NodeTransform;
export interface ForParseResult {
source: ExpressionNode;
value: ExpressionNode | undefined;
key: ExpressionNode | undefined;
index: ExpressionNode | undefined;
}
export declare function parseForExpression(input: SimpleExpressionNode, context: TransformContext): ForParseResult | undefined;
export declare function createForLoopParams({ value, key, index }: ForParseResult, memoArgs?: ExpressionNode[]): ExpressionNode[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createForLoopParams = exports.parseForExpression = exports.transformFor = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const ast_1 = require("../ast");
const codegen_1 = require("../codegen");
const transformExpression_1 = require("./transformExpression");
exports.transformFor = (0, compiler_core_1.createStructuralDirectiveTransform)('for', (_node, dir, _context) => {
const context = _context;
if (!dir.exp) {
context.onError((0, compiler_core_1.createCompilerError)(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));
return;
}
const parseResult = parseForExpression(dir.exp, context);
if (!parseResult) {
context.onError((0, compiler_core_1.createCompilerError)(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));
return;
}
const { addIdentifiers, removeIdentifiers, scopes } = context;
const { source, value, key, index } = parseResult;
scopes.vFor++;
if (context.prefixIdentifiers) {
value && addIdentifiers(value);
key && addIdentifiers(key);
index && addIdentifiers(index);
}
const vForScope = context.addVForScope({
source: source.content,
value: value ? value.content : '',
key: key ? key.content : '',
index: index ? index.content : '',
identifiers: {},
});
return () => {
scopes.vFor--;
if (context.prefixIdentifiers) {
value && removeIdentifiers(value);
key && removeIdentifiers(key);
index && removeIdentifiers(index);
}
const { currentScope } = context;
currentScope.body.push((0, ast_1.createVariableDeclaration)(currentScope.id.next(), (0, codegen_1.genVForScope)(vForScope)));
};
});
const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
const stripParensRE = /^\(|\)$/g;
function parseForExpression(input, context) {
const loc = input.loc;
const exp = input.content;
const inMatch = exp.match(forAliasRE);
if (!inMatch)
return;
const [, LHS, RHS] = inMatch;
const result = {
source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),
value: undefined,
key: undefined,
index: undefined,
};
if (context.prefixIdentifiers) {
result.source = (0, transformExpression_1.processExpression)(result.source, context);
}
let valueContent = LHS.trim().replace(stripParensRE, '').trim();
const trimmedOffset = LHS.indexOf(valueContent);
const iteratorMatch = valueContent.match(forIteratorRE);
if (iteratorMatch) {
valueContent = valueContent.replace(forIteratorRE, '').trim();
const keyContent = iteratorMatch[1].trim();
let keyOffset;
if (keyContent) {
keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);
result.key = createAliasExpression(loc, keyContent, keyOffset);
if (context.prefixIdentifiers) {
result.key = (0, transformExpression_1.processExpression)(result.key, context, true);
}
}
if (iteratorMatch[2]) {
const indexContent = iteratorMatch[2].trim();
if (indexContent) {
result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key
? keyOffset + keyContent.length
: trimmedOffset + valueContent.length));
if (context.prefixIdentifiers) {
result.index = (0, transformExpression_1.processExpression)(result.index, context, true);
}
}
}
}
if (valueContent) {
result.value = createAliasExpression(loc, valueContent, trimmedOffset);
if (context.prefixIdentifiers) {
result.value = (0, transformExpression_1.processExpression)(result.value, context, true);
}
}
return result;
}
exports.parseForExpression = parseForExpression;
function createAliasExpression(range, content, offset) {
return (0, compiler_core_1.createSimpleExpression)(content, false, (0, compiler_core_1.getInnerRange)(range, offset, content.length));
}
function createForLoopParams({ value, key, index }, memoArgs = []) {
return createParamsList([value, key, index, ...memoArgs]);
}
exports.createForLoopParams = createForLoopParams;
function createParamsList(args) {
let i = args.length;
while (i--) {
if (args[i])
break;
}
return args
.slice(0, i + 1)
.map((arg, i) => arg || (0, compiler_core_1.createSimpleExpression)(`_`.repeat(i + 1), false));
}
{
"name": "@dcloudio/uni-mp-compiler",
"version": "3.0.0-alpha-3000020210913001",
"description": "uni-mp-compiler",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-mp-compiler"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "Apache-2.0",
"gitHead": "453a3e6ead807864087692f4339ea3d667045fe7",
"dependencies": {
"@babel/parser": "^7.15.0",
"@babel/types": "^7.15.0",
"@vue/compiler-core": "3.2.19",
"estree-walker": "^3.0.0"
}
}
import { parseExpression } from '@babel/parser'
import {
identifier,
blockStatement,
callExpression,
objectProperty,
objectExpression,
spreadElement,
ObjectProperty,
ObjectExpression,
Expression,
SpreadElement,
ConditionalExpression,
arrowFunctionExpression,
Identifier,
returnStatement,
conditionalExpression,
} from '@babel/types'
import { CodegenScope, CodegenVForScope, CodegenVIfScope } from './options'
export function createIdentifier(name: string) {
return identifier(name)
}
export function createObjectProperty(
name: string,
value: Expression
): ObjectProperty {
return objectProperty(identifier(name), value)
}
export function createSpreadElement(argument: ConditionalExpression) {
return spreadElement(argument)
}
export function createObjectExpression(
properties: Array<ObjectProperty | SpreadElement>
): ObjectExpression {
return objectExpression(properties)
}
export function createVIfProperty(condition: Expression, { id }: CodegenScope) {
return objectProperty(identifier(id.next()), condition)
}
export function createVIfConditionalExpression({
condition,
properties,
}: CodegenVIfScope) {
return conditionalExpression(
condition!,
objectExpression(properties),
objectExpression([])
)
}
export function createVIfSpreadElement(vIfScope: CodegenVIfScope) {
return spreadElement(createVIfConditionalExpression(vIfScope))
}
// export function createVIfProperties(
// vIfScope: CodegenVIfScope,
// { id, scopes }: CodegenScope
// ) {
// const index = scopes.indexOf(vIfScope)
// const vIfProperties: ObjectProperty[] = []
// let vIfspreadElement: SpreadElement
// let alternateExpr: ConditionalExpression | ObjectExpression =
// objectExpression([])
// for (let i = scopes.length - 1; i >= index; i--) {
// const { name, condition, properties } = scopes[i] as CodegenVIfScope
// if (name === 'if') {
// vIfProperties.push(objectProperty(identifier(id.next()), condition!))
// vIfspreadElement = spreadElement(
// conditionalExpression(
// condition!,
// objectExpression(properties),
// alternateExpr
// )
// )
// } else if (name === 'else-if') {
// vIfProperties.push(objectProperty(identifier(id.next()), condition!))
// alternateExpr = conditionalExpression(
// condition!,
// objectExpression(properties),
// alternateExpr
// )
// } else if (name === 'else') {
// alternateExpr = objectExpression(properties)
// }
// }
// return [...vIfProperties.reverse(), vIfspreadElement!]
// }
export function createVForCallExpression(vForScope: CodegenVForScope) {
return callExpression(identifier('vFor'), [
parseExpression(vForScope.source),
createVForArrowFunctionExpression(vForScope),
])
}
function createVForArrowFunctionExpression(vForScope: CodegenVForScope) {
const params: Identifier[] = []
if (vForScope.value) {
params.push(identifier(vForScope.value))
}
if (vForScope.key) {
params.push(identifier(vForScope.key))
}
if (vForScope.index) {
params.push(identifier(vForScope.index))
}
return arrowFunctionExpression(
params,
blockStatement([returnStatement(objectExpression(vForScope.properties))])
)
}
import {
RootNode,
CodegenContext,
CodegenResult,
helperNameMap,
CompoundExpressionNode,
SimpleExpressionNode,
InterpolationNode,
TextNode,
NodeTypes,
TO_DISPLAY_STRING,
} from '@vue/compiler-core'
import { isString, isSymbol } from '@vue/shared'
import { CodegenOptions, CodegenScope, CodegenVForScope } from './options'
interface MPCodegenContext
extends Omit<
CodegenContext,
'sourceMap' | 'optimizeImports' | 'ssrRuntimeModuleName' | 'ssr' | 'inSSR'
> {}
export function generate(
ast: RootNode,
options: CodegenOptions & {
onContextCreated?: (context: MPCodegenContext) => void
} = {}
): CodegenResult {
const context = createCodegenContext(ast, options)
const { push, indent, deindent, mode } = context
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()
deindent()
push(`}`)
return {
code: context.code,
preamble: '',
ast,
}
}
function createCodegenContext(
ast: RootNode,
{
mode = 'function',
prefixIdentifiers = mode === 'module',
filename = `template.vue.html`,
scopeId = null,
runtimeGlobalName = `Vue`,
runtimeModuleName = `vue`,
isTS = false,
}: CodegenOptions
) {
const context: MPCodegenContext = {
mode,
prefixIdentifiers,
filename,
scopeId,
runtimeGlobalName,
runtimeModuleName,
isTS,
source: ast.loc.source,
code: ``,
column: 1,
line: 1,
offset: 0,
indentLevel: 0,
pure: false,
map: undefined,
helper(key) {
return `_${helperNameMap[key]}`
},
push(code, node) {
context.code += code
},
indent() {
newline(++context.indentLevel)
},
deindent(withoutNewLine = false) {
if (withoutNewLine) {
--context.indentLevel
} else {
newline(--context.indentLevel)
}
},
newline() {
newline(context.indentLevel)
},
}
function newline(n: number) {
context.push('\n' + ` `.repeat(n))
}
return context
}
function genModulePreamble(
ast: RootNode,
context: MPCodegenContext,
inline?: boolean
) {
const { push, newline, runtimeModuleName } = context
// generate import statements for helpers
if (ast.helpers.length) {
push(
`import { ${ast.helpers
.map((s) => `${helperNameMap[s]} as _${helperNameMap[s]}`)
.join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`
)
}
newline()
if (!inline) {
push(`export `)
}
}
function genFunctionPreamble(ast: RootNode, context: MPCodegenContext) {
const { prefixIdentifiers, push, newline, runtimeGlobalName } = context
const VueBinding = runtimeGlobalName
const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
// Generate const declaration for helpers
// In prefix mode, we place the const declaration at top so it's done
// only once; But if we not prefixing, we place the declaration inside the
// with block so it doesn't incur the `in` check cost for every helper access.
if (ast.helpers.length > 0) {
if (prefixIdentifiers) {
push(
`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`
)
} else {
// "with" mode.
// save Vue in a separate variable to avoid collision
push(`const _Vue = ${VueBinding}\n`)
// in "with" mode, helpers are declared inside the with block to avoid
// has check cost, but hoists are lifted out of the function - we need
// to provide the helper here.
}
}
newline()
push(`return `)
}
type CodegenNode =
| SimpleExpressionNode
| CompoundExpressionNode
| InterpolationNode
| TextNode
| string
| symbol
interface GenNodeContext {
code: string
helper(key: symbol): string
push(code: string, node?: CodegenNode): void
}
function createGenNodeContext() {
const context: GenNodeContext = {
code: '',
helper(key) {
return `_${helperNameMap[key]}`
},
push(code) {
context.code += code
},
}
return context
}
export function genNode(
node: CodegenNode | symbol | string,
context?: GenNodeContext
) {
if (!context) {
context = createGenNodeContext()
}
if (isString(node)) {
context.push(node)
return context
}
if (isSymbol(node)) {
context.push(context.helper(node))
return context
}
switch (node.type) {
case NodeTypes.TEXT:
genText(node, context)
break
case NodeTypes.SIMPLE_EXPRESSION:
genExpression(node, context)
break
case NodeTypes.INTERPOLATION:
genInterpolation(node, context)
break
case NodeTypes.COMPOUND_EXPRESSION:
genCompoundExpression(node, context)
break
}
return context
}
function genText(
node: TextNode | SimpleExpressionNode,
context: GenNodeContext
) {
context.push(JSON.stringify(node.content), node)
}
function genExpression(node: SimpleExpressionNode, context: GenNodeContext) {
const { content, isStatic } = node
context.push(isStatic ? JSON.stringify(content) : content, node)
}
function genInterpolation(node: InterpolationNode, context: GenNodeContext) {
const { push, helper } = context
push(`${helper(TO_DISPLAY_STRING)}(`)
genNode(node.content, context)
push(`)`)
}
function genCompoundExpression(
node: CompoundExpressionNode,
context: GenNodeContext
) {
for (let i = 0; i < node.children!.length; i++) {
const child = node.children![i]
if (isString(child)) {
context.push(child)
} else {
genNode(child, context)
}
}
}
import { isString, isSymbol } from '@vue/shared'
import {
CodegenResult,
CompoundExpressionNode,
helperNameMap,
InterpolationNode,
NodeTypes,
SimpleExpressionNode,
TextNode,
TO_DISPLAY_STRING,
} from '@vue/compiler-core'
import { default as babelGenerate } from '@babel/generator'
import { CodegenOptions, CodegenScope } from './options'
import { createObjectExpression } from './ast'
export function generate(
scope: CodegenScope,
options: CodegenOptions
): Omit<CodegenResult, 'ast'> {
const isSetupInlined = !!options.inline
// 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(', ')
const codes: string[] = []
if (isSetupInlined) {
codes.push(`(${signature}) => {`)
} else {
codes.push(`function ${functionName}(${signature}) {`)
}
codes.push(
`return ` +
babelGenerate(createObjectExpression(scope.properties), {
// concise: true,
}).code
)
codes.push(`}`)
return {
code: codes.join('\n'),
preamble: '',
}
}
type CodegenNode =
| SimpleExpressionNode
| CompoundExpressionNode
| InterpolationNode
| TextNode
| string
| symbol
interface GenNodeContext {
code: string
helper(key: symbol): string
push(code: string, node?: CodegenNode): void
}
function createGenNodeContext() {
const context: GenNodeContext = {
code: '',
helper(key) {
return `_${helperNameMap[key]}`
},
push(code) {
context.code += code
},
}
return context
}
export function genNode(
node: CodegenNode | symbol | string,
context?: GenNodeContext
) {
if (!context) {
context = createGenNodeContext()
}
if (isString(node)) {
context.push(node)
return context
}
if (isSymbol(node)) {
context.push(context.helper(node))
return context
}
switch (node.type) {
case NodeTypes.TEXT:
genText(node, context)
break
case NodeTypes.SIMPLE_EXPRESSION:
genExpression(node, context)
break
case NodeTypes.INTERPOLATION:
genInterpolation(node, context)
break
case NodeTypes.COMPOUND_EXPRESSION:
genCompoundExpression(node, context)
break
}
return context
}
function genText(
node: TextNode | SimpleExpressionNode,
context: GenNodeContext
) {
context.push(JSON.stringify(node.content), node)
}
function genExpression(node: SimpleExpressionNode, context: GenNodeContext) {
const { content, isStatic } = node
context.push(isStatic ? JSON.stringify(content) : content, node)
}
function genInterpolation(node: InterpolationNode, context: GenNodeContext) {
const { push, helper } = context
push(`${helper(TO_DISPLAY_STRING)}(`)
genNode(node.content, context)
push(`)`)
}
function genCompoundExpression(
node: CompoundExpressionNode,
context: GenNodeContext
) {
for (let i = 0; i < node.children!.length; i++) {
const child = node.children![i]
if (isString(child)) {
context.push(child)
} else {
genNode(child, context)
}
}
}
import { baseParse } from '@vue/compiler-core'
import { isString, extend } from '@vue/shared'
import { generate } from './codegen'
import { CompilerOptions } from './options'
import { DirectiveTransform, NodeTransform, transform } from './transform'
import { transformExpression } from './transforms/transformExpression'
import { transformIdentifier } from './transforms/transformIdentifier'
import { transformIf } from './transforms/vIf'
import { transformFor } from './transforms/vFor'
import { generate as genTemplate } from './template/codegen'
export type TransformPreset = [
NodeTransform[],
Record<string, DirectiveTransform>
]
export function getBaseTransformPreset(
prefixIdentifiers?: boolean
): TransformPreset {
const nodeTransforms = [transformIf, transformFor]
if (prefixIdentifiers) {
nodeTransforms.push(transformExpression)
}
return [nodeTransforms, {}]
}
export function baseCompile(template: string, options: CompilerOptions = {}) {
const prefixIdentifiers =
options.prefixIdentifiers === true || options.mode === 'module'
const ast = isString(template) ? baseParse(template, options) : template
const [nodeTransforms, directiveTransforms] =
getBaseTransformPreset(prefixIdentifiers)
const context = transform(
ast,
extend({}, options, {
prefixIdentifiers,
nodeTransforms: [
...nodeTransforms,
...(options.nodeTransforms || []),
transformIdentifier,
],
directiveTransforms: extend(
{},
directiveTransforms,
options.directiveTransforms || {}
),
})
)
const result = extend(generate(context.scope, options), { ast })
if (options.filename && options.emitFile) {
genTemplate(ast, { filename: options.filename, emitFile: options.emitFile })
}
return result
}
import { ParserOptions } from '@vue/compiler-core'
import namedCharacterReferences from './namedChars.json'
// lazy compute this to make this file tree-shakable for browser
let maxCRNameLength: number
export const decodeHtml: ParserOptions['decodeEntities'] = (
rawText,
asAttr
) => {
let offset = 0
const end = rawText.length
let decodedText = ''
function advance(length: number) {
offset += length
rawText = rawText.slice(length)
}
while (offset < end) {
const head = /&(?:#x?)?/i.exec(rawText)
if (!head || offset + head.index >= end) {
const remaining = end - offset
decodedText += rawText.slice(0, remaining)
advance(remaining)
break
}
// Advance to the "&".
decodedText += rawText.slice(0, head.index)
advance(head.index)
if (head[0] === '&') {
// Named character reference.
let name = ''
let value: string | undefined = undefined
if (/[0-9a-z]/i.test(rawText[1])) {
if (!maxCRNameLength) {
maxCRNameLength = Object.keys(namedCharacterReferences).reduce(
(max, name) => Math.max(max, name.length),
0
)
}
for (let length = maxCRNameLength; !value && length > 0; --length) {
name = rawText.substr(1, length)
value = (namedCharacterReferences as Record<string, string>)[name]
}
if (value) {
const semi = name.endsWith(';')
if (
asAttr &&
!semi &&
/[=a-z0-9]/i.test(rawText[name.length + 1] || '')
) {
decodedText += '&' + name
advance(1 + name.length)
} else {
decodedText += value
advance(1 + name.length)
}
} else {
decodedText += '&' + name
advance(1 + name.length)
}
} else {
decodedText += '&'
advance(1)
}
} else {
// Numeric character reference.
const hex = head[0] === '&#x'
const pattern = hex ? /^&#x([0-9a-f]+);?/i : /^&#([0-9]+);?/
const body = pattern.exec(rawText)
if (!body) {
decodedText += head[0]
advance(head[0].length)
} else {
// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
let cp = Number.parseInt(body[1], hex ? 16 : 10)
if (cp === 0) {
cp = 0xfffd
} else if (cp > 0x10ffff) {
cp = 0xfffd
} else if (cp >= 0xd800 && cp <= 0xdfff) {
cp = 0xfffd
} else if ((cp >= 0xfdd0 && cp <= 0xfdef) || (cp & 0xfffe) === 0xfffe) {
// noop
} else if (
(cp >= 0x01 && cp <= 0x08) ||
cp === 0x0b ||
(cp >= 0x0d && cp <= 0x1f) ||
(cp >= 0x7f && cp <= 0x9f)
) {
cp = CCR_REPLACEMENTS[cp] || cp
}
decodedText += String.fromCodePoint(cp)
advance(body[0].length)
}
}
}
return decodedText
}
// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
const CCR_REPLACEMENTS: Record<number, number | undefined> = {
0x80: 0x20ac,
0x82: 0x201a,
0x83: 0x0192,
0x84: 0x201e,
0x85: 0x2026,
0x86: 0x2020,
0x87: 0x2021,
0x88: 0x02c6,
0x89: 0x2030,
0x8a: 0x0160,
0x8b: 0x2039,
0x8c: 0x0152,
0x8e: 0x017d,
0x91: 0x2018,
0x92: 0x2019,
0x93: 0x201c,
0x94: 0x201d,
0x95: 0x2022,
0x96: 0x2013,
0x97: 0x2014,
0x98: 0x02dc,
0x99: 0x2122,
0x9a: 0x0161,
0x9b: 0x203a,
0x9c: 0x0153,
0x9e: 0x017e,
0x9f: 0x0178,
}
export default class IdentifierGenerator {
private _chars: string =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
private _nextIds: number[] = [0]
next() {
const r = []
for (const char of this._nextIds) {
r.unshift(this._chars[char])
}
this._increment()
return r.join('')
}
_increment() {
for (let i = 0; i < this._nextIds.length; i++) {
const val = ++this._nextIds[i]
if (val >= this._chars.length) {
this._nextIds[i] = 0
} else {
return
}
}
this._nextIds.push(0)
}
*[Symbol.iterator]() {
while (true) {
yield this.next()
}
}
}
import { extend } from '@vue/shared'
import {
baseParse,
CodegenResult,
ParserOptions,
RootNode,
} from '@vue/compiler-core'
import { baseCompile } from './compile'
import { parserOptions } from './parserOptions'
import { CompilerOptions } from './options'
export function parse(template: string, options: ParserOptions = {}): RootNode {
return baseParse(template, extend({}, parserOptions, options))
}
export function compile(
template: string,
options: CompilerOptions = {}
): CodegenResult {
return baseCompile(
template,
extend({}, parserOptions, options, {
directiveTransforms: extend({}, options.directiveTransforms || {}),
})
)
}
此差异已折叠。
import { ParserPlugin } from '@babel/parser'
import { Expression, ObjectProperty, SpreadElement } from '@babel/types'
import { BindingMetadata, CompilerError } from '@vue/compiler-core'
import IdentifierGenerator from './identifier'
import { DirectiveTransform, NodeTransform } from './transform'
export interface ErrorHandlingOptions {
onWarn?: (warning: CompilerError) => void
onError?: (error: CompilerError) => void
}
interface SharedTransformCodegenOptions {
inline?: boolean
isTS?: boolean
filename?: string
bindingMetadata?: BindingMetadata
prefixIdentifiers?: boolean
}
export interface TransformOptions
extends SharedTransformCodegenOptions,
ErrorHandlingOptions {
nodeTransforms?: NodeTransform[]
directiveTransforms?: Record<string, DirectiveTransform | undefined>
isBuiltInComponent?: (tag: string) => symbol | void
isCustomElement?: (tag: string) => boolean | void
expressionPlugins?: ParserPlugin[]
}
export interface CodegenRootScope {
id: IdentifierGenerator
identifiers: string[]
properties: (ObjectProperty | SpreadElement)[]
scopes: (CodegenVIfScope | CodegenVForScope)[]
parent: CodegenScope | null
}
export interface CodegenVIfScopeInit {
name: 'if' | 'else-if' | 'else' | string
condition?: Expression
}
export interface CodegenVForScopeInit {
source: string
value?: string
key?: string
index?: string
}
export interface CodegenVIfScope
extends CodegenRootScope,
CodegenVIfScopeInit {}
export interface CodegenVForScope
extends CodegenRootScope,
CodegenVForScopeInit {}
export type CodegenScope = CodegenRootScope | CodegenVIfScope | CodegenVForScope
interface EmittedFile {
fileName?: string
name?: string
source?: string | Uint8Array
type: 'asset'
}
export interface CodegenOptions extends SharedTransformCodegenOptions {
mode?: 'module' | 'function'
scopeId?: string | null
runtimeModuleName?: string
runtimeGlobalName?: string
emitFile?: (emittedFile: EmittedFile) => string
}
export interface TemplateCodegenOptions {
filename: string
emitFile: (emittedFile: EmittedFile) => string
}
export type CompilerOptions = TransformOptions & CodegenOptions
import {
TextModes,
ParserOptions,
ElementNode,
Namespaces,
NodeTypes,
} from '@vue/compiler-core'
import { makeMap, isVoidTag, isHTMLTag, isSVGTag } from '@vue/shared'
import { decodeHtml } from './decodeHtml'
const isRawTextContainer = /*#__PURE__*/ makeMap(
'style,iframe,script,noscript',
true
)
export const enum DOMNamespaces {
HTML = Namespaces.HTML,
SVG,
MATH_ML,
}
export const parserOptions: ParserOptions = {
isVoidTag,
isNativeTag: (tag) => isHTMLTag(tag) || isSVGTag(tag),
isPreTag: (tag) => tag === 'pre',
decodeEntities: decodeHtml,
// https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher
getNamespace(tag: string, parent: ElementNode | undefined): DOMNamespaces {
let ns = parent ? parent.ns : DOMNamespaces.HTML
if (parent && ns === DOMNamespaces.MATH_ML) {
if (parent.tag === 'annotation-xml') {
if (tag === 'svg') {
return DOMNamespaces.SVG
}
if (
parent.props.some(
(a) =>
a.type === NodeTypes.ATTRIBUTE &&
a.name === 'encoding' &&
a.value != null &&
(a.value.content === 'text/html' ||
a.value.content === 'application/xhtml+xml')
)
) {
ns = DOMNamespaces.HTML
}
} else if (
/^m(?:[ions]|text)$/.test(parent.tag) &&
tag !== 'mglyph' &&
tag !== 'malignmark'
) {
ns = DOMNamespaces.HTML
}
} else if (parent && ns === DOMNamespaces.SVG) {
if (
parent.tag === 'foreignObject' ||
parent.tag === 'desc' ||
parent.tag === 'title'
) {
ns = DOMNamespaces.HTML
}
}
if (ns === DOMNamespaces.HTML) {
if (tag === 'svg') {
return DOMNamespaces.SVG
}
if (tag === 'math') {
return DOMNamespaces.MATH_ML
}
}
return ns
},
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-html-fragments
getTextMode({ tag, ns }: ElementNode): TextModes {
if (ns === DOMNamespaces.HTML) {
if (tag === 'textarea' || tag === 'title') {
return TextModes.RCDATA
}
if (isRawTextContainer(tag)) {
return TextModes.RAWTEXT
}
}
return TextModes.DATA
},
}
import {
AttributeNode,
DirectiveNode,
ElementNode,
ExpressionNode,
NodeTypes,
RootNode,
SimpleExpressionNode,
TemplateChildNode,
TextNode,
} from '@vue/compiler-core'
import { TemplateCodegenOptions } from '../options'
import { genNode as genCodeNode } from '../codegen'
import { ForNode } from '../transforms/vFor'
import { IfNode } from '../transforms/vIf'
interface TemplateCodegenContext {
code: string
push(code: string): void
}
export function generate(
{ children }: RootNode,
{ emitFile, filename }: TemplateCodegenOptions
) {
const context: TemplateCodegenContext = {
code: '',
push(code) {
context.code += code
},
}
children.forEach((node) => {
genNode(node, context)
})
emitFile({ type: 'asset', fileName: filename, source: context.code })
}
export function genNode(
node: TemplateChildNode,
context: TemplateCodegenContext
) {
switch (node.type) {
case NodeTypes.TEXT:
return genText(node, context)
case NodeTypes.INTERPOLATION:
return genExpression(node.content, context)
case NodeTypes.ELEMENT:
return genElement(node, context)
}
}
function genText(node: TextNode, { push }: TemplateCodegenContext) {
push(node.content)
}
function genExpression(node: ExpressionNode, { push }: TemplateCodegenContext) {
push(`{{${genCodeNode(node).code}}}`)
}
function genVIf(exp: string, { push }: TemplateCodegenContext) {
push(` wx:if="{{${exp}}}"`)
}
function genVElseIf(exp: string, { push }: TemplateCodegenContext) {
push(` wx:elif="{{${exp}}}"`)
}
function genVElse({ push }: TemplateCodegenContext) {
push(` wx:else`)
}
function genVFor(
node: ForNode,
props: (AttributeNode | DirectiveNode)[],
{ push }: TemplateCodegenContext
) {
push(` wx:for="{{${node.source}}}"`)
if (node.value) {
push(` wx:for-item="${node.value}"`)
}
if (node.key) {
push(` wx:for-index="${node.key}"`)
}
const keyIndex = props.findIndex(
(prop) =>
prop.type === NodeTypes.DIRECTIVE &&
prop.name === 'bind' &&
prop.arg &&
prop.arg.type === NodeTypes.SIMPLE_EXPRESSION &&
prop.arg.content === 'key'
)
if (keyIndex > -1) {
const keyProp = props[keyIndex] as DirectiveNode
const key = (keyProp.exp as SimpleExpressionNode).content
push(` wx:key="${key.includes('.') ? key.split('.')[1] : key}"`)
props.splice(keyIndex, 1)
}
}
export function genElement(node: ElementNode, context: TemplateCodegenContext) {
const { tag, children, isSelfClosing, props } = node
const { push } = context
push(`<${tag}`)
const ifNode = (node as any).ifNode as IfNode
if (ifNode) {
if (ifNode.name === 'if') {
genVIf(ifNode.condition, context)
} else if (ifNode.name === 'else-if') {
genVElseIf(ifNode.condition, context)
} else if (ifNode.name === 'else') {
genVElse(context)
}
}
const forNode = (node as any).forNode as ForNode
if (forNode) {
genVFor(forNode, props, context)
}
if (props.length) {
genElementProps(props, context)
}
if (isSelfClosing) {
push(`/>`)
} else {
push(`>`)
children.forEach((node) => {
genNode(node, context)
})
push(`</${tag}>`)
}
}
export function genElementProps(
props: Array<AttributeNode | DirectiveNode>,
context: TemplateCodegenContext
) {
const { push } = context
props.forEach((prop) => {
if (prop.type === NodeTypes.ATTRIBUTE) {
context.push(` ${prop.name}=${prop.value}`)
} else {
const { name } = prop
if (name === 'bind') {
push(` `)
genDirectiveNode(prop, context)
}
}
})
}
function genDirectiveNode(
prop: DirectiveNode,
{ push }: TemplateCodegenContext
) {
const arg = (prop.arg as SimpleExpressionNode).content
const exp = (prop.exp as SimpleExpressionNode).content
push(`${arg}="{{${exp}}}"`)
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
{
"extends": "../../tsconfig.node.json",
"compilerOptions": {
"outDir": "dist",
"resolveJsonModule": true
},
"include": ["src", "../shims-node.d.ts", "../shims-uni-app.d.ts"]
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
export declare function uniMainJsPlugin(): import("vite").Plugin;
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册