@vue/compiler-core 3.1.1 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler-core.cjs.js +169 -63
- package/dist/compiler-core.cjs.prod.js +169 -63
- package/dist/compiler-core.d.ts +7 -1
- package/dist/compiler-core.esm-bundler.js +168 -62
- package/package.json +2 -2
|
@@ -356,18 +356,84 @@ function isCoreComponent(tag) {
|
|
|
356
356
|
}
|
|
357
357
|
const nonIdentifierRE = /^\d|[^\$\w]/;
|
|
358
358
|
const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);
|
|
359
|
-
const
|
|
359
|
+
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/;
|
|
360
|
+
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/;
|
|
361
|
+
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g;
|
|
362
|
+
/**
|
|
363
|
+
* Simple lexer to check if an expression is a member expression. This is
|
|
364
|
+
* lax and only checks validity at the root level (i.e. does not validate exps
|
|
365
|
+
* inside square brackets), but it's ok since these are only used on template
|
|
366
|
+
* expressions and false positives are invalid expressions in the first place.
|
|
367
|
+
*/
|
|
360
368
|
const isMemberExpression = (path) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
369
|
+
// remove whitespaces around . or [ first
|
|
370
|
+
path = path.trim().replace(whitespaceRE, s => s.trim());
|
|
371
|
+
let state = 0 /* inMemberExp */;
|
|
372
|
+
let stateStack = [];
|
|
373
|
+
let currentOpenBracketCount = 0;
|
|
374
|
+
let currentOpenParensCount = 0;
|
|
375
|
+
let currentStringType = null;
|
|
376
|
+
for (let i = 0; i < path.length; i++) {
|
|
377
|
+
const char = path.charAt(i);
|
|
378
|
+
switch (state) {
|
|
379
|
+
case 0 /* inMemberExp */:
|
|
380
|
+
if (char === '[') {
|
|
381
|
+
stateStack.push(state);
|
|
382
|
+
state = 1 /* inBrackets */;
|
|
383
|
+
currentOpenBracketCount++;
|
|
384
|
+
}
|
|
385
|
+
else if (char === '(') {
|
|
386
|
+
stateStack.push(state);
|
|
387
|
+
state = 2 /* inParens */;
|
|
388
|
+
currentOpenParensCount++;
|
|
389
|
+
}
|
|
390
|
+
else if (!(i === 0 ? validFirstIdentCharRE : validIdentCharRE).test(char)) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
case 1 /* inBrackets */:
|
|
395
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
396
|
+
stateStack.push(state);
|
|
397
|
+
state = 3 /* inString */;
|
|
398
|
+
currentStringType = char;
|
|
399
|
+
}
|
|
400
|
+
else if (char === `[`) {
|
|
401
|
+
currentOpenBracketCount++;
|
|
402
|
+
}
|
|
403
|
+
else if (char === `]`) {
|
|
404
|
+
if (!--currentOpenBracketCount) {
|
|
405
|
+
state = stateStack.pop();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
break;
|
|
409
|
+
case 2 /* inParens */:
|
|
410
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
411
|
+
stateStack.push(state);
|
|
412
|
+
state = 3 /* inString */;
|
|
413
|
+
currentStringType = char;
|
|
414
|
+
}
|
|
415
|
+
else if (char === `(`) {
|
|
416
|
+
currentOpenParensCount++;
|
|
417
|
+
}
|
|
418
|
+
else if (char === `)`) {
|
|
419
|
+
// if the exp ends as a call then it should not be considered valid
|
|
420
|
+
if (i === path.length - 1) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (!--currentOpenParensCount) {
|
|
424
|
+
state = stateStack.pop();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
428
|
+
case 3 /* inString */:
|
|
429
|
+
if (char === currentStringType) {
|
|
430
|
+
state = stateStack.pop();
|
|
431
|
+
currentStringType = null;
|
|
432
|
+
}
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return !currentOpenBracketCount && !currentOpenParensCount;
|
|
371
437
|
};
|
|
372
438
|
function getInnerRange(loc, offset, length) {
|
|
373
439
|
const source = loc.source.substr(offset, length);
|
|
@@ -936,6 +1002,10 @@ function parseElement(context, ancestors) {
|
|
|
936
1002
|
const isPreBoundary = context.inPre && !wasInPre;
|
|
937
1003
|
const isVPreBoundary = context.inVPre && !wasInVPre;
|
|
938
1004
|
if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
|
|
1005
|
+
// #4030 self-closing <pre> tag
|
|
1006
|
+
if (context.options.isPreTag(element.tag)) {
|
|
1007
|
+
context.inPre = false;
|
|
1008
|
+
}
|
|
939
1009
|
return element;
|
|
940
1010
|
}
|
|
941
1011
|
// Children.
|
|
@@ -991,12 +1061,13 @@ function parseTag(context, type, parent) {
|
|
|
991
1061
|
// save current state in case we need to re-parse attributes with v-pre
|
|
992
1062
|
const cursor = getCursor(context);
|
|
993
1063
|
const currentSource = context.source;
|
|
994
|
-
// Attributes.
|
|
995
|
-
let props = parseAttributes(context, type);
|
|
996
1064
|
// check <pre> tag
|
|
997
|
-
|
|
1065
|
+
const isPreTag = context.options.isPreTag(tag);
|
|
1066
|
+
if (isPreTag) {
|
|
998
1067
|
context.inPre = true;
|
|
999
1068
|
}
|
|
1069
|
+
// Attributes.
|
|
1070
|
+
let props = parseAttributes(context, type);
|
|
1000
1071
|
// check v-pre
|
|
1001
1072
|
if (type === 0 /* Start */ &&
|
|
1002
1073
|
!context.inVPre &&
|
|
@@ -1043,41 +1114,17 @@ function parseTag(context, type, parent) {
|
|
|
1043
1114
|
}
|
|
1044
1115
|
}
|
|
1045
1116
|
let tagType = 0 /* ELEMENT */;
|
|
1046
|
-
|
|
1047
|
-
if (!context.inVPre && !options.isCustomElement(tag)) {
|
|
1048
|
-
const hasVIs = props.some(p => {
|
|
1049
|
-
if (p.name !== 'is')
|
|
1050
|
-
return;
|
|
1051
|
-
// v-is="xxx" (TODO: deprecate)
|
|
1052
|
-
if (p.type === 7 /* DIRECTIVE */) {
|
|
1053
|
-
return true;
|
|
1054
|
-
}
|
|
1055
|
-
// is="vue:xxx"
|
|
1056
|
-
if (p.value && p.value.content.startsWith('vue:')) {
|
|
1057
|
-
return true;
|
|
1058
|
-
}
|
|
1059
|
-
// in compat mode, any is usage is considered a component
|
|
1060
|
-
if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1061
|
-
return true;
|
|
1062
|
-
}
|
|
1063
|
-
});
|
|
1064
|
-
if (options.isNativeTag && !hasVIs) {
|
|
1065
|
-
if (!options.isNativeTag(tag))
|
|
1066
|
-
tagType = 1 /* COMPONENT */;
|
|
1067
|
-
}
|
|
1068
|
-
else if (hasVIs ||
|
|
1069
|
-
isCoreComponent(tag) ||
|
|
1070
|
-
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1071
|
-
/^[A-Z]/.test(tag) ||
|
|
1072
|
-
tag === 'component') {
|
|
1073
|
-
tagType = 1 /* COMPONENT */;
|
|
1074
|
-
}
|
|
1117
|
+
if (!context.inVPre) {
|
|
1075
1118
|
if (tag === 'slot') {
|
|
1076
1119
|
tagType = 2 /* SLOT */;
|
|
1077
1120
|
}
|
|
1078
|
-
else if (tag === 'template'
|
|
1079
|
-
props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1080
|
-
|
|
1121
|
+
else if (tag === 'template') {
|
|
1122
|
+
if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1123
|
+
tagType = 3 /* TEMPLATE */;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
else if (isComponent(tag, props, context)) {
|
|
1127
|
+
tagType = 1 /* COMPONENT */;
|
|
1081
1128
|
}
|
|
1082
1129
|
}
|
|
1083
1130
|
return {
|
|
@@ -1092,6 +1139,49 @@ function parseTag(context, type, parent) {
|
|
|
1092
1139
|
codegenNode: undefined // to be created during transform phase
|
|
1093
1140
|
};
|
|
1094
1141
|
}
|
|
1142
|
+
function isComponent(tag, props, context) {
|
|
1143
|
+
const options = context.options;
|
|
1144
|
+
if (options.isCustomElement(tag)) {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
if (tag === 'component' ||
|
|
1148
|
+
/^[A-Z]/.test(tag) ||
|
|
1149
|
+
isCoreComponent(tag) ||
|
|
1150
|
+
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1151
|
+
(options.isNativeTag && !options.isNativeTag(tag))) {
|
|
1152
|
+
return true;
|
|
1153
|
+
}
|
|
1154
|
+
// at this point the tag should be a native tag, but check for potential "is"
|
|
1155
|
+
// casting
|
|
1156
|
+
for (let i = 0; i < props.length; i++) {
|
|
1157
|
+
const p = props[i];
|
|
1158
|
+
if (p.type === 6 /* ATTRIBUTE */) {
|
|
1159
|
+
if (p.name === 'is' && p.value) {
|
|
1160
|
+
if (p.value.content.startsWith('vue:')) {
|
|
1161
|
+
return true;
|
|
1162
|
+
}
|
|
1163
|
+
else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1164
|
+
return true;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
else {
|
|
1169
|
+
// directive
|
|
1170
|
+
// v-is (TODO Deprecate)
|
|
1171
|
+
if (p.name === 'is') {
|
|
1172
|
+
return true;
|
|
1173
|
+
}
|
|
1174
|
+
else if (
|
|
1175
|
+
// :is on plain element - only treat as component in compat mode
|
|
1176
|
+
p.name === 'bind' &&
|
|
1177
|
+
isBindKey(p.arg, 'is') &&
|
|
1178
|
+
true &&
|
|
1179
|
+
checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1095
1185
|
function parseAttributes(context, type) {
|
|
1096
1186
|
const props = [];
|
|
1097
1187
|
const attributeNames = new Set();
|
|
@@ -1988,7 +2078,7 @@ function createStructuralDirectiveTransform(name, fn) {
|
|
|
1988
2078
|
|
|
1989
2079
|
const PURE_ANNOTATION = `/*#__PURE__*/`;
|
|
1990
2080
|
const WITH_ID = `_withId`;
|
|
1991
|
-
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap: sourceMap$1 = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false }) {
|
|
2081
|
+
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap: sourceMap$1 = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false, isTS = false }) {
|
|
1992
2082
|
const context = {
|
|
1993
2083
|
mode,
|
|
1994
2084
|
prefixIdentifiers,
|
|
@@ -1999,6 +2089,7 @@ function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode
|
|
|
1999
2089
|
runtimeGlobalName,
|
|
2000
2090
|
runtimeModuleName,
|
|
2001
2091
|
ssr,
|
|
2092
|
+
isTS,
|
|
2002
2093
|
source: ast.loc.source,
|
|
2003
2094
|
code: ``,
|
|
2004
2095
|
column: 1,
|
|
@@ -2278,7 +2369,7 @@ function genModulePreamble(ast, context, genScopeId, inline) {
|
|
|
2278
2369
|
push(`export `);
|
|
2279
2370
|
}
|
|
2280
2371
|
}
|
|
2281
|
-
function genAssets(assets, type, { helper, push, newline }) {
|
|
2372
|
+
function genAssets(assets, type, { helper, push, newline, isTS }) {
|
|
2282
2373
|
const resolver = helper(type === 'filter'
|
|
2283
2374
|
? RESOLVE_FILTER
|
|
2284
2375
|
: type === 'component'
|
|
@@ -2291,7 +2382,7 @@ function genAssets(assets, type, { helper, push, newline }) {
|
|
|
2291
2382
|
if (maybeSelfReference) {
|
|
2292
2383
|
id = id.slice(0, -6);
|
|
2293
2384
|
}
|
|
2294
|
-
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`);
|
|
2385
|
+
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);
|
|
2295
2386
|
if (i < assets.length - 1) {
|
|
2296
2387
|
newline();
|
|
2297
2388
|
}
|
|
@@ -3804,7 +3895,8 @@ function hasForwardedSlots(children) {
|
|
|
3804
3895
|
switch (child.type) {
|
|
3805
3896
|
case 1 /* ELEMENT */:
|
|
3806
3897
|
if (child.tagType === 2 /* SLOT */ ||
|
|
3807
|
-
(child.tagType === 0 /* ELEMENT */
|
|
3898
|
+
((child.tagType === 0 /* ELEMENT */ ||
|
|
3899
|
+
child.tagType === 3 /* TEMPLATE */) &&
|
|
3808
3900
|
hasForwardedSlots(child.children))) {
|
|
3809
3901
|
return true;
|
|
3810
3902
|
}
|
|
@@ -3968,16 +4060,10 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3968
4060
|
let { tag } = node;
|
|
3969
4061
|
// 1. dynamic component
|
|
3970
4062
|
const isExplicitDynamic = isComponentTag(tag);
|
|
3971
|
-
const isProp = findProp(node, 'is')
|
|
4063
|
+
const isProp = findProp(node, 'is');
|
|
3972
4064
|
if (isProp) {
|
|
3973
|
-
if (
|
|
3974
|
-
|
|
3975
|
-
// if not <component>, only is value that starts with "vue:" will be
|
|
3976
|
-
// treated as component by the parse phase and reach here, unless it's
|
|
3977
|
-
// compat mode where all is values are considered components
|
|
3978
|
-
tag = isProp.value.content.replace(/^vue:/, '');
|
|
3979
|
-
}
|
|
3980
|
-
else {
|
|
4065
|
+
if (isExplicitDynamic ||
|
|
4066
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {
|
|
3981
4067
|
const exp = isProp.type === 6 /* ATTRIBUTE */
|
|
3982
4068
|
? isProp.value && createSimpleExpression(isProp.value.content, true)
|
|
3983
4069
|
: isProp.exp;
|
|
@@ -3987,6 +4073,21 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3987
4073
|
]);
|
|
3988
4074
|
}
|
|
3989
4075
|
}
|
|
4076
|
+
else if (isProp.type === 6 /* ATTRIBUTE */ &&
|
|
4077
|
+
isProp.value.content.startsWith('vue:')) {
|
|
4078
|
+
// <button is="vue:xxx">
|
|
4079
|
+
// if not <component>, only is value that starts with "vue:" will be
|
|
4080
|
+
// treated as component by the parse phase and reach here, unless it's
|
|
4081
|
+
// compat mode where all is values are considered components
|
|
4082
|
+
tag = isProp.value.content.slice(4);
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
// 1.5 v-is (TODO: Deprecate)
|
|
4086
|
+
const isDir = !isExplicitDynamic && findDir(node, 'is');
|
|
4087
|
+
if (isDir && isDir.exp) {
|
|
4088
|
+
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
|
|
4089
|
+
isDir.exp
|
|
4090
|
+
]);
|
|
3990
4091
|
}
|
|
3991
4092
|
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
|
|
3992
4093
|
const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);
|
|
@@ -4130,7 +4231,9 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
4130
4231
|
}
|
|
4131
4232
|
// skip is on <component>, or is="vue:xxx"
|
|
4132
4233
|
if (name === 'is' &&
|
|
4133
|
-
(isComponentTag(tag) ||
|
|
4234
|
+
(isComponentTag(tag) ||
|
|
4235
|
+
(value && value.content.startsWith('vue:')) ||
|
|
4236
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {
|
|
4134
4237
|
continue;
|
|
4135
4238
|
}
|
|
4136
4239
|
properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));
|
|
@@ -4153,7 +4256,10 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
4153
4256
|
}
|
|
4154
4257
|
// skip v-is and :is on <component>
|
|
4155
4258
|
if (name === 'is' ||
|
|
4156
|
-
(isVBind &&
|
|
4259
|
+
(isVBind &&
|
|
4260
|
+
isBindKey(arg, 'is') &&
|
|
4261
|
+
(isComponentTag(tag) ||
|
|
4262
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {
|
|
4157
4263
|
continue;
|
|
4158
4264
|
}
|
|
4159
4265
|
// skip v-on in SSR compilation
|
|
@@ -4337,7 +4443,7 @@ function buildDirectiveArgs(dir, context) {
|
|
|
4337
4443
|
else {
|
|
4338
4444
|
// user directive.
|
|
4339
4445
|
// see if we have directives exposed via <script setup>
|
|
4340
|
-
const fromSetup = resolveSetupReference(dir.name, context);
|
|
4446
|
+
const fromSetup = resolveSetupReference('v-' + dir.name, context);
|
|
4341
4447
|
if (fromSetup) {
|
|
4342
4448
|
dirArgs.push(fromSetup);
|
|
4343
4449
|
}
|
|
@@ -4737,7 +4843,7 @@ const transformModel = (dir, node, context) => {
|
|
|
4737
4843
|
const maybeRef = context.inline &&
|
|
4738
4844
|
bindingType &&
|
|
4739
4845
|
bindingType !== "setup-const" /* SETUP_CONST */;
|
|
4740
|
-
if (!isMemberExpression(expString) && !maybeRef) {
|
|
4846
|
+
if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {
|
|
4741
4847
|
context.onError(createCompilerError(41 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));
|
|
4742
4848
|
return createTransformProps();
|
|
4743
4849
|
}
|
|
@@ -355,18 +355,84 @@ function isCoreComponent(tag) {
|
|
|
355
355
|
}
|
|
356
356
|
const nonIdentifierRE = /^\d|[^\$\w]/;
|
|
357
357
|
const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);
|
|
358
|
-
const
|
|
358
|
+
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/;
|
|
359
|
+
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/;
|
|
360
|
+
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g;
|
|
361
|
+
/**
|
|
362
|
+
* Simple lexer to check if an expression is a member expression. This is
|
|
363
|
+
* lax and only checks validity at the root level (i.e. does not validate exps
|
|
364
|
+
* inside square brackets), but it's ok since these are only used on template
|
|
365
|
+
* expressions and false positives are invalid expressions in the first place.
|
|
366
|
+
*/
|
|
359
367
|
const isMemberExpression = (path) => {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
368
|
+
// remove whitespaces around . or [ first
|
|
369
|
+
path = path.trim().replace(whitespaceRE, s => s.trim());
|
|
370
|
+
let state = 0 /* inMemberExp */;
|
|
371
|
+
let stateStack = [];
|
|
372
|
+
let currentOpenBracketCount = 0;
|
|
373
|
+
let currentOpenParensCount = 0;
|
|
374
|
+
let currentStringType = null;
|
|
375
|
+
for (let i = 0; i < path.length; i++) {
|
|
376
|
+
const char = path.charAt(i);
|
|
377
|
+
switch (state) {
|
|
378
|
+
case 0 /* inMemberExp */:
|
|
379
|
+
if (char === '[') {
|
|
380
|
+
stateStack.push(state);
|
|
381
|
+
state = 1 /* inBrackets */;
|
|
382
|
+
currentOpenBracketCount++;
|
|
383
|
+
}
|
|
384
|
+
else if (char === '(') {
|
|
385
|
+
stateStack.push(state);
|
|
386
|
+
state = 2 /* inParens */;
|
|
387
|
+
currentOpenParensCount++;
|
|
388
|
+
}
|
|
389
|
+
else if (!(i === 0 ? validFirstIdentCharRE : validIdentCharRE).test(char)) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
break;
|
|
393
|
+
case 1 /* inBrackets */:
|
|
394
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
395
|
+
stateStack.push(state);
|
|
396
|
+
state = 3 /* inString */;
|
|
397
|
+
currentStringType = char;
|
|
398
|
+
}
|
|
399
|
+
else if (char === `[`) {
|
|
400
|
+
currentOpenBracketCount++;
|
|
401
|
+
}
|
|
402
|
+
else if (char === `]`) {
|
|
403
|
+
if (!--currentOpenBracketCount) {
|
|
404
|
+
state = stateStack.pop();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
408
|
+
case 2 /* inParens */:
|
|
409
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
410
|
+
stateStack.push(state);
|
|
411
|
+
state = 3 /* inString */;
|
|
412
|
+
currentStringType = char;
|
|
413
|
+
}
|
|
414
|
+
else if (char === `(`) {
|
|
415
|
+
currentOpenParensCount++;
|
|
416
|
+
}
|
|
417
|
+
else if (char === `)`) {
|
|
418
|
+
// if the exp ends as a call then it should not be considered valid
|
|
419
|
+
if (i === path.length - 1) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (!--currentOpenParensCount) {
|
|
423
|
+
state = stateStack.pop();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
break;
|
|
427
|
+
case 3 /* inString */:
|
|
428
|
+
if (char === currentStringType) {
|
|
429
|
+
state = stateStack.pop();
|
|
430
|
+
currentStringType = null;
|
|
431
|
+
}
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return !currentOpenBracketCount && !currentOpenParensCount;
|
|
370
436
|
};
|
|
371
437
|
function getInnerRange(loc, offset, length) {
|
|
372
438
|
const source = loc.source.substr(offset, length);
|
|
@@ -937,6 +1003,10 @@ function parseElement(context, ancestors) {
|
|
|
937
1003
|
const isPreBoundary = context.inPre && !wasInPre;
|
|
938
1004
|
const isVPreBoundary = context.inVPre && !wasInVPre;
|
|
939
1005
|
if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
|
|
1006
|
+
// #4030 self-closing <pre> tag
|
|
1007
|
+
if (context.options.isPreTag(element.tag)) {
|
|
1008
|
+
context.inPre = false;
|
|
1009
|
+
}
|
|
940
1010
|
return element;
|
|
941
1011
|
}
|
|
942
1012
|
// Children.
|
|
@@ -992,12 +1062,13 @@ function parseTag(context, type, parent) {
|
|
|
992
1062
|
// save current state in case we need to re-parse attributes with v-pre
|
|
993
1063
|
const cursor = getCursor(context);
|
|
994
1064
|
const currentSource = context.source;
|
|
995
|
-
// Attributes.
|
|
996
|
-
let props = parseAttributes(context, type);
|
|
997
1065
|
// check <pre> tag
|
|
998
|
-
|
|
1066
|
+
const isPreTag = context.options.isPreTag(tag);
|
|
1067
|
+
if (isPreTag) {
|
|
999
1068
|
context.inPre = true;
|
|
1000
1069
|
}
|
|
1070
|
+
// Attributes.
|
|
1071
|
+
let props = parseAttributes(context, type);
|
|
1001
1072
|
// check v-pre
|
|
1002
1073
|
if (type === 0 /* Start */ &&
|
|
1003
1074
|
!context.inVPre &&
|
|
@@ -1025,41 +1096,17 @@ function parseTag(context, type, parent) {
|
|
|
1025
1096
|
return;
|
|
1026
1097
|
}
|
|
1027
1098
|
let tagType = 0 /* ELEMENT */;
|
|
1028
|
-
|
|
1029
|
-
if (!context.inVPre && !options.isCustomElement(tag)) {
|
|
1030
|
-
const hasVIs = props.some(p => {
|
|
1031
|
-
if (p.name !== 'is')
|
|
1032
|
-
return;
|
|
1033
|
-
// v-is="xxx" (TODO: deprecate)
|
|
1034
|
-
if (p.type === 7 /* DIRECTIVE */) {
|
|
1035
|
-
return true;
|
|
1036
|
-
}
|
|
1037
|
-
// is="vue:xxx"
|
|
1038
|
-
if (p.value && p.value.content.startsWith('vue:')) {
|
|
1039
|
-
return true;
|
|
1040
|
-
}
|
|
1041
|
-
// in compat mode, any is usage is considered a component
|
|
1042
|
-
if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1043
|
-
return true;
|
|
1044
|
-
}
|
|
1045
|
-
});
|
|
1046
|
-
if (options.isNativeTag && !hasVIs) {
|
|
1047
|
-
if (!options.isNativeTag(tag))
|
|
1048
|
-
tagType = 1 /* COMPONENT */;
|
|
1049
|
-
}
|
|
1050
|
-
else if (hasVIs ||
|
|
1051
|
-
isCoreComponent(tag) ||
|
|
1052
|
-
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1053
|
-
/^[A-Z]/.test(tag) ||
|
|
1054
|
-
tag === 'component') {
|
|
1055
|
-
tagType = 1 /* COMPONENT */;
|
|
1056
|
-
}
|
|
1099
|
+
if (!context.inVPre) {
|
|
1057
1100
|
if (tag === 'slot') {
|
|
1058
1101
|
tagType = 2 /* SLOT */;
|
|
1059
1102
|
}
|
|
1060
|
-
else if (tag === 'template'
|
|
1061
|
-
props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1062
|
-
|
|
1103
|
+
else if (tag === 'template') {
|
|
1104
|
+
if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1105
|
+
tagType = 3 /* TEMPLATE */;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
else if (isComponent(tag, props, context)) {
|
|
1109
|
+
tagType = 1 /* COMPONENT */;
|
|
1063
1110
|
}
|
|
1064
1111
|
}
|
|
1065
1112
|
return {
|
|
@@ -1074,6 +1121,49 @@ function parseTag(context, type, parent) {
|
|
|
1074
1121
|
codegenNode: undefined // to be created during transform phase
|
|
1075
1122
|
};
|
|
1076
1123
|
}
|
|
1124
|
+
function isComponent(tag, props, context) {
|
|
1125
|
+
const options = context.options;
|
|
1126
|
+
if (options.isCustomElement(tag)) {
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
if (tag === 'component' ||
|
|
1130
|
+
/^[A-Z]/.test(tag) ||
|
|
1131
|
+
isCoreComponent(tag) ||
|
|
1132
|
+
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1133
|
+
(options.isNativeTag && !options.isNativeTag(tag))) {
|
|
1134
|
+
return true;
|
|
1135
|
+
}
|
|
1136
|
+
// at this point the tag should be a native tag, but check for potential "is"
|
|
1137
|
+
// casting
|
|
1138
|
+
for (let i = 0; i < props.length; i++) {
|
|
1139
|
+
const p = props[i];
|
|
1140
|
+
if (p.type === 6 /* ATTRIBUTE */) {
|
|
1141
|
+
if (p.name === 'is' && p.value) {
|
|
1142
|
+
if (p.value.content.startsWith('vue:')) {
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1146
|
+
return true;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
// directive
|
|
1152
|
+
// v-is (TODO Deprecate)
|
|
1153
|
+
if (p.name === 'is') {
|
|
1154
|
+
return true;
|
|
1155
|
+
}
|
|
1156
|
+
else if (
|
|
1157
|
+
// :is on plain element - only treat as component in compat mode
|
|
1158
|
+
p.name === 'bind' &&
|
|
1159
|
+
isBindKey(p.arg, 'is') &&
|
|
1160
|
+
true &&
|
|
1161
|
+
checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1162
|
+
return true;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1077
1167
|
function parseAttributes(context, type) {
|
|
1078
1168
|
const props = [];
|
|
1079
1169
|
const attributeNames = new Set();
|
|
@@ -1945,7 +2035,7 @@ function createStructuralDirectiveTransform(name, fn) {
|
|
|
1945
2035
|
|
|
1946
2036
|
const PURE_ANNOTATION = `/*#__PURE__*/`;
|
|
1947
2037
|
const WITH_ID = `_withId`;
|
|
1948
|
-
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap: sourceMap$1 = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false }) {
|
|
2038
|
+
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap: sourceMap$1 = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false, isTS = false }) {
|
|
1949
2039
|
const context = {
|
|
1950
2040
|
mode,
|
|
1951
2041
|
prefixIdentifiers,
|
|
@@ -1956,6 +2046,7 @@ function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode
|
|
|
1956
2046
|
runtimeGlobalName,
|
|
1957
2047
|
runtimeModuleName,
|
|
1958
2048
|
ssr,
|
|
2049
|
+
isTS,
|
|
1959
2050
|
source: ast.loc.source,
|
|
1960
2051
|
code: ``,
|
|
1961
2052
|
column: 1,
|
|
@@ -2235,7 +2326,7 @@ function genModulePreamble(ast, context, genScopeId, inline) {
|
|
|
2235
2326
|
push(`export `);
|
|
2236
2327
|
}
|
|
2237
2328
|
}
|
|
2238
|
-
function genAssets(assets, type, { helper, push, newline }) {
|
|
2329
|
+
function genAssets(assets, type, { helper, push, newline, isTS }) {
|
|
2239
2330
|
const resolver = helper(type === 'filter'
|
|
2240
2331
|
? RESOLVE_FILTER
|
|
2241
2332
|
: type === 'component'
|
|
@@ -2248,7 +2339,7 @@ function genAssets(assets, type, { helper, push, newline }) {
|
|
|
2248
2339
|
if (maybeSelfReference) {
|
|
2249
2340
|
id = id.slice(0, -6);
|
|
2250
2341
|
}
|
|
2251
|
-
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`);
|
|
2342
|
+
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);
|
|
2252
2343
|
if (i < assets.length - 1) {
|
|
2253
2344
|
newline();
|
|
2254
2345
|
}
|
|
@@ -3728,7 +3819,8 @@ function hasForwardedSlots(children) {
|
|
|
3728
3819
|
switch (child.type) {
|
|
3729
3820
|
case 1 /* ELEMENT */:
|
|
3730
3821
|
if (child.tagType === 2 /* SLOT */ ||
|
|
3731
|
-
(child.tagType === 0 /* ELEMENT */
|
|
3822
|
+
((child.tagType === 0 /* ELEMENT */ ||
|
|
3823
|
+
child.tagType === 3 /* TEMPLATE */) &&
|
|
3732
3824
|
hasForwardedSlots(child.children))) {
|
|
3733
3825
|
return true;
|
|
3734
3826
|
}
|
|
@@ -3873,16 +3965,10 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3873
3965
|
let { tag } = node;
|
|
3874
3966
|
// 1. dynamic component
|
|
3875
3967
|
const isExplicitDynamic = isComponentTag(tag);
|
|
3876
|
-
const isProp = findProp(node, 'is')
|
|
3968
|
+
const isProp = findProp(node, 'is');
|
|
3877
3969
|
if (isProp) {
|
|
3878
|
-
if (
|
|
3879
|
-
|
|
3880
|
-
// if not <component>, only is value that starts with "vue:" will be
|
|
3881
|
-
// treated as component by the parse phase and reach here, unless it's
|
|
3882
|
-
// compat mode where all is values are considered components
|
|
3883
|
-
tag = isProp.value.content.replace(/^vue:/, '');
|
|
3884
|
-
}
|
|
3885
|
-
else {
|
|
3970
|
+
if (isExplicitDynamic ||
|
|
3971
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {
|
|
3886
3972
|
const exp = isProp.type === 6 /* ATTRIBUTE */
|
|
3887
3973
|
? isProp.value && createSimpleExpression(isProp.value.content, true)
|
|
3888
3974
|
: isProp.exp;
|
|
@@ -3892,6 +3978,21 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3892
3978
|
]);
|
|
3893
3979
|
}
|
|
3894
3980
|
}
|
|
3981
|
+
else if (isProp.type === 6 /* ATTRIBUTE */ &&
|
|
3982
|
+
isProp.value.content.startsWith('vue:')) {
|
|
3983
|
+
// <button is="vue:xxx">
|
|
3984
|
+
// if not <component>, only is value that starts with "vue:" will be
|
|
3985
|
+
// treated as component by the parse phase and reach here, unless it's
|
|
3986
|
+
// compat mode where all is values are considered components
|
|
3987
|
+
tag = isProp.value.content.slice(4);
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
// 1.5 v-is (TODO: Deprecate)
|
|
3991
|
+
const isDir = !isExplicitDynamic && findDir(node, 'is');
|
|
3992
|
+
if (isDir && isDir.exp) {
|
|
3993
|
+
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
|
|
3994
|
+
isDir.exp
|
|
3995
|
+
]);
|
|
3895
3996
|
}
|
|
3896
3997
|
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
|
|
3897
3998
|
const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);
|
|
@@ -4035,7 +4136,9 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
4035
4136
|
}
|
|
4036
4137
|
// skip is on <component>, or is="vue:xxx"
|
|
4037
4138
|
if (name === 'is' &&
|
|
4038
|
-
(isComponentTag(tag) ||
|
|
4139
|
+
(isComponentTag(tag) ||
|
|
4140
|
+
(value && value.content.startsWith('vue:')) ||
|
|
4141
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {
|
|
4039
4142
|
continue;
|
|
4040
4143
|
}
|
|
4041
4144
|
properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));
|
|
@@ -4058,7 +4161,10 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
4058
4161
|
}
|
|
4059
4162
|
// skip v-is and :is on <component>
|
|
4060
4163
|
if (name === 'is' ||
|
|
4061
|
-
(isVBind &&
|
|
4164
|
+
(isVBind &&
|
|
4165
|
+
isBindKey(arg, 'is') &&
|
|
4166
|
+
(isComponentTag(tag) ||
|
|
4167
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {
|
|
4062
4168
|
continue;
|
|
4063
4169
|
}
|
|
4064
4170
|
// skip v-on in SSR compilation
|
|
@@ -4219,7 +4325,7 @@ function buildDirectiveArgs(dir, context) {
|
|
|
4219
4325
|
else {
|
|
4220
4326
|
// user directive.
|
|
4221
4327
|
// see if we have directives exposed via <script setup>
|
|
4222
|
-
const fromSetup = resolveSetupReference(dir.name, context);
|
|
4328
|
+
const fromSetup = resolveSetupReference('v-' + dir.name, context);
|
|
4223
4329
|
if (fromSetup) {
|
|
4224
4330
|
dirArgs.push(fromSetup);
|
|
4225
4331
|
}
|
|
@@ -4616,7 +4722,7 @@ const transformModel = (dir, node, context) => {
|
|
|
4616
4722
|
const maybeRef = context.inline &&
|
|
4617
4723
|
bindingType &&
|
|
4618
4724
|
bindingType !== "setup-const" /* SETUP_CONST */;
|
|
4619
|
-
if (!isMemberExpression(expString) && !maybeRef) {
|
|
4725
|
+
if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {
|
|
4620
4726
|
context.onError(createCompilerError(41 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));
|
|
4621
4727
|
return createTransformProps();
|
|
4622
4728
|
}
|
package/dist/compiler-core.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ export declare const CAPITALIZE: unique symbol;
|
|
|
119
119
|
|
|
120
120
|
export declare function checkCompatEnabled(key: CompilerDeprecationTypes, context: ParserContext | TransformContext, loc: SourceLocation | null, ...args: any[]): boolean;
|
|
121
121
|
|
|
122
|
-
export declare interface CodegenContext extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'
|
|
122
|
+
export declare interface CodegenContext extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
|
|
123
123
|
source: string;
|
|
124
124
|
code: string;
|
|
125
125
|
line: number;
|
|
@@ -557,6 +557,12 @@ export declare const isBuiltInType: (tag: string, expected: string) => boolean;
|
|
|
557
557
|
|
|
558
558
|
export declare function isCoreComponent(tag: string): symbol | void;
|
|
559
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Simple lexer to check if an expression is a member expression. This is
|
|
562
|
+
* lax and only checks validity at the root level (i.e. does not validate exps
|
|
563
|
+
* inside square brackets), but it's ok since these are only used on template
|
|
564
|
+
* expressions and false positives are invalid expressions in the first place.
|
|
565
|
+
*/
|
|
560
566
|
export declare const isMemberExpression: (path: string) => boolean;
|
|
561
567
|
|
|
562
568
|
export declare const isSimpleIdentifier: (name: string) => boolean;
|
|
@@ -351,18 +351,84 @@ function isCoreComponent(tag) {
|
|
|
351
351
|
}
|
|
352
352
|
const nonIdentifierRE = /^\d|[^\$\w]/;
|
|
353
353
|
const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);
|
|
354
|
-
const
|
|
354
|
+
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/;
|
|
355
|
+
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/;
|
|
356
|
+
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g;
|
|
357
|
+
/**
|
|
358
|
+
* Simple lexer to check if an expression is a member expression. This is
|
|
359
|
+
* lax and only checks validity at the root level (i.e. does not validate exps
|
|
360
|
+
* inside square brackets), but it's ok since these are only used on template
|
|
361
|
+
* expressions and false positives are invalid expressions in the first place.
|
|
362
|
+
*/
|
|
355
363
|
const isMemberExpression = (path) => {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
364
|
+
// remove whitespaces around . or [ first
|
|
365
|
+
path = path.trim().replace(whitespaceRE, s => s.trim());
|
|
366
|
+
let state = 0 /* inMemberExp */;
|
|
367
|
+
let stateStack = [];
|
|
368
|
+
let currentOpenBracketCount = 0;
|
|
369
|
+
let currentOpenParensCount = 0;
|
|
370
|
+
let currentStringType = null;
|
|
371
|
+
for (let i = 0; i < path.length; i++) {
|
|
372
|
+
const char = path.charAt(i);
|
|
373
|
+
switch (state) {
|
|
374
|
+
case 0 /* inMemberExp */:
|
|
375
|
+
if (char === '[') {
|
|
376
|
+
stateStack.push(state);
|
|
377
|
+
state = 1 /* inBrackets */;
|
|
378
|
+
currentOpenBracketCount++;
|
|
379
|
+
}
|
|
380
|
+
else if (char === '(') {
|
|
381
|
+
stateStack.push(state);
|
|
382
|
+
state = 2 /* inParens */;
|
|
383
|
+
currentOpenParensCount++;
|
|
384
|
+
}
|
|
385
|
+
else if (!(i === 0 ? validFirstIdentCharRE : validIdentCharRE).test(char)) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
case 1 /* inBrackets */:
|
|
390
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
391
|
+
stateStack.push(state);
|
|
392
|
+
state = 3 /* inString */;
|
|
393
|
+
currentStringType = char;
|
|
394
|
+
}
|
|
395
|
+
else if (char === `[`) {
|
|
396
|
+
currentOpenBracketCount++;
|
|
397
|
+
}
|
|
398
|
+
else if (char === `]`) {
|
|
399
|
+
if (!--currentOpenBracketCount) {
|
|
400
|
+
state = stateStack.pop();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
break;
|
|
404
|
+
case 2 /* inParens */:
|
|
405
|
+
if (char === `'` || char === `"` || char === '`') {
|
|
406
|
+
stateStack.push(state);
|
|
407
|
+
state = 3 /* inString */;
|
|
408
|
+
currentStringType = char;
|
|
409
|
+
}
|
|
410
|
+
else if (char === `(`) {
|
|
411
|
+
currentOpenParensCount++;
|
|
412
|
+
}
|
|
413
|
+
else if (char === `)`) {
|
|
414
|
+
// if the exp ends as a call then it should not be considered valid
|
|
415
|
+
if (i === path.length - 1) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
if (!--currentOpenParensCount) {
|
|
419
|
+
state = stateStack.pop();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
case 3 /* inString */:
|
|
424
|
+
if (char === currentStringType) {
|
|
425
|
+
state = stateStack.pop();
|
|
426
|
+
currentStringType = null;
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return !currentOpenBracketCount && !currentOpenParensCount;
|
|
366
432
|
};
|
|
367
433
|
function getInnerRange(loc, offset, length) {
|
|
368
434
|
const source = loc.source.substr(offset, length);
|
|
@@ -940,6 +1006,10 @@ function parseElement(context, ancestors) {
|
|
|
940
1006
|
const isPreBoundary = context.inPre && !wasInPre;
|
|
941
1007
|
const isVPreBoundary = context.inVPre && !wasInVPre;
|
|
942
1008
|
if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
|
|
1009
|
+
// #4030 self-closing <pre> tag
|
|
1010
|
+
if (context.options.isPreTag(element.tag)) {
|
|
1011
|
+
context.inPre = false;
|
|
1012
|
+
}
|
|
943
1013
|
return element;
|
|
944
1014
|
}
|
|
945
1015
|
// Children.
|
|
@@ -995,12 +1065,13 @@ function parseTag(context, type, parent) {
|
|
|
995
1065
|
// save current state in case we need to re-parse attributes with v-pre
|
|
996
1066
|
const cursor = getCursor(context);
|
|
997
1067
|
const currentSource = context.source;
|
|
998
|
-
// Attributes.
|
|
999
|
-
let props = parseAttributes(context, type);
|
|
1000
1068
|
// check <pre> tag
|
|
1001
|
-
|
|
1069
|
+
const isPreTag = context.options.isPreTag(tag);
|
|
1070
|
+
if (isPreTag) {
|
|
1002
1071
|
context.inPre = true;
|
|
1003
1072
|
}
|
|
1073
|
+
// Attributes.
|
|
1074
|
+
let props = parseAttributes(context, type);
|
|
1004
1075
|
// check v-pre
|
|
1005
1076
|
if (type === 0 /* Start */ &&
|
|
1006
1077
|
!context.inVPre &&
|
|
@@ -1048,41 +1119,17 @@ function parseTag(context, type, parent) {
|
|
|
1048
1119
|
}
|
|
1049
1120
|
}
|
|
1050
1121
|
let tagType = 0 /* ELEMENT */;
|
|
1051
|
-
|
|
1052
|
-
if (!context.inVPre && !options.isCustomElement(tag)) {
|
|
1053
|
-
const hasVIs = props.some(p => {
|
|
1054
|
-
if (p.name !== 'is')
|
|
1055
|
-
return;
|
|
1056
|
-
// v-is="xxx" (TODO: deprecate)
|
|
1057
|
-
if (p.type === 7 /* DIRECTIVE */) {
|
|
1058
|
-
return true;
|
|
1059
|
-
}
|
|
1060
|
-
// is="vue:xxx"
|
|
1061
|
-
if (p.value && p.value.content.startsWith('vue:')) {
|
|
1062
|
-
return true;
|
|
1063
|
-
}
|
|
1064
|
-
// in compat mode, any is usage is considered a component
|
|
1065
|
-
if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1066
|
-
return true;
|
|
1067
|
-
}
|
|
1068
|
-
});
|
|
1069
|
-
if (options.isNativeTag && !hasVIs) {
|
|
1070
|
-
if (!options.isNativeTag(tag))
|
|
1071
|
-
tagType = 1 /* COMPONENT */;
|
|
1072
|
-
}
|
|
1073
|
-
else if (hasVIs ||
|
|
1074
|
-
isCoreComponent(tag) ||
|
|
1075
|
-
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1076
|
-
/^[A-Z]/.test(tag) ||
|
|
1077
|
-
tag === 'component') {
|
|
1078
|
-
tagType = 1 /* COMPONENT */;
|
|
1079
|
-
}
|
|
1122
|
+
if (!context.inVPre) {
|
|
1080
1123
|
if (tag === 'slot') {
|
|
1081
1124
|
tagType = 2 /* SLOT */;
|
|
1082
1125
|
}
|
|
1083
|
-
else if (tag === 'template'
|
|
1084
|
-
props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1085
|
-
|
|
1126
|
+
else if (tag === 'template') {
|
|
1127
|
+
if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
|
|
1128
|
+
tagType = 3 /* TEMPLATE */;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
else if (isComponent(tag, props, context)) {
|
|
1132
|
+
tagType = 1 /* COMPONENT */;
|
|
1086
1133
|
}
|
|
1087
1134
|
}
|
|
1088
1135
|
return {
|
|
@@ -1097,6 +1144,49 @@ function parseTag(context, type, parent) {
|
|
|
1097
1144
|
codegenNode: undefined // to be created during transform phase
|
|
1098
1145
|
};
|
|
1099
1146
|
}
|
|
1147
|
+
function isComponent(tag, props, context) {
|
|
1148
|
+
const options = context.options;
|
|
1149
|
+
if (options.isCustomElement(tag)) {
|
|
1150
|
+
return false;
|
|
1151
|
+
}
|
|
1152
|
+
if (tag === 'component' ||
|
|
1153
|
+
/^[A-Z]/.test(tag) ||
|
|
1154
|
+
isCoreComponent(tag) ||
|
|
1155
|
+
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
|
1156
|
+
(options.isNativeTag && !options.isNativeTag(tag))) {
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
// at this point the tag should be a native tag, but check for potential "is"
|
|
1160
|
+
// casting
|
|
1161
|
+
for (let i = 0; i < props.length; i++) {
|
|
1162
|
+
const p = props[i];
|
|
1163
|
+
if (p.type === 6 /* ATTRIBUTE */) {
|
|
1164
|
+
if (p.name === 'is' && p.value) {
|
|
1165
|
+
if (p.value.content.startsWith('vue:')) {
|
|
1166
|
+
return true;
|
|
1167
|
+
}
|
|
1168
|
+
else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
// directive
|
|
1175
|
+
// v-is (TODO Deprecate)
|
|
1176
|
+
if (p.name === 'is') {
|
|
1177
|
+
return true;
|
|
1178
|
+
}
|
|
1179
|
+
else if (
|
|
1180
|
+
// :is on plain element - only treat as component in compat mode
|
|
1181
|
+
p.name === 'bind' &&
|
|
1182
|
+
isBindKey(p.arg, 'is') &&
|
|
1183
|
+
true &&
|
|
1184
|
+
checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1100
1190
|
function parseAttributes(context, type) {
|
|
1101
1191
|
const props = [];
|
|
1102
1192
|
const attributeNames = new Set();
|
|
@@ -1961,7 +2051,7 @@ function createStructuralDirectiveTransform(name, fn) {
|
|
|
1961
2051
|
}
|
|
1962
2052
|
|
|
1963
2053
|
const PURE_ANNOTATION = `/*#__PURE__*/`;
|
|
1964
|
-
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false }) {
|
|
2054
|
+
function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false, isTS = false }) {
|
|
1965
2055
|
const context = {
|
|
1966
2056
|
mode,
|
|
1967
2057
|
prefixIdentifiers,
|
|
@@ -1972,6 +2062,7 @@ function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode
|
|
|
1972
2062
|
runtimeGlobalName,
|
|
1973
2063
|
runtimeModuleName,
|
|
1974
2064
|
ssr,
|
|
2065
|
+
isTS,
|
|
1975
2066
|
source: ast.loc.source,
|
|
1976
2067
|
code: ``,
|
|
1977
2068
|
column: 1,
|
|
@@ -2127,7 +2218,7 @@ function genFunctionPreamble(ast, context) {
|
|
|
2127
2218
|
newline();
|
|
2128
2219
|
push(`return `);
|
|
2129
2220
|
}
|
|
2130
|
-
function genAssets(assets, type, { helper, push, newline }) {
|
|
2221
|
+
function genAssets(assets, type, { helper, push, newline, isTS }) {
|
|
2131
2222
|
const resolver = helper(type === 'filter'
|
|
2132
2223
|
? RESOLVE_FILTER
|
|
2133
2224
|
: type === 'component'
|
|
@@ -2140,7 +2231,7 @@ function genAssets(assets, type, { helper, push, newline }) {
|
|
|
2140
2231
|
if (maybeSelfReference) {
|
|
2141
2232
|
id = id.slice(0, -6);
|
|
2142
2233
|
}
|
|
2143
|
-
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`);
|
|
2234
|
+
push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);
|
|
2144
2235
|
if (i < assets.length - 1) {
|
|
2145
2236
|
newline();
|
|
2146
2237
|
}
|
|
@@ -3253,7 +3344,8 @@ function hasForwardedSlots(children) {
|
|
|
3253
3344
|
switch (child.type) {
|
|
3254
3345
|
case 1 /* ELEMENT */:
|
|
3255
3346
|
if (child.tagType === 2 /* SLOT */ ||
|
|
3256
|
-
(child.tagType === 0 /* ELEMENT */
|
|
3347
|
+
((child.tagType === 0 /* ELEMENT */ ||
|
|
3348
|
+
child.tagType === 3 /* TEMPLATE */) &&
|
|
3257
3349
|
hasForwardedSlots(child.children))) {
|
|
3258
3350
|
return true;
|
|
3259
3351
|
}
|
|
@@ -3420,16 +3512,10 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3420
3512
|
let { tag } = node;
|
|
3421
3513
|
// 1. dynamic component
|
|
3422
3514
|
const isExplicitDynamic = isComponentTag(tag);
|
|
3423
|
-
const isProp = findProp(node, 'is')
|
|
3515
|
+
const isProp = findProp(node, 'is');
|
|
3424
3516
|
if (isProp) {
|
|
3425
|
-
if (
|
|
3426
|
-
|
|
3427
|
-
// if not <component>, only is value that starts with "vue:" will be
|
|
3428
|
-
// treated as component by the parse phase and reach here, unless it's
|
|
3429
|
-
// compat mode where all is values are considered components
|
|
3430
|
-
tag = isProp.value.content.replace(/^vue:/, '');
|
|
3431
|
-
}
|
|
3432
|
-
else {
|
|
3517
|
+
if (isExplicitDynamic ||
|
|
3518
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {
|
|
3433
3519
|
const exp = isProp.type === 6 /* ATTRIBUTE */
|
|
3434
3520
|
? isProp.value && createSimpleExpression(isProp.value.content, true)
|
|
3435
3521
|
: isProp.exp;
|
|
@@ -3439,6 +3525,21 @@ function resolveComponentType(node, context, ssr = false) {
|
|
|
3439
3525
|
]);
|
|
3440
3526
|
}
|
|
3441
3527
|
}
|
|
3528
|
+
else if (isProp.type === 6 /* ATTRIBUTE */ &&
|
|
3529
|
+
isProp.value.content.startsWith('vue:')) {
|
|
3530
|
+
// <button is="vue:xxx">
|
|
3531
|
+
// if not <component>, only is value that starts with "vue:" will be
|
|
3532
|
+
// treated as component by the parse phase and reach here, unless it's
|
|
3533
|
+
// compat mode where all is values are considered components
|
|
3534
|
+
tag = isProp.value.content.slice(4);
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
// 1.5 v-is (TODO: Deprecate)
|
|
3538
|
+
const isDir = !isExplicitDynamic && findDir(node, 'is');
|
|
3539
|
+
if (isDir && isDir.exp) {
|
|
3540
|
+
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
|
|
3541
|
+
isDir.exp
|
|
3542
|
+
]);
|
|
3442
3543
|
}
|
|
3443
3544
|
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
|
|
3444
3545
|
const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);
|
|
@@ -3522,7 +3623,9 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
3522
3623
|
}
|
|
3523
3624
|
// skip is on <component>, or is="vue:xxx"
|
|
3524
3625
|
if (name === 'is' &&
|
|
3525
|
-
(isComponentTag(tag) ||
|
|
3626
|
+
(isComponentTag(tag) ||
|
|
3627
|
+
(value && value.content.startsWith('vue:')) ||
|
|
3628
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {
|
|
3526
3629
|
continue;
|
|
3527
3630
|
}
|
|
3528
3631
|
properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));
|
|
@@ -3545,7 +3648,10 @@ function buildProps(node, context, props = node.props, ssr = false) {
|
|
|
3545
3648
|
}
|
|
3546
3649
|
// skip v-is and :is on <component>
|
|
3547
3650
|
if (name === 'is' ||
|
|
3548
|
-
(isVBind &&
|
|
3651
|
+
(isVBind &&
|
|
3652
|
+
isBindKey(arg, 'is') &&
|
|
3653
|
+
(isComponentTag(tag) ||
|
|
3654
|
+
(isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {
|
|
3549
3655
|
continue;
|
|
3550
3656
|
}
|
|
3551
3657
|
// skip v-on in SSR compilation
|
|
@@ -4089,7 +4195,7 @@ const transformModel = (dir, node, context) => {
|
|
|
4089
4195
|
// _unref(exp)
|
|
4090
4196
|
context.bindingMetadata[rawExp];
|
|
4091
4197
|
const maybeRef = !true /* SETUP_CONST */;
|
|
4092
|
-
if (!isMemberExpression(expString) && !maybeRef) {
|
|
4198
|
+
if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {
|
|
4093
4199
|
context.onError(createCompilerError(41 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));
|
|
4094
4200
|
return createTransformProps();
|
|
4095
4201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vue/compiler-core",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.5",
|
|
4
4
|
"description": "@vue/compiler-core",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/compiler-core.esm-bundler.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-core#readme",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@vue/shared": "3.1.
|
|
35
|
+
"@vue/shared": "3.1.5",
|
|
36
36
|
"@babel/parser": "^7.12.0",
|
|
37
37
|
"@babel/types": "^7.12.0",
|
|
38
38
|
"estree-walker": "^2.0.1",
|