@vue/compiler-dom 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.
@@ -45,11 +45,20 @@ const slotFlagsText = {
45
45
 
46
46
  const range = 2;
47
47
  function generateCodeFrame(source, start = 0, end = source.length) {
48
- const lines = source.split(/\r?\n/);
48
+ // Split the content into individual lines but capture the newline sequence
49
+ // that separated each line. This is important because the actual sequence is
50
+ // needed to properly take into account the full line length for offset
51
+ // comparison
52
+ let lines = source.split(/(\r?\n)/);
53
+ // Separate the lines and newline sequences into separate arrays for easier referencing
54
+ const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);
55
+ lines = lines.filter((_, idx) => idx % 2 === 0);
49
56
  let count = 0;
50
57
  const res = [];
51
58
  for (let i = 0; i < lines.length; i++) {
52
- count += lines[i].length + 1;
59
+ count +=
60
+ lines[i].length +
61
+ ((newlineSequences[i] && newlineSequences[i].length) || 0);
53
62
  if (count >= start) {
54
63
  for (let j = i - range; j <= i + range || end > count; j++) {
55
64
  if (j < 0 || j >= lines.length)
@@ -57,9 +66,10 @@ function generateCodeFrame(source, start = 0, end = source.length) {
57
66
  const line = j + 1;
58
67
  res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`);
59
68
  const lineLength = lines[j].length;
69
+ const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0;
60
70
  if (j === i) {
61
71
  // push underline
62
- const pad = start - (count - lineLength) + 1;
72
+ const pad = start - (count - (lineLength + newLineSeqLength));
63
73
  const length = Math.max(1, end > count ? lineLength - pad : end - start);
64
74
  res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length));
65
75
  }
@@ -68,7 +78,7 @@ function generateCodeFrame(source, start = 0, end = source.length) {
68
78
  const length = Math.max(Math.min(end - count, lineLength), 1);
69
79
  res.push(` | ` + '^'.repeat(length));
70
80
  }
71
- count += lineLength + 1;
81
+ count += lineLength + newLineSeqLength;
72
82
  }
73
83
  }
74
84
  break;
@@ -515,18 +525,84 @@ function isCoreComponent(tag) {
515
525
  }
516
526
  const nonIdentifierRE = /^\d|[^\$\w]/;
517
527
  const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);
518
- const memberExpRE = /^[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*(?:\s*\.\s*[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*|\[(.+)\])*$/;
528
+ const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/;
529
+ const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/;
530
+ const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g;
531
+ /**
532
+ * Simple lexer to check if an expression is a member expression. This is
533
+ * lax and only checks validity at the root level (i.e. does not validate exps
534
+ * inside square brackets), but it's ok since these are only used on template
535
+ * expressions and false positives are invalid expressions in the first place.
536
+ */
519
537
  const isMemberExpression = (path) => {
520
- if (!path)
521
- return false;
522
- const matched = memberExpRE.exec(path.trim());
523
- if (!matched)
524
- return false;
525
- if (!matched[1])
526
- return true;
527
- if (!/[\[\]]/.test(matched[1]))
528
- return true;
529
- return isMemberExpression(matched[1].trim());
538
+ // remove whitespaces around . or [ first
539
+ path = path.trim().replace(whitespaceRE, s => s.trim());
540
+ let state = 0 /* inMemberExp */;
541
+ let stateStack = [];
542
+ let currentOpenBracketCount = 0;
543
+ let currentOpenParensCount = 0;
544
+ let currentStringType = null;
545
+ for (let i = 0; i < path.length; i++) {
546
+ const char = path.charAt(i);
547
+ switch (state) {
548
+ case 0 /* inMemberExp */:
549
+ if (char === '[') {
550
+ stateStack.push(state);
551
+ state = 1 /* inBrackets */;
552
+ currentOpenBracketCount++;
553
+ }
554
+ else if (char === '(') {
555
+ stateStack.push(state);
556
+ state = 2 /* inParens */;
557
+ currentOpenParensCount++;
558
+ }
559
+ else if (!(i === 0 ? validFirstIdentCharRE : validIdentCharRE).test(char)) {
560
+ return false;
561
+ }
562
+ break;
563
+ case 1 /* inBrackets */:
564
+ if (char === `'` || char === `"` || char === '`') {
565
+ stateStack.push(state);
566
+ state = 3 /* inString */;
567
+ currentStringType = char;
568
+ }
569
+ else if (char === `[`) {
570
+ currentOpenBracketCount++;
571
+ }
572
+ else if (char === `]`) {
573
+ if (!--currentOpenBracketCount) {
574
+ state = stateStack.pop();
575
+ }
576
+ }
577
+ break;
578
+ case 2 /* inParens */:
579
+ if (char === `'` || char === `"` || char === '`') {
580
+ stateStack.push(state);
581
+ state = 3 /* inString */;
582
+ currentStringType = char;
583
+ }
584
+ else if (char === `(`) {
585
+ currentOpenParensCount++;
586
+ }
587
+ else if (char === `)`) {
588
+ // if the exp ends as a call then it should not be considered valid
589
+ if (i === path.length - 1) {
590
+ return false;
591
+ }
592
+ if (!--currentOpenParensCount) {
593
+ state = stateStack.pop();
594
+ }
595
+ }
596
+ break;
597
+ case 3 /* inString */:
598
+ if (char === currentStringType) {
599
+ state = stateStack.pop();
600
+ currentStringType = null;
601
+ }
602
+ break;
603
+ }
604
+ }
605
+ return !currentOpenBracketCount && !currentOpenParensCount;
530
606
  };
531
607
  function getInnerRange(loc, offset, length) {
532
608
  const source = loc.source.substr(offset, length);
@@ -1095,6 +1171,10 @@ function parseElement(context, ancestors) {
1095
1171
  const isPreBoundary = context.inPre && !wasInPre;
1096
1172
  const isVPreBoundary = context.inVPre && !wasInVPre;
1097
1173
  if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
1174
+ // #4030 self-closing <pre> tag
1175
+ if (context.options.isPreTag(element.tag)) {
1176
+ context.inPre = false;
1177
+ }
1098
1178
  return element;
1099
1179
  }
1100
1180
  // Children.
@@ -1150,12 +1230,13 @@ function parseTag(context, type, parent) {
1150
1230
  // save current state in case we need to re-parse attributes with v-pre
1151
1231
  const cursor = getCursor(context);
1152
1232
  const currentSource = context.source;
1153
- // Attributes.
1154
- let props = parseAttributes(context, type);
1155
1233
  // check <pre> tag
1156
- if (context.options.isPreTag(tag)) {
1234
+ const isPreTag = context.options.isPreTag(tag);
1235
+ if (isPreTag) {
1157
1236
  context.inPre = true;
1158
1237
  }
1238
+ // Attributes.
1239
+ let props = parseAttributes(context, type);
1159
1240
  // check v-pre
1160
1241
  if (type === 0 /* Start */ &&
1161
1242
  !context.inVPre &&
@@ -1202,41 +1283,17 @@ function parseTag(context, type, parent) {
1202
1283
  }
1203
1284
  }
1204
1285
  let tagType = 0 /* ELEMENT */;
1205
- const options = context.options;
1206
- if (!context.inVPre && !options.isCustomElement(tag)) {
1207
- const hasVIs = props.some(p => {
1208
- if (p.name !== 'is')
1209
- return;
1210
- // v-is="xxx" (TODO: deprecate)
1211
- if (p.type === 7 /* DIRECTIVE */) {
1212
- return true;
1213
- }
1214
- // is="vue:xxx"
1215
- if (p.value && p.value.content.startsWith('vue:')) {
1216
- return true;
1217
- }
1218
- // in compat mode, any is usage is considered a component
1219
- if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
1220
- return true;
1221
- }
1222
- });
1223
- if (options.isNativeTag && !hasVIs) {
1224
- if (!options.isNativeTag(tag))
1225
- tagType = 1 /* COMPONENT */;
1226
- }
1227
- else if (hasVIs ||
1228
- isCoreComponent(tag) ||
1229
- (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
1230
- /^[A-Z]/.test(tag) ||
1231
- tag === 'component') {
1232
- tagType = 1 /* COMPONENT */;
1233
- }
1286
+ if (!context.inVPre) {
1234
1287
  if (tag === 'slot') {
1235
1288
  tagType = 2 /* SLOT */;
1236
1289
  }
1237
- else if (tag === 'template' &&
1238
- props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
1239
- tagType = 3 /* TEMPLATE */;
1290
+ else if (tag === 'template') {
1291
+ if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {
1292
+ tagType = 3 /* TEMPLATE */;
1293
+ }
1294
+ }
1295
+ else if (isComponent(tag, props, context)) {
1296
+ tagType = 1 /* COMPONENT */;
1240
1297
  }
1241
1298
  }
1242
1299
  return {
@@ -1251,6 +1308,49 @@ function parseTag(context, type, parent) {
1251
1308
  codegenNode: undefined // to be created during transform phase
1252
1309
  };
1253
1310
  }
1311
+ function isComponent(tag, props, context) {
1312
+ const options = context.options;
1313
+ if (options.isCustomElement(tag)) {
1314
+ return false;
1315
+ }
1316
+ if (tag === 'component' ||
1317
+ /^[A-Z]/.test(tag) ||
1318
+ isCoreComponent(tag) ||
1319
+ (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
1320
+ (options.isNativeTag && !options.isNativeTag(tag))) {
1321
+ return true;
1322
+ }
1323
+ // at this point the tag should be a native tag, but check for potential "is"
1324
+ // casting
1325
+ for (let i = 0; i < props.length; i++) {
1326
+ const p = props[i];
1327
+ if (p.type === 6 /* ATTRIBUTE */) {
1328
+ if (p.name === 'is' && p.value) {
1329
+ if (p.value.content.startsWith('vue:')) {
1330
+ return true;
1331
+ }
1332
+ else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
1333
+ return true;
1334
+ }
1335
+ }
1336
+ }
1337
+ else {
1338
+ // directive
1339
+ // v-is (TODO Deprecate)
1340
+ if (p.name === 'is') {
1341
+ return true;
1342
+ }
1343
+ else if (
1344
+ // :is on plain element - only treat as component in compat mode
1345
+ p.name === 'bind' &&
1346
+ isBindKey(p.arg, 'is') &&
1347
+ true &&
1348
+ checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {
1349
+ return true;
1350
+ }
1351
+ }
1352
+ }
1353
+ }
1254
1354
  function parseAttributes(context, type) {
1255
1355
  const props = [];
1256
1356
  const attributeNames = new Set();
@@ -2113,7 +2213,7 @@ function createStructuralDirectiveTransform(name, fn) {
2113
2213
  }
2114
2214
 
2115
2215
  const PURE_ANNOTATION = `/*#__PURE__*/`;
2116
- function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false }) {
2216
+ 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 }) {
2117
2217
  const context = {
2118
2218
  mode,
2119
2219
  prefixIdentifiers,
@@ -2124,6 +2224,7 @@ function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode
2124
2224
  runtimeGlobalName,
2125
2225
  runtimeModuleName,
2126
2226
  ssr,
2227
+ isTS,
2127
2228
  source: ast.loc.source,
2128
2229
  code: ``,
2129
2230
  column: 1,
@@ -2279,7 +2380,7 @@ function genFunctionPreamble(ast, context) {
2279
2380
  newline();
2280
2381
  push(`return `);
2281
2382
  }
2282
- function genAssets(assets, type, { helper, push, newline }) {
2383
+ function genAssets(assets, type, { helper, push, newline, isTS }) {
2283
2384
  const resolver = helper(type === 'filter'
2284
2385
  ? RESOLVE_FILTER
2285
2386
  : type === 'component'
@@ -2292,7 +2393,7 @@ function genAssets(assets, type, { helper, push, newline }) {
2292
2393
  if (maybeSelfReference) {
2293
2394
  id = id.slice(0, -6);
2294
2395
  }
2295
- push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`);
2396
+ push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);
2296
2397
  if (i < assets.length - 1) {
2297
2398
  newline();
2298
2399
  }
@@ -3400,7 +3501,8 @@ function hasForwardedSlots(children) {
3400
3501
  switch (child.type) {
3401
3502
  case 1 /* ELEMENT */:
3402
3503
  if (child.tagType === 2 /* SLOT */ ||
3403
- (child.tagType === 0 /* ELEMENT */ &&
3504
+ ((child.tagType === 0 /* ELEMENT */ ||
3505
+ child.tagType === 3 /* TEMPLATE */) &&
3404
3506
  hasForwardedSlots(child.children))) {
3405
3507
  return true;
3406
3508
  }
@@ -3564,16 +3666,10 @@ function resolveComponentType(node, context, ssr = false) {
3564
3666
  let { tag } = node;
3565
3667
  // 1. dynamic component
3566
3668
  const isExplicitDynamic = isComponentTag(tag);
3567
- const isProp = findProp(node, 'is') || (!isExplicitDynamic && findDir(node, 'is'));
3669
+ const isProp = findProp(node, 'is');
3568
3670
  if (isProp) {
3569
- if (!isExplicitDynamic && isProp.type === 6 /* ATTRIBUTE */) {
3570
- // <button is="vue:xxx">
3571
- // if not <component>, only is value that starts with "vue:" will be
3572
- // treated as component by the parse phase and reach here, unless it's
3573
- // compat mode where all is values are considered components
3574
- tag = isProp.value.content.replace(/^vue:/, '');
3575
- }
3576
- else {
3671
+ if (isExplicitDynamic ||
3672
+ (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {
3577
3673
  const exp = isProp.type === 6 /* ATTRIBUTE */
3578
3674
  ? isProp.value && createSimpleExpression(isProp.value.content, true)
3579
3675
  : isProp.exp;
@@ -3583,6 +3679,21 @@ function resolveComponentType(node, context, ssr = false) {
3583
3679
  ]);
3584
3680
  }
3585
3681
  }
3682
+ else if (isProp.type === 6 /* ATTRIBUTE */ &&
3683
+ isProp.value.content.startsWith('vue:')) {
3684
+ // <button is="vue:xxx">
3685
+ // if not <component>, only is value that starts with "vue:" will be
3686
+ // treated as component by the parse phase and reach here, unless it's
3687
+ // compat mode where all is values are considered components
3688
+ tag = isProp.value.content.slice(4);
3689
+ }
3690
+ }
3691
+ // 1.5 v-is (TODO: Deprecate)
3692
+ const isDir = !isExplicitDynamic && findDir(node, 'is');
3693
+ if (isDir && isDir.exp) {
3694
+ return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
3695
+ isDir.exp
3696
+ ]);
3586
3697
  }
3587
3698
  // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
3588
3699
  const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);
@@ -3666,7 +3777,9 @@ function buildProps(node, context, props = node.props, ssr = false) {
3666
3777
  }
3667
3778
  // skip is on <component>, or is="vue:xxx"
3668
3779
  if (name === 'is' &&
3669
- (isComponentTag(tag) || (value && value.content.startsWith('vue:')))) {
3780
+ (isComponentTag(tag) ||
3781
+ (value && value.content.startsWith('vue:')) ||
3782
+ (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {
3670
3783
  continue;
3671
3784
  }
3672
3785
  properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));
@@ -3689,7 +3802,10 @@ function buildProps(node, context, props = node.props, ssr = false) {
3689
3802
  }
3690
3803
  // skip v-is and :is on <component>
3691
3804
  if (name === 'is' ||
3692
- (isVBind && isComponentTag(tag) && isBindKey(arg, 'is'))) {
3805
+ (isVBind &&
3806
+ isBindKey(arg, 'is') &&
3807
+ (isComponentTag(tag) ||
3808
+ (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {
3693
3809
  continue;
3694
3810
  }
3695
3811
  // skip v-on in SSR compilation
@@ -4214,7 +4330,7 @@ const transformModel = (dir, node, context) => {
4214
4330
  // _unref(exp)
4215
4331
  context.bindingMetadata[rawExp];
4216
4332
  const maybeRef = !true /* SETUP_CONST */;
4217
- if (!isMemberExpression(expString) && !maybeRef) {
4333
+ if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {
4218
4334
  context.onError(createCompilerError(41 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));
4219
4335
  return createTransformProps();
4220
4336
  }