@vue/compiler-vapor 3.6.0-beta.15 → 3.6.0-beta.17

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @vue/compiler-vapor v3.6.0-beta.15
2
+ * @vue/compiler-vapor v3.6.0-beta.17
3
3
  * (c) 2018-present Yuxi (Evan) You and Vue contributors
4
4
  * @license MIT
5
5
  **/
@@ -152,7 +152,7 @@ const EMPTY_EXPRESSION = (0, _vue_compiler_dom.createSimpleExpression)("", true)
152
152
  //#region packages/compiler-vapor/src/utils.ts
153
153
  const findProp$1 = _vue_compiler_dom.findProp;
154
154
  /** find directive */
155
- const findDir$2 = _vue_compiler_dom.findDir;
155
+ const findDir$4 = _vue_compiler_dom.findDir;
156
156
  function propToExpression(prop) {
157
157
  return prop.type === 6 ? prop.value ? (0, _vue_compiler_dom.createSimpleExpression)(prop.value.content, true, prop.value.loc) : EMPTY_EXPRESSION : prop.exp;
158
158
  }
@@ -230,6 +230,7 @@ function getBlockShape(block) {
230
230
  //#endregion
231
231
  //#region packages/compiler-vapor/src/transform.ts
232
232
  const generatedVarRE = /^[nxr](\d+)$/;
233
+ const childContextInfoCache = /* @__PURE__ */ new WeakMap();
233
234
  var TransformContext = class TransformContext {
234
235
  constructor(ir, node, options = {}) {
235
236
  this.ir = ir;
@@ -255,6 +256,7 @@ var TransformContext = class TransformContext {
255
256
  this.operationIndex = this.block.operation.length;
256
257
  this.isLastEffectiveChild = true;
257
258
  this.isOnRightmostPath = true;
259
+ this.isSingleRoot = false;
258
260
  this.templateCloseTags = void 0;
259
261
  this.templateCloseBlocks = false;
260
262
  this.globalId = 0;
@@ -380,8 +382,10 @@ var TransformContext = class TransformContext {
380
382
  create(node, index) {
381
383
  let effectiveParent = this;
382
384
  while (effectiveParent && effectiveParent.node.type === 1 && effectiveParent.node.tagType === 3) effectiveParent = effectiveParent.parent;
383
- const isLastEffectiveChild = this.isEffectivelyLastChild(index);
385
+ const childInfo = this.getChildContextInfo();
386
+ const isLastEffectiveChild = childInfo.isLastEffectiveChild[index];
384
387
  const isOnRightmostPath = this.isOnRightmostPath && isLastEffectiveChild;
388
+ const isSingleRoot = this.isSingleRootChild(childInfo);
385
389
  return Object.assign(Object.create(TransformContext.prototype), this, {
386
390
  node,
387
391
  parent: this,
@@ -396,6 +400,7 @@ var TransformContext = class TransformContext {
396
400
  effectiveParent,
397
401
  isLastEffectiveChild,
398
402
  isOnRightmostPath,
403
+ isSingleRoot,
399
404
  templateCloseTags: this.templateCloseTags,
400
405
  templateCloseBlocks: this.templateCloseBlocks
401
406
  });
@@ -405,12 +410,59 @@ var TransformContext = class TransformContext {
405
410
  if (operation && isBlockOperation(operation) && operation.effectIndex !== void 0 && operation.effectIndex >= index) operation.effectIndex++;
406
411
  for (const child of dynamic.children) this.shiftEffectBoundaries(index, child);
407
412
  }
408
- isEffectivelyLastChild(index) {
409
- const children = this.node.children;
410
- if (!children) return true;
411
- return children.every((c, i) => i <= index || c.type === 1 && c.tagType === 1);
413
+ getChildContextInfo() {
414
+ const node = this.node;
415
+ if (node.type !== 0 && node.type !== 1) return {
416
+ node,
417
+ hasSingleRootChild: true,
418
+ isLastEffectiveChild: []
419
+ };
420
+ const cached = childContextInfoCache.get(this);
421
+ if (cached && cached.node === node) return cached;
422
+ const { children } = node;
423
+ const isLastEffectiveChild = new Array(children.length);
424
+ let hasFollowingEffectiveChild = false;
425
+ for (let i = children.length - 1; i >= 0; i--) {
426
+ isLastEffectiveChild[i] = !hasFollowingEffectiveChild;
427
+ if (!isComponentChild(children[i])) hasFollowingEffectiveChild = true;
428
+ }
429
+ const childInfo = {
430
+ node,
431
+ hasSingleRootChild: hasSingleRootChild(children),
432
+ isLastEffectiveChild
433
+ };
434
+ childContextInfoCache.set(this, childInfo);
435
+ return childInfo;
436
+ }
437
+ isSingleRootChild(childInfo) {
438
+ if (this.inVFor || !childInfo.hasSingleRootChild) return false;
439
+ if (this.node.type === 0) return true;
440
+ return this.node.type === 1 && this.node.tagType === 3 && !!this.parent && this.isSingleRoot;
412
441
  }
413
442
  };
443
+ function hasSingleRootChild(children) {
444
+ let nonCommentChildren = 0;
445
+ let hasEncounteredIf = false;
446
+ let isSingleIfBlock = true;
447
+ for (const child of children) {
448
+ if ((0, _vue_compiler_dom.isCommentOrWhitespace)(child)) continue;
449
+ nonCommentChildren++;
450
+ if (isIfChild(child)) {
451
+ if (hasEncounteredIf) isSingleIfBlock = false;
452
+ hasEncounteredIf = true;
453
+ } else if (!hasEncounteredIf || !isElseChild(child)) isSingleIfBlock = false;
454
+ }
455
+ return nonCommentChildren === 1 || isSingleIfBlock;
456
+ }
457
+ function isComponentChild(child) {
458
+ return child.type === 1 && child.tagType === 1;
459
+ }
460
+ function isIfChild(child) {
461
+ return child.type === 9 || child.type === 1 && !!(0, _vue_compiler_dom.findDir)(child, "if");
462
+ }
463
+ function isElseChild(child) {
464
+ return child.type === 1 && !!(0, _vue_compiler_dom.findDir)(child, /^else(-if)?$/, true);
465
+ }
414
466
  const defaultOptions = {
415
467
  filename: "",
416
468
  prefixIdentifiers: true,
@@ -671,6 +723,8 @@ function genPrependNode(oper, { helper }) {
671
723
  function genExpression(node, context, assignment) {
672
724
  node = context.getExpressionReplacement(node);
673
725
  const { content, ast, isStatic, loc } = node;
726
+ const { options } = context;
727
+ const { inline } = options;
674
728
  if (isStatic) return [[
675
729
  JSON.stringify(content),
676
730
  -2,
@@ -692,23 +746,31 @@ function genExpression(node, context, assignment) {
692
746
  let hasMemberExpression = false;
693
747
  if (ids.length) {
694
748
  const [frag, push] = buildCodeFragment();
695
- ids.sort((a, b) => a.start - b.start).forEach((id, i) => {
696
- const start = id.start - 1;
697
- const end = id.end - 1;
698
- const last = ids[i - 1];
699
- const leadingText = content.slice(last ? last.end - 1 : 0, start);
700
- if (leadingText.length) push([leadingText, -3]);
701
- const source = content.slice(start, end);
749
+ let lastEnd = 0;
750
+ ids.sort((a, b) => a.start - b.start).forEach((id) => {
751
+ const idStart = id.start - 1;
752
+ const idEnd = id.end - 1;
753
+ const source = content.slice(idStart, idEnd);
702
754
  const parentStack = parentStackMap.get(id);
703
755
  const parent = parentStack[parentStack.length - 1];
756
+ let start = idStart;
757
+ let end = idEnd;
758
+ if (inline && options.bindingMetadata && options.bindingMetadata[source] === "setup-let" && parent && parent.type === "UpdateExpression" && parent.argument === id) {
759
+ start = parent.start - 1;
760
+ end = parent.end - 1;
761
+ }
762
+ if (start < lastEnd) return;
763
+ const leadingText = content.slice(lastEnd, start);
764
+ if (leadingText.length) push([leadingText, -3]);
704
765
  hasMemberExpression || (hasMemberExpression = parent && (parent.type === "MemberExpression" || parent.type === "OptionalMemberExpression"));
705
766
  push(...genIdentifier(source, context, {
706
767
  start: (0, _vue_compiler_dom.advancePositionWithClone)(node.loc.start, source, start),
707
768
  end: (0, _vue_compiler_dom.advancePositionWithClone)(node.loc.start, source, end),
708
769
  source
709
- }, hasMemberExpression ? void 0 : assignment, id, parent, parentStack));
710
- if (i === ids.length - 1 && end < content.length) push([content.slice(end), -3]);
770
+ }, hasMemberExpression ? void 0 : assignment, id, parent, parentStack, node));
771
+ lastEnd = end;
711
772
  });
773
+ if (lastEnd < content.length) push([content.slice(lastEnd), -3]);
712
774
  if (assignment && hasMemberExpression) push(` = ${assignment}`);
713
775
  return frag;
714
776
  } else return [[
@@ -717,7 +779,7 @@ function genExpression(node, context, assignment) {
717
779
  loc
718
780
  ]];
719
781
  }
720
- function genIdentifier(raw, context, loc, assignment, id, parent, parentStack) {
782
+ function genIdentifier(raw, context, loc, assignment, id, parent, parentStack, sourceNode) {
721
783
  const { options, helper, identifiers } = context;
722
784
  const { inline, bindingMetadata } = options;
723
785
  let name = raw;
@@ -737,19 +799,49 @@ function genIdentifier(raw, context, loc, assignment, id, parent, parentStack) {
737
799
  else return genExpression(replacement, context, assignment);
738
800
  }
739
801
  let prefix;
740
- if ((0, _vue_compiler_dom.isStaticProperty)(parent) && parent.shorthand) prefix = `${raw}: `;
741
802
  const type = bindingMetadata && bindingMetadata[raw];
803
+ const isDestructureAssignment = parent && (0, _vue_compiler_dom.isInDestructureAssignment)(parent, parentStack || []);
804
+ const isAssignmentLVal = parent && parent.type === "AssignmentExpression" && parent.left === id;
805
+ const isUpdateArg = parent && parent.type === "UpdateExpression" && parent.argument === id;
806
+ if ((0, _vue_compiler_dom.isStaticProperty)(parent) && parent.shorthand && !(inline && type === "setup-let" && isDestructureAssignment)) prefix = `${raw}: `;
742
807
  if (inline) switch (type) {
743
808
  case "setup-let":
744
- name = raw = assignment ? `_isRef(${raw}) ? (${raw}.value = ${assignment}) : (${raw} = ${assignment})` : unref();
809
+ if (isAssignmentLVal) {
810
+ const { right, operator } = parent;
811
+ const source = sourceNode;
812
+ const sourceContent = source.content;
813
+ const rightStart = right.start - 1;
814
+ const rightEnd = right.end - 1;
815
+ const rightContent = sourceContent.slice(rightStart, rightEnd);
816
+ const rightExp = (0, _vue_compiler_dom.createSimpleExpression)(rightContent, false, {
817
+ start: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, sourceContent, rightStart),
818
+ end: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, sourceContent, rightEnd),
819
+ source: rightContent
820
+ });
821
+ rightExp.ast = parseExp(context, rightContent);
822
+ return [
823
+ prefix,
824
+ `${helper("isRef")}(${raw}) ? ${raw}.value ${operator} `,
825
+ ...genExpression(rightExp, context),
826
+ ` : `,
827
+ [
828
+ raw,
829
+ -2,
830
+ loc,
831
+ name
832
+ ]
833
+ ];
834
+ } else if (isUpdateArg) {
835
+ const { prefix: isPrefix, operator } = parent;
836
+ const updatePrefix = isPrefix ? operator : ``;
837
+ const updatePostfix = isPrefix ? `` : operator;
838
+ raw = `${helper("isRef")}(${raw}) ? ${updatePrefix}${raw}.value${updatePostfix} : ${updatePrefix}${raw}${updatePostfix}`;
839
+ } else if (!isDestructureAssignment) name = raw = assignment ? `${helper("isRef")}(${raw}) ? (${raw}.value = ${assignment}) : (${raw} = ${assignment})` : unref();
745
840
  break;
746
841
  case "setup-ref":
747
842
  name = raw = withAssignment(`${raw}.value`);
748
843
  break;
749
844
  case "setup-maybe-ref":
750
- const isDestructureAssignment = parent && (0, _vue_compiler_dom.isInDestructureAssignment)(parent, parentStack || []);
751
- const isAssignmentLVal = parent && parent.type === "AssignmentExpression" && parent.left === id;
752
- const isUpdateArg = parent && parent.type === "UpdateExpression" && parent.argument === id;
753
845
  raw = isAssignmentLVal || isUpdateArg || isDestructureAssignment ? name = `${raw}.value` : assignment ? `${helper("isRef")}(${raw}) ? (${raw}.value = ${assignment}) : null` : unref();
754
846
  break;
755
847
  case "props":
@@ -785,10 +877,10 @@ function canPrefix(name) {
785
877
  }
786
878
  function processExpressions(context, expressions, shouldDeclare) {
787
879
  const expressionReplacements = /* @__PURE__ */ new Map();
788
- const { seenVariable, variableToExpMap, expToVariableMap, seenIdentifier, updatedVariable } = analyzeExpressions(expressions);
880
+ const { seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable } = analyzeExpressions(expressions);
789
881
  const reservedNames = new Set(seenIdentifier);
790
- const varDeclarations = processRepeatedVariables(context, seenVariable, variableToExpMap, expToVariableMap, seenIdentifier, updatedVariable, reservedNames, expressionReplacements);
791
- const expDeclarations = processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expToVariableMap, reservedNames, expressionReplacements);
882
+ const varDeclarations = processRepeatedVariables(context, seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable, reservedNames, expressionReplacements);
883
+ const expDeclarations = processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expressionRecords, reservedNames, expressionReplacements);
792
884
  return {
793
885
  ...genDeclarations([...varDeclarations, ...expDeclarations], context, shouldDeclare),
794
886
  expressionReplacements
@@ -797,19 +889,22 @@ function processExpressions(context, expressions, shouldDeclare) {
797
889
  function analyzeExpressions(expressions) {
798
890
  const seenVariable = Object.create(null);
799
891
  const variableToExpMap = /* @__PURE__ */ new Map();
800
- const expToVariableMap = /* @__PURE__ */ new Map();
892
+ const expressionRecords = /* @__PURE__ */ new Map();
801
893
  const seenIdentifier = /* @__PURE__ */ new Set();
802
894
  const updatedVariable = /* @__PURE__ */ new Set();
895
+ const getRecord = (exp) => {
896
+ let record = expressionRecords.get(exp);
897
+ if (!record) expressionRecords.set(exp, record = { variables: [] });
898
+ return record;
899
+ };
803
900
  const registerVariable = (name, exp, isIdentifier, loc, parentStack = []) => {
804
901
  if (isIdentifier) seenIdentifier.add(name);
805
902
  seenVariable[name] = (seenVariable[name] || 0) + 1;
806
903
  variableToExpMap.set(name, (variableToExpMap.get(name) || /* @__PURE__ */ new Set()).add(exp));
807
- const variables = expToVariableMap.get(exp) || [];
808
- variables.push({
904
+ getRecord(exp).variables.push({
809
905
  name,
810
906
  loc
811
907
  });
812
- expToVariableMap.set(exp, variables);
813
908
  if (parentStack.some((p) => p.type === "UpdateExpression" || p.type === "AssignmentExpression")) updatedVariable.add(name);
814
909
  };
815
910
  for (const exp of expressions) {
@@ -846,7 +941,7 @@ function analyzeExpressions(expressions) {
846
941
  seenVariable,
847
942
  seenIdentifier,
848
943
  variableToExpMap,
849
- expToVariableMap,
944
+ expressionRecords,
850
945
  updatedVariable
851
946
  };
852
947
  }
@@ -856,9 +951,10 @@ function getProcessedExpression(exp, expressionReplacements) {
856
951
  function setExpressionReplacement(expressionReplacements, exp, content, ast) {
857
952
  expressionReplacements.set(exp, (0, _vue_shared.extend)({ ast }, (0, _vue_compiler_dom.createSimpleExpression)(content, exp.isStatic, exp.loc, exp.constType)));
858
953
  }
859
- function processRepeatedVariables(context, seenVariable, variableToExpMap, expToVariableMap, seenIdentifier, updatedVariable, reservedNames, expressionReplacements) {
954
+ function processRepeatedVariables(context, seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable, reservedNames, expressionReplacements) {
860
955
  const declarations = [];
861
- const expToReplacementMap = /* @__PURE__ */ new Map();
956
+ const declaredNames = /* @__PURE__ */ new Set();
957
+ const replacementPlan = /* @__PURE__ */ new Map();
862
958
  for (const [name, exps] of variableToExpMap) {
863
959
  if (updatedVariable.has(name)) continue;
864
960
  if ((0, _vue_shared.isGloballyAllowed)(name)) continue;
@@ -867,96 +963,201 @@ function processRepeatedVariables(context, seenVariable, variableToExpMap, expTo
867
963
  const varName = isIdentifier ? name : getUniqueDeclarationName(genVarName(name), reservedNames);
868
964
  exps.forEach((node) => {
869
965
  if (node.ast && varName !== name) {
870
- const replacements = expToReplacementMap.get(node) || [];
871
- replacements.push({
872
- name: varName,
873
- locs: expToVariableMap.get(node).reduce((locs, v) => {
874
- if (v.name === name && v.loc) locs.push(v.loc);
875
- return locs;
876
- }, [])
966
+ for (const variable of getExpressionVariables(expressionRecords, node)) if (variable.name === name && variable.loc) queueContentReplacement(replacementPlan, node, {
967
+ start: variable.loc.start - 1,
968
+ end: variable.loc.end - 1,
969
+ content: varName
877
970
  });
878
- expToReplacementMap.set(node, replacements);
879
971
  }
880
972
  });
881
- if (!declarations.some((d) => d.name === varName) && (!isIdentifier || shouldDeclareVariable(name, expToVariableMap, exps))) declarations.push({
882
- name: varName,
883
- isIdentifier,
884
- value: (0, _vue_shared.extend)({ ast: isIdentifier ? null : parseExp(context, name) }, (0, _vue_compiler_dom.createSimpleExpression)(name)),
885
- rawName: name,
886
- exps,
887
- seenCount: seenVariable[name]
888
- });
973
+ if (!declaredNames.has(varName) && (!isIdentifier || shouldDeclareVariable(name, expressionRecords, exps))) {
974
+ declaredNames.add(varName);
975
+ declarations.push({
976
+ name: varName,
977
+ isIdentifier,
978
+ value: (0, _vue_shared.extend)({ ast: isIdentifier ? null : parseExp(context, name) }, (0, _vue_compiler_dom.createSimpleExpression)(name)),
979
+ rawName: name,
980
+ exps,
981
+ seenCount: seenVariable[name]
982
+ });
983
+ }
889
984
  }
890
985
  }
891
- for (const [exp, replacements] of expToReplacementMap) {
892
- let content = getProcessedExpression(exp, expressionReplacements).content;
893
- replacements.flatMap(({ name, locs }) => locs.map(({ start, end }) => ({
894
- start,
895
- end,
896
- name
897
- }))).sort((a, b) => b.end - a.end).forEach(({ start, end, name }) => {
898
- content = content.slice(0, start - 1) + name + content.slice(end - 1);
899
- });
900
- setExpressionReplacement(expressionReplacements, exp, content, parseExp(context, content));
901
- }
986
+ applyReplacementPlan(context, expressionReplacements, replacementPlan);
902
987
  return declarations;
903
988
  }
904
- function shouldDeclareVariable(name, expToVariableMap, exps) {
905
- const vars = Array.from(exps, (exp) => expToVariableMap.get(exp).map((v) => v.name));
906
- if (vars.every((v) => v.length === 1)) return true;
907
- if (vars.some((v) => v.filter((e) => e === name).length > 1)) return true;
908
- const first = vars[0];
909
- if (vars.some((v) => v.length !== first.length)) {
910
- if (vars.some((v) => v.length > first.length && v.every((e) => first.includes(e))) || vars.some((v) => first.length > v.length && first.every((e) => v.includes(e)))) return false;
989
+ function shouldDeclareVariable(name, expressionRecords, exps) {
990
+ const variableUsages = [];
991
+ let allSingleVariable = true;
992
+ let hasRepeatedName = false;
993
+ let hasDifferentLength = false;
994
+ outer: for (const exp of exps) {
995
+ const variables = getExpressionVariables(expressionRecords, exp);
996
+ if (allSingleVariable && variables.length !== 1) allSingleVariable = false;
997
+ if (!hasDifferentLength && variableUsages.length > 0 && variables.length !== variableUsages[0].length) hasDifferentLength = true;
998
+ let nameCount = 0;
999
+ for (const variable of variables) if (variable.name === name && ++nameCount > 1) {
1000
+ hasRepeatedName = true;
1001
+ break outer;
1002
+ }
1003
+ variableUsages.push(variables);
1004
+ }
1005
+ if (allSingleVariable) return true;
1006
+ if (hasRepeatedName) return true;
1007
+ const first = variableUsages[0];
1008
+ if (hasDifferentLength) {
1009
+ for (const variables of variableUsages) {
1010
+ if (variables.length === first.length) continue;
1011
+ const longer = variables.length > first.length ? variables : first;
1012
+ const shorter = variables.length > first.length ? first : variables;
1013
+ const shorterNames = /* @__PURE__ */ new Set();
1014
+ for (const variable of shorter) shorterNames.add(variable.name);
1015
+ let isSubset = true;
1016
+ for (const variable of longer) if (!shorterNames.has(variable.name)) {
1017
+ isSubset = false;
1018
+ break;
1019
+ }
1020
+ if (isSubset) return false;
1021
+ }
911
1022
  return true;
912
1023
  }
913
- if (vars.every((v) => v.every((e, idx) => e === first[idx]))) return false;
914
- return true;
1024
+ for (const variables of variableUsages) for (let i = 0; i < variables.length; i++) if (variables[i].name !== first[i].name) return true;
1025
+ return false;
915
1026
  }
916
- function processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expToVariableMap, reservedNames, expressionReplacements) {
1027
+ function processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expressionRecords, reservedNames, expressionReplacements) {
917
1028
  const declarations = [];
918
- const seenExp = expressions.reduce((acc, exp) => {
919
- const vars = expToVariableMap.get(exp);
920
- if (!vars) return acc;
1029
+ const seenExp = /* @__PURE__ */ new Map();
1030
+ for (const exp of expressions) {
1031
+ var _expressionRecords$ge;
1032
+ const vars = (_expressionRecords$ge = expressionRecords.get(exp)) === null || _expressionRecords$ge === void 0 ? void 0 : _expressionRecords$ge.variables;
1033
+ if (!vars) continue;
921
1034
  const processed = getProcessedExpression(exp, expressionReplacements);
922
- const variables = vars.map((v) => v.name);
923
- if (processed.ast && processed.ast.type !== "Identifier" && !(variables && variables.some((v) => updatedVariable.has(v))) && !variables.some((v) => (0, _vue_shared.isGloballyAllowed)(v))) acc[processed.content] = (acc[processed.content] || 0) + 1;
924
- return acc;
925
- }, Object.create(null));
926
- Object.entries(seenExp).forEach(([content, count]) => {
927
- if (count > 1) {
928
- const delVars = {};
929
- for (let i = varDeclarations.length - 1; i >= 0; i--) {
930
- const item = varDeclarations[i];
931
- if (!item.exps || !item.seenCount) continue;
932
- if ([...item.exps].every((node) => getProcessedExpression(node, expressionReplacements).content === content && item.seenCount === count)) {
933
- delVars[item.name] = item.rawName;
934
- reservedNames.delete(item.name);
935
- varDeclarations.splice(i, 1);
936
- }
937
- }
938
- const value = (0, _vue_shared.extend)({}, getProcessedExpression(expressions.find((exp) => getProcessedExpression(exp, expressionReplacements).content === content), expressionReplacements));
939
- Object.keys(delVars).forEach((name) => {
940
- value.content = value.content.replace(name, delVars[name]);
941
- if (value.ast) value.ast = parseExp(context, value.content);
942
- });
943
- const varName = getUniqueDeclarationName(genVarName(content), reservedNames);
944
- declarations.push({
945
- name: varName,
946
- value
1035
+ if (canCacheExpression(processed, vars, updatedVariable)) {
1036
+ const seen = seenExp.get(processed.content);
1037
+ if (seen) seen.count++;
1038
+ else seenExp.set(processed.content, {
1039
+ count: 1,
1040
+ first: exp
947
1041
  });
948
- expressions.forEach((exp) => {
949
- const processed = getProcessedExpression(exp, expressionReplacements);
950
- if (processed.content === content) setExpressionReplacement(expressionReplacements, exp, varName, null);
951
- else if (processed.content.includes(content)) {
952
- const replacedContent = processed.content.replace(new RegExp(escapeRegExp(content), "g"), varName);
1042
+ }
1043
+ }
1044
+ const repeatedExpressions = [...seenExp].sort(([contentA], [contentB]) => contentB.length - contentA.length);
1045
+ for (const [content, { count, first }] of repeatedExpressions) if (count > 1) {
1046
+ const removedDeclarations = [];
1047
+ for (let i = varDeclarations.length - 1; i >= 0; i--) {
1048
+ const item = varDeclarations[i];
1049
+ if (!item.exps || !item.seenCount) continue;
1050
+ if ([...item.exps].every((node) => getProcessedExpression(node, expressionReplacements).content === content && item.seenCount === count)) {
1051
+ removedDeclarations.push({
1052
+ name: item.name,
1053
+ rawName: item.rawName
1054
+ });
1055
+ reservedNames.delete(item.name);
1056
+ varDeclarations.splice(i, 1);
1057
+ }
1058
+ }
1059
+ const value = (0, _vue_shared.extend)({}, getProcessedExpression(first, expressionReplacements));
1060
+ const restorePlan = [];
1061
+ for (const { name, rawName } of removedDeclarations) restorePlan.push(...findIdentifierReplacements(value, name, rawName));
1062
+ if (restorePlan.length) {
1063
+ value.content = applyContentReplacements(value.content, restorePlan);
1064
+ if (value.ast) value.ast = parseExp(context, value.content);
1065
+ }
1066
+ const varName = getUniqueDeclarationName(genVarName(content), reservedNames);
1067
+ declarations.push({
1068
+ name: varName,
1069
+ value
1070
+ });
1071
+ for (const exp of expressions) {
1072
+ const processed = getProcessedExpression(exp, expressionReplacements);
1073
+ if (processed.content === content) setExpressionReplacement(expressionReplacements, exp, varName, null);
1074
+ else if (processed.content.includes(content)) {
1075
+ const replacements = findContentReplacements(processed, content, varName);
1076
+ if (replacements.length) {
1077
+ const replacedContent = applyContentReplacements(processed.content, replacements);
953
1078
  setExpressionReplacement(expressionReplacements, exp, replacedContent, parseExp(context, replacedContent));
954
1079
  }
955
- });
1080
+ }
956
1081
  }
957
- });
1082
+ }
958
1083
  return declarations;
959
1084
  }
1085
+ function canCacheExpression(processed, vars, updatedVariable) {
1086
+ if (!processed.ast || processed.ast.type === "Identifier") return false;
1087
+ for (const { name } of vars) if (updatedVariable.has(name) || (0, _vue_shared.isGloballyAllowed)(name)) return false;
1088
+ return true;
1089
+ }
1090
+ function getExpressionVariables(expressionRecords, exp) {
1091
+ var _expressionRecords$ge2;
1092
+ return ((_expressionRecords$ge2 = expressionRecords.get(exp)) === null || _expressionRecords$ge2 === void 0 ? void 0 : _expressionRecords$ge2.variables) || [];
1093
+ }
1094
+ function queueContentReplacement(replacementPlan, exp, replacement) {
1095
+ const replacements = replacementPlan.get(exp);
1096
+ if (replacements) replacements.push(replacement);
1097
+ else replacementPlan.set(exp, [replacement]);
1098
+ }
1099
+ function applyReplacementPlan(context, expressionReplacements, replacementPlan) {
1100
+ for (const [exp, replacements] of replacementPlan) {
1101
+ if (!replacements.length) continue;
1102
+ const content = applyContentReplacements(getProcessedExpression(exp, expressionReplacements).content, replacements);
1103
+ setExpressionReplacement(expressionReplacements, exp, content, parseExp(context, content));
1104
+ }
1105
+ }
1106
+ function findContentReplacements(exp, content, replacement) {
1107
+ const identifiers = getIdentifierRanges(exp);
1108
+ if (!identifiers.length) return [];
1109
+ const replacements = [];
1110
+ let searchStart = 0;
1111
+ let start = exp.content.indexOf(content, searchStart);
1112
+ while (start !== -1) {
1113
+ const end = start + content.length;
1114
+ let canReplace = false;
1115
+ for (const identifier of identifiers) {
1116
+ if (start >= identifier.end || end <= identifier.start) continue;
1117
+ if (start > identifier.start || end < identifier.end) {
1118
+ canReplace = false;
1119
+ break;
1120
+ }
1121
+ canReplace = true;
1122
+ }
1123
+ if (canReplace) {
1124
+ replacements.push({
1125
+ start,
1126
+ end,
1127
+ content: replacement
1128
+ });
1129
+ searchStart = end;
1130
+ } else searchStart = start + 1;
1131
+ start = exp.content.indexOf(content, searchStart);
1132
+ }
1133
+ return replacements;
1134
+ }
1135
+ function findIdentifierReplacements(exp, name, replacement) {
1136
+ const replacements = [];
1137
+ for (const { start, end } of getIdentifierRanges(exp)) if (exp.content.slice(start, end) === name) replacements.push({
1138
+ start,
1139
+ end,
1140
+ content: replacement
1141
+ });
1142
+ return replacements;
1143
+ }
1144
+ function getIdentifierRanges(exp) {
1145
+ if (!exp.ast || typeof exp.ast !== "object") return [];
1146
+ const identifiers = [];
1147
+ (0, _vue_compiler_dom.walkIdentifiers)(exp.ast, (id) => {
1148
+ identifiers.push({
1149
+ start: id.start - 1,
1150
+ end: id.end - 1
1151
+ });
1152
+ }, false);
1153
+ return identifiers;
1154
+ }
1155
+ function applyContentReplacements(content, replacements) {
1156
+ replacements.sort((a, b) => b.start - a.start).forEach(({ start, end, content: replacement }) => {
1157
+ content = content.slice(0, start) + replacement + content.slice(end);
1158
+ });
1159
+ return content;
1160
+ }
960
1161
  function genDeclarations(declarations, context, shouldDeclare) {
961
1162
  const [frag, push] = buildCodeFragment();
962
1163
  const ids = Object.create(null);
@@ -984,9 +1185,6 @@ function genDeclarations(declarations, context, shouldDeclare) {
984
1185
  varNames: [...varNames]
985
1186
  };
986
1187
  }
987
- function escapeRegExp(string) {
988
- return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
989
- }
990
1188
  function parseExp(context, content) {
991
1189
  return (0, _babel_parser.parseExpression)(`(${content})`, getParserOptions(context.options.expressionPlugins));
992
1190
  }
@@ -1177,7 +1375,7 @@ function genFor(oper, context) {
1177
1375
  idMap[rawIndex] = `${indexVar}.value`;
1178
1376
  idMap[indexVar] = null;
1179
1377
  }
1180
- const { selectorPatterns, keyOnlyBindingPatterns } = matchPatterns(render, keyProp, idMap, context);
1378
+ const { selectorPatterns, keyOnlyBindingPatterns, skippedEffectIndexes } = matchPatterns(render, keyProp, idMap, context);
1181
1379
  const selectorDeclarations = [];
1182
1380
  const selectorName = (i) => selectorPatterns.length > 1 ? `_selector${id}_${i}` : `_selector${id}`;
1183
1381
  for (let i = 0; i < selectorPatterns.length; i++) {
@@ -1197,26 +1395,20 @@ function genFor(oper, context) {
1197
1395
  }
1198
1396
  for (const { effect } of keyOnlyBindingPatterns) for (const oper of effect.operations) patternFrag.push(...genOperation(oper, context));
1199
1397
  return patternFrag;
1200
- }));
1398
+ }, skippedEffectIndexes));
1201
1399
  else frag.push(...genBlockContent(render, context));
1202
1400
  frag.push(INDENT_END, NEWLINE, "}");
1203
1401
  return frag;
1204
1402
  }, idMap);
1205
1403
  exitScope();
1206
- let flags = 0;
1207
- if (onlyChild) flags |= 1;
1208
- if (component) flags |= 2;
1209
- if (isFragmentBlock(render)) flags |= 16;
1210
- if (!component && isSingleNodeBlock(render)) flags |= 8;
1211
- if (once) flags |= 4;
1212
- if (slotRoot) flags |= 32;
1404
+ const flags = genForFlags(onlyChild, component, isFragmentBlock(render), !component && isSingleNodeBlock(render), once, slotRoot);
1213
1405
  const onResetCalls = [];
1214
1406
  for (let i = 0; i < selectorPatterns.length; i++) onResetCalls.push(NEWLINE, `n${id}.onReset(${selectorName(i)}.reset)`);
1215
1407
  return [
1216
1408
  NEWLINE,
1217
1409
  ...selectorDeclarations,
1218
1410
  `const n${id} = `,
1219
- ...genCall([helper("createFor"), "undefined"], sourceExpr, blockFn, genCallback(keyProp), flags ? String(flags) : void 0),
1411
+ ...genCall([helper("createFor"), "undefined"], sourceExpr, blockFn, genCallback(keyProp), flags),
1220
1412
  ...onResetCalls
1221
1413
  ];
1222
1414
  function genCallback(expr) {
@@ -1241,6 +1433,36 @@ function genFor(oper, context) {
1241
1433
  return idMap;
1242
1434
  }
1243
1435
  }
1436
+ function genForFlags(onlyChild, component, isFragment, isSingleNode, once, slotRoot) {
1437
+ let flags = 0;
1438
+ const names = [];
1439
+ if (onlyChild) {
1440
+ flags |= 1;
1441
+ names.push("FAST_REMOVE");
1442
+ }
1443
+ if (component) {
1444
+ flags |= 2;
1445
+ names.push("IS_COMPONENT");
1446
+ }
1447
+ if (isFragment) {
1448
+ flags |= 16;
1449
+ names.push("IS_FRAGMENT");
1450
+ }
1451
+ if (isSingleNode) {
1452
+ flags |= 8;
1453
+ names.push("IS_SINGLE_NODE");
1454
+ }
1455
+ if (once) {
1456
+ flags |= 4;
1457
+ names.push("ONCE");
1458
+ }
1459
+ if (slotRoot) {
1460
+ flags |= 32;
1461
+ names.push("SLOT_ROOT");
1462
+ }
1463
+ if (!flags) return;
1464
+ return `${flags} /* ${names.join(", ")} */`;
1465
+ }
1244
1466
  function isSingleNodeBlock(block) {
1245
1467
  const child = getSingleReturnedChild(block);
1246
1468
  return !!child && child.template != null;
@@ -1327,39 +1549,35 @@ function buildDestructureIdMap(idToPathMap, baseAccessor, plugins) {
1327
1549
  function matchPatterns(render, keyProp, idMap, context) {
1328
1550
  const selectorPatterns = [];
1329
1551
  const keyOnlyBindingPatterns = [];
1330
- const removedEffectIndexes = [];
1331
- render.effect = render.effect.filter((effect, index) => {
1332
- if (keyProp !== void 0) {
1333
- const selector = matchSelectorPattern(effect, keyProp.content, idMap, context);
1334
- if (selector) {
1335
- selectorPatterns.push(selector);
1336
- removedEffectIndexes.push(index);
1337
- return false;
1338
- }
1339
- const keyOnly = matchKeyOnlyBindingPattern(effect, keyProp.content);
1340
- if (keyOnly) {
1341
- keyOnlyBindingPatterns.push(keyOnly);
1342
- removedEffectIndexes.push(index);
1343
- return false;
1344
- }
1552
+ let skippedEffectIndexes;
1553
+ if (keyProp === void 0) return {
1554
+ keyOnlyBindingPatterns,
1555
+ selectorPatterns,
1556
+ skippedEffectIndexes
1557
+ };
1558
+ for (let index = 0; index < render.effect.length; index++) {
1559
+ const effect = render.effect[index];
1560
+ const selector = matchSelectorPattern(effect, keyProp.content, idMap, context);
1561
+ if (selector) {
1562
+ selectorPatterns.push(selector);
1563
+ skipEffect(index);
1564
+ continue;
1345
1565
  }
1346
- return true;
1347
- });
1348
- if (removedEffectIndexes.length) shiftEffectBoundaries(render.dynamic, removedEffectIndexes);
1566
+ const keyOnly = matchKeyOnlyBindingPattern(effect, keyProp.content);
1567
+ if (keyOnly) {
1568
+ keyOnlyBindingPatterns.push(keyOnly);
1569
+ skipEffect(index);
1570
+ }
1571
+ }
1349
1572
  return {
1350
1573
  keyOnlyBindingPatterns,
1351
- selectorPatterns
1574
+ selectorPatterns,
1575
+ skippedEffectIndexes
1352
1576
  };
1353
- }
1354
- function shiftEffectBoundaries(dynamic, removedEffectIndexes) {
1355
- const operation = dynamic.operation;
1356
- if (operation && isBlockOperation(operation) && operation.effectIndex !== void 0) {
1357
- let offset = 0;
1358
- for (const removedIndex of removedEffectIndexes) if (removedIndex < operation.effectIndex) offset++;
1359
- else break;
1360
- operation.effectIndex -= offset;
1577
+ function skipEffect(index) {
1578
+ if (!skippedEffectIndexes) skippedEffectIndexes = /* @__PURE__ */ new Set();
1579
+ skippedEffectIndexes.add(index);
1361
1580
  }
1362
- for (const child of dynamic.children) shiftEffectBoundaries(child, removedEffectIndexes);
1363
1581
  }
1364
1582
  function matchKeyOnlyBindingPattern(effect, key) {
1365
1583
  if (effect.expressions.length === 1) {
@@ -1464,14 +1682,25 @@ function genIfFlags(blockShape, once, slotRoot, index) {
1464
1682
  return `${flags} /* ${genIfFlagNames(once, slotRoot, index, blockShape)} */`;
1465
1683
  }
1466
1684
  function genIfFlagNames(once, slotRoot, index, blockShape) {
1467
- const names = ["BLOCK_SHAPE"];
1685
+ const names = [`TRUE_${genBlockShapeName(blockShape)}`];
1686
+ const falseShape = blockShape >> 2;
1687
+ const hasFalseBranch = (falseShape & 3) !== 0;
1688
+ if (hasFalseBranch) names.push(`FALSE_${genBlockShapeName(falseShape)}`);
1468
1689
  if (blockShape & 32) names.push("TRUE_NO_SCOPE");
1469
- if (blockShape & 64) names.push("FALSE_NO_SCOPE");
1690
+ if (hasFalseBranch && blockShape & 64) names.push("FALSE_NO_SCOPE");
1470
1691
  if (once) names.push("ONCE");
1471
1692
  if (slotRoot) names.push("SLOT_ROOT");
1472
- if (!once && index !== void 0) names.push("INDEX_SHIFT");
1693
+ if (!once && index !== void 0) names.push(`KEYED_INDEX_${index}`);
1473
1694
  return names.join(", ");
1474
1695
  }
1696
+ function genBlockShapeName(flags) {
1697
+ switch (flags & 3) {
1698
+ case 0: return "EMPTY";
1699
+ case 1: return "SINGLE_ROOT";
1700
+ case 2: return "MULTI_ROOT";
1701
+ }
1702
+ return "UNKNOWN";
1703
+ }
1475
1704
  //#endregion
1476
1705
  //#region packages/compiler-vapor/src/generators/prop.ts
1477
1706
  const helpers = {
@@ -1653,7 +1882,12 @@ function genPropKey({ key: node, modifier, runtimeCamelize, handler, handlerModi
1653
1882
  if (runtimeCamelize) {
1654
1883
  key.push(" || \"\"");
1655
1884
  key = genCall(helper("camelize"), key);
1656
- }
1885
+ } else if (modifier) key = [
1886
+ "(",
1887
+ ...key,
1888
+ " || \"\"",
1889
+ ")"
1890
+ ];
1657
1891
  if (handler) key = genCall(helper("toHandlerKey"), key);
1658
1892
  return [
1659
1893
  "[",
@@ -1745,6 +1979,11 @@ function genVShow(oper, context) {
1745
1979
  ])];
1746
1980
  }
1747
1981
  //#endregion
1982
+ //#region packages/compiler-vapor/src/generators/modifier.ts
1983
+ function genDirectiveModifiers(modifiers) {
1984
+ return modifiers.map((value) => `${(0, _vue_compiler_dom.isSimpleIdentifier)(value) ? value : JSON.stringify(value)}: true`).join(", ");
1985
+ }
1986
+ //#endregion
1748
1987
  //#region packages/compiler-vapor/src/generators/vModel.ts
1749
1988
  const helperMap = {
1750
1989
  text: "applyTextModel",
@@ -1759,7 +1998,7 @@ function genVModel(oper, context) {
1759
1998
  `() => (`,
1760
1999
  ...genExpression(exp, context),
1761
2000
  `)`
1762
- ], genModelHandler(exp, context), modifiers.length ? `{ ${modifiers.map((e) => e.content + ": true").join(",")} }` : void 0)];
2001
+ ], genModelHandler(exp, context), modifiers.length ? `{ ${genDirectiveModifiers(modifiers.map((e) => e.content))} }` : void 0)];
1763
2002
  }
1764
2003
  function genModelHandler(exp, context) {
1765
2004
  return [
@@ -1801,14 +2040,15 @@ function genCustomDirectives(opers, context) {
1801
2040
  return genMulti(DELIMITERS_ARRAY.concat("void 0"), directiveVar, value, argument, modifiers);
1802
2041
  }
1803
2042
  }
1804
- function genDirectiveModifiers(modifiers) {
1805
- return modifiers.map((value) => `${(0, _vue_compiler_dom.isSimpleIdentifier)(value) ? value : JSON.stringify(value)}: true`).join(", ");
1806
- }
1807
2043
  function filterCustomDirectives(id, operations) {
1808
2044
  return operations.filter((oper) => oper.type === 14 && oper.element === id && !oper.builtin);
1809
2045
  }
1810
2046
  //#endregion
1811
2047
  //#region packages/compiler-vapor/src/generators/component.ts
2048
+ function genStaticModifierPropKey(name) {
2049
+ const key = (0, _vue_shared.getModifierPropName)(name);
2050
+ return [(0, _vue_compiler_dom.isSimpleIdentifier)(key) ? key : JSON.stringify(key)];
2051
+ }
1812
2052
  function genCreateComponent(operation, context) {
1813
2053
  const { helper } = context;
1814
2054
  const singleUseAssetComponentNames = context.singleUseAssetComponentNames;
@@ -1817,7 +2057,7 @@ function genCreateComponent(operation, context) {
1817
2057
  const tag = genTag();
1818
2058
  const { root, props, slots, once, slotRoot } = operation;
1819
2059
  const isRuntimeDynamicComponent = !!(operation.dynamic && !operation.dynamic.isStatic);
1820
- const dynamicComponentFlags = isRuntimeDynamicComponent ? (root ? 1 : 0) | (once ? 2 : 0) | (slotRoot ? 4 : 0) : 0;
2060
+ const dynamicComponentFlags = isRuntimeDynamicComponent ? genDynamicComponentFlags(root, once, slotRoot) : false;
1821
2061
  const rawSlots = genRawSlots(slots, context);
1822
2062
  const [ids, handlers] = processInlineHandlers(props, context);
1823
2063
  const rawProps = context.withId(() => genRawProps(props, context, true), ids);
@@ -1833,7 +2073,7 @@ function genCreateComponent(operation, context) {
1833
2073
  ];
1834
2074
  }, []),
1835
2075
  `const n${operation.id} = `,
1836
- ...genCall(isRuntimeDynamicComponent ? helper("createDynamicComponent") : operation.useCreateElement ? helper("createPlainElement") : useAssetComponentHelper ? helper("createAssetComponent") : operation.asset ? helper("createComponentWithFallback") : helper("createComponent"), tag, rawProps, rawSlots, isRuntimeDynamicComponent ? dynamicComponentFlags ? String(dynamicComponentFlags) : false : root ? "true" : false, isRuntimeDynamicComponent ? false : once && "true", isRuntimeDynamicComponent ? false : maybeSelfReference && "true"),
2076
+ ...genCall(isRuntimeDynamicComponent ? helper("createDynamicComponent") : operation.useCreateElement ? helper("createPlainElement") : useAssetComponentHelper ? helper("createAssetComponent") : operation.asset ? helper("createComponentWithFallback") : helper("createComponent"), tag, rawProps, rawSlots, isRuntimeDynamicComponent ? dynamicComponentFlags : root ? "true" : false, isRuntimeDynamicComponent ? false : once && "true", isRuntimeDynamicComponent ? false : maybeSelfReference && "true"),
1837
2077
  ...genDirectivesForElement(operation.id, context)
1838
2078
  ];
1839
2079
  function genTag() {
@@ -1859,6 +2099,24 @@ function genCreateComponent(operation, context) {
1859
2099
  }
1860
2100
  }
1861
2101
  }
2102
+ function genDynamicComponentFlags(root, once, slotRoot) {
2103
+ let flags = 0;
2104
+ const names = [];
2105
+ if (root) {
2106
+ flags |= 1;
2107
+ names.push("SINGLE_ROOT");
2108
+ }
2109
+ if (once) {
2110
+ flags |= 2;
2111
+ names.push("ONCE");
2112
+ }
2113
+ if (slotRoot) {
2114
+ flags |= 4;
2115
+ names.push("SLOT_ROOT");
2116
+ }
2117
+ if (!flags) return false;
2118
+ return `${flags} /* ${names.join(", ")} */`;
2119
+ }
1862
2120
  function getUniqueHandlerName(context, name) {
1863
2121
  const { seenInlineHandlerNames } = context;
1864
2122
  name = genVarName(name);
@@ -1950,7 +2208,7 @@ function genStaticProps(props, context, dynamicProps, directStaticLiteralProps =
1950
2208
  }
1951
2209
  const { key, modelModifiers } = prop;
1952
2210
  if (modelModifiers && modelModifiers.length) {
1953
- const modifiersKey = key.isStatic ? [(0, _vue_shared.getModifierPropName)(key.content)] : [
2211
+ const modifiersKey = key.isStatic ? genStaticModifierPropKey(key.content) : [
1954
2212
  "[",
1955
2213
  ...genExpression(key, context),
1956
2214
  " + \"Modifiers\"]"
@@ -1993,7 +2251,7 @@ function genDynamicProps(props, context, directStaticLiteralProps = false) {
1993
2251
  ]);
1994
2252
  const { modelModifiers } = p;
1995
2253
  if (modelModifiers && modelModifiers.length) {
1996
- const modifiersKey = p.key.isStatic ? [(0, _vue_shared.getModifierPropName)(p.key.content)] : [
2254
+ const modifiersKey = p.key.isStatic ? genStaticModifierPropKey(p.key.content) : [
1997
2255
  "[",
1998
2256
  ...genExpression(p.key, context),
1999
2257
  " + \"Modifiers\"]"
@@ -2118,7 +2376,7 @@ function genDynamicSlot(slot, context, withFunction = false) {
2118
2376
  }
2119
2377
  function genBasicDynamicSlot(slot, context) {
2120
2378
  const { name, fn } = slot;
2121
- return genMulti(DELIMITERS_OBJECT_NEWLINE, ["name: ", ...genExpression(name, context)], ["fn: ", ...genSlotBlockWithProps(fn, context)]);
2379
+ return genMulti(DELIMITERS_OBJECT_NEWLINE, ["name: ", ...genExpression(name, context)], ["fn: ", ...genSlotBlockWithProps(fn, context, false)]);
2122
2380
  }
2123
2381
  function genLoopSlot(slot, context) {
2124
2382
  const { name, fn, loop } = slot;
@@ -2130,7 +2388,7 @@ function genLoopSlot(slot, context) {
2130
2388
  if (rawValue) idMap[rawValue] = rawValue;
2131
2389
  if (rawKey) idMap[rawKey] = rawKey;
2132
2390
  if (rawIndex) idMap[rawIndex] = rawIndex;
2133
- const slotExpr = genMulti(DELIMITERS_OBJECT_NEWLINE, ["name: ", ...context.withId(() => genExpression(name, context), idMap)], ["fn: ", ...context.withId(() => genSlotBlockWithProps(fn, context), idMap)]);
2391
+ const slotExpr = genMulti(DELIMITERS_OBJECT_NEWLINE, ["name: ", ...context.withId(() => genExpression(name, context), idMap)], ["fn: ", ...context.withId(() => genSlotBlockWithProps(fn, context, false), idMap)]);
2134
2392
  return [...genCall(context.helper("createForSlots"), genExpression(source, context), [
2135
2393
  ...genMulti([
2136
2394
  "(",
@@ -2156,7 +2414,7 @@ function genConditionalSlot(slot, context) {
2156
2414
  INDENT_END
2157
2415
  ];
2158
2416
  }
2159
- function genSlotBlockWithProps(oper, context) {
2417
+ function genSlotBlockWithProps(oper, context, emitNonStableFlag = true) {
2160
2418
  let propsName;
2161
2419
  let exitScope;
2162
2420
  let depth;
@@ -2169,12 +2427,56 @@ function genSlotBlockWithProps(oper, context) {
2169
2427
  const idMap = idToPathMap.size ? buildDestructureIdMap(idToPathMap, propsName || "", context.options.expressionPlugins) : {};
2170
2428
  if (propsName) idMap[propsName] = null;
2171
2429
  const exitSlotBlock = context.enterSlotBlock();
2172
- markSlotRootOperations(oper);
2430
+ const hasStableRoot = hasStableSlotRoot(oper, context);
2431
+ if (!hasStableRoot) markSlotRootOperations(oper);
2173
2432
  let blockFn = context.withId(() => genBlock(oper, context, propsName ? [propsName] : []), idMap);
2433
+ if (emitNonStableFlag && !hasStableRoot) blockFn = genCall(context.helper("extend"), blockFn, [`{ _: ${genSlotFlags$1(8)} }`]);
2174
2434
  exitSlotBlock();
2175
2435
  exitScope && exitScope();
2176
2436
  return blockFn;
2177
2437
  }
2438
+ function genSlotFlags$1(flags) {
2439
+ const names = [];
2440
+ if (flags & 1) names.push("NO_SLOTTED");
2441
+ if (flags & 2) names.push("ONCE");
2442
+ if (flags & 4) names.push("SLOT_ROOT");
2443
+ if (flags & 8) names.push("NON_STABLE");
2444
+ return `${flags} /* ${names.join(", ")} */`;
2445
+ }
2446
+ const commentOnlyTemplateRE = /^(?:<!--[\s\S]*?-->)+$/;
2447
+ function hasStableSlotRoot(block, context) {
2448
+ let hasValidRoot = false;
2449
+ for (let i = 0; i < block.returns.length; i++) {
2450
+ const id = block.returns[i];
2451
+ const child = findReturnedDynamic$1(block, id);
2452
+ const operation = child && child.operation;
2453
+ if (!operation) {
2454
+ if (child && isStableTemplateSlotRoot(child, context)) hasValidRoot = true;
2455
+ continue;
2456
+ }
2457
+ switch (operation.type) {
2458
+ case 12:
2459
+ if (!operation.dynamic || operation.dynamic.isStatic) {
2460
+ hasValidRoot = true;
2461
+ continue;
2462
+ }
2463
+ continue;
2464
+ case 17:
2465
+ if (hasStableSlotRoot(operation.block, context)) {
2466
+ hasValidRoot = true;
2467
+ continue;
2468
+ }
2469
+ continue;
2470
+ default: continue;
2471
+ }
2472
+ }
2473
+ return hasValidRoot;
2474
+ }
2475
+ function isStableTemplateSlotRoot(child, context) {
2476
+ if (child.template == null) return false;
2477
+ const content = context.ir.template.entries[child.template].content;
2478
+ return content !== "" && !commentOnlyTemplateRE.test(content.trim());
2479
+ }
2178
2480
  //#endregion
2179
2481
  //#region packages/compiler-vapor/src/generators/slotOutlet.ts
2180
2482
  function genSlotOutlet(oper, context) {
@@ -2183,7 +2485,7 @@ function genSlotOutlet(oper, context) {
2183
2485
  const [frag, push] = buildCodeFragment();
2184
2486
  let fallbackArg;
2185
2487
  if (fallback) {
2186
- markSlotRootOperations(fallback);
2488
+ if (context.inSlotBlock) markSlotRootOperations(fallback);
2187
2489
  fallbackArg = genBlock(fallback, context);
2188
2490
  }
2189
2491
  const createSlot = helper("createSlot");
@@ -2193,9 +2495,17 @@ function genSlotOutlet(oper, context) {
2193
2495
  ...genExpression(name, context),
2194
2496
  ")"
2195
2497
  ];
2196
- push(NEWLINE, `const n${id} = `, ...genCall(createSlot, nameArg, rawPropsArg, fallbackArg, flags ? String(flags) : void 0));
2498
+ push(NEWLINE, `const n${id} = `, ...genCall(createSlot, nameArg, rawPropsArg, fallbackArg, genSlotFlags(flags)));
2197
2499
  return frag;
2198
2500
  }
2501
+ function genSlotFlags(flags) {
2502
+ if (!flags) return;
2503
+ const names = [];
2504
+ if (flags & 1) names.push("NO_SLOTTED");
2505
+ if (flags & 2) names.push("ONCE");
2506
+ if (flags & 4) names.push("SLOT_ROOT");
2507
+ return `${flags} /* ${names.join(", ")} */`;
2508
+ }
2199
2509
  //#endregion
2200
2510
  //#region packages/compiler-vapor/src/generators/key.ts
2201
2511
  function genKey(oper, context) {
@@ -2468,7 +2778,7 @@ function genBlock(oper, context, args = [], root) {
2468
2778
  "}"
2469
2779
  ];
2470
2780
  }
2471
- function genBlockContent(block, context, root, genEffectsExtraFrag) {
2781
+ function genBlockContent(block, context, root, genEffectsExtraFrag, skippedEffectIndexes) {
2472
2782
  const [frag, push] = buildCodeFragment();
2473
2783
  const { dynamic, effect, operation, returns } = block;
2474
2784
  const resetBlock = context.enterBlock(block);
@@ -2493,7 +2803,7 @@ function genBlockContent(block, context, root, genEffectsExtraFrag) {
2493
2803
  operationIndex++;
2494
2804
  }
2495
2805
  if (effectIndex < effectEnd) {
2496
- push(...genEffects(effect.slice(effectIndex, effectEnd), context));
2806
+ push(...genEffectRange(effectIndex, effectEnd));
2497
2807
  effectIndex = effectEnd;
2498
2808
  }
2499
2809
  };
@@ -2507,14 +2817,21 @@ function genBlockContent(block, context, root, genEffectsExtraFrag) {
2507
2817
  }
2508
2818
  for (const child of dynamic.children) if (!child.hasDynamicChild) push(...genChildren(child, context, push, `n${child.id}`, flushBeforeDynamic));
2509
2819
  if (operationIndex < operation.length) push(...genOperations(operation.slice(operationIndex), context));
2510
- if (effectIndex < effect.length) push(...genEffects(effect.slice(effectIndex), context, genEffectsExtraFrag));
2820
+ if (effectIndex < effect.length) push(...genEffectRange(effectIndex, effect.length, genEffectsExtraFrag));
2511
2821
  else if (genEffectsExtraFrag) push(...genEffects([], context, genEffectsExtraFrag));
2512
2822
  push(NEWLINE, `return `);
2513
2823
  const returnNodes = returns.map((n) => `n${n}`);
2514
- push(...returnNodes.length > 1 ? genMulti(DELIMITERS_ARRAY, ...returnNodes) : [returnNodes[0] || "null"]);
2824
+ push(...returnNodes.length > 1 ? genMulti(DELIMITERS_ARRAY, ...returnNodes) : [returnNodes[0] || "[]"]);
2515
2825
  resetBlock();
2516
2826
  context.singleUseAssetComponentNames = prevSingleUseAssetComponentNames;
2517
2827
  return frag;
2828
+ function genEffectRange(start, end, genExtraFrag) {
2829
+ if (!skippedEffectIndexes) return genEffects(effect.slice(start, end), context, genExtraFrag);
2830
+ const effects = [];
2831
+ for (let i = start; i < end; i++) if (!skippedEffectIndexes.has(i)) effects.push(effect[i]);
2832
+ if (effects.length || genExtraFrag) return genEffects(effects, context, genExtraFrag);
2833
+ return [];
2834
+ }
2518
2835
  function genResolveAssets(kind, helper) {
2519
2836
  for (const name of context.ir[kind]) push(NEWLINE, `const ${(0, _vue_compiler_dom.toValidAssetId)(name, kind)} = `, ...genCall(context.helper(helper), JSON.stringify(name)));
2520
2837
  }
@@ -2526,7 +2843,6 @@ function markSlotRootOperations(block) {
2526
2843
  if (!operation) continue;
2527
2844
  if (operation.type === 15) markSlotRootIf(operation);
2528
2845
  else if (operation.type === 16) markSlotRootFor(operation);
2529
- else if (operation.type === 13) markSlotRootSlotOutlet(operation);
2530
2846
  else if (operation.type === 12) markSlotRootComponent(operation);
2531
2847
  }
2532
2848
  }
@@ -2542,10 +2858,6 @@ function markSlotRootFor(operation) {
2542
2858
  if (!operation.once) operation.slotRoot = true;
2543
2859
  markSlotRootOperations(operation.render);
2544
2860
  }
2545
- function markSlotRootSlotOutlet(operation) {
2546
- operation.flags |= 4;
2547
- if (operation.fallback) markSlotRootOperations(operation.fallback);
2548
- }
2549
2861
  function markSlotRootComponent(operation) {
2550
2862
  if (!operation.once && operation.dynamic && !operation.dynamic.isStatic) operation.slotRoot = true;
2551
2863
  }
@@ -2850,11 +3162,36 @@ const transformVBind = (dir, node, context) => {
2850
3162
  };
2851
3163
  };
2852
3164
  //#endregion
3165
+ //#region packages/compiler-vapor/src/transforms/vHtml.ts
3166
+ function ignoreVHtmlChildren(node, context, clear) {
3167
+ if (!node.children.length) return;
3168
+ const dir = (0, _vue_compiler_dom.findDir)(node, "html");
3169
+ if (!dir) return;
3170
+ context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(55, dir.loc));
3171
+ if (clear === "node") node.children.length = 0;
3172
+ else context.childrenTemplate.length = 0;
3173
+ }
3174
+ const transformVHtml = (dir, node, context) => {
3175
+ let { exp, loc } = dir;
3176
+ if (!exp) {
3177
+ context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(54, loc));
3178
+ exp = EMPTY_EXPRESSION;
3179
+ }
3180
+ ignoreVHtmlChildren(node, context, "template");
3181
+ context.registerEffect([exp], {
3182
+ type: 8,
3183
+ element: context.reference(),
3184
+ value: exp,
3185
+ isComponent: node.tagType === 1
3186
+ });
3187
+ };
3188
+ //#endregion
2853
3189
  //#region packages/compiler-vapor/src/transforms/transformElement.ts
2854
3190
  const isReservedProp = /* @__PURE__ */ (0, _vue_shared.makeMap)(",key,ref,ref_for,ref_key,");
2855
3191
  const transformElement = (node, context) => {
2856
3192
  let effectIndex = context.block.effect.length;
2857
3193
  const getEffectIndex = () => effectIndex++;
3194
+ if (node.type === 1 && node.children.length) ignoreVHtmlChildren(node, context, "node");
2858
3195
  let parentSlots;
2859
3196
  if (node.type === 1 && (node.tagType === 1 || context.options.isCustomElement(node.tag))) {
2860
3197
  parentSlots = context.slots;
@@ -2868,7 +3205,7 @@ const transformElement = (node, context) => {
2868
3205
  const isDynamicComponent = isComponentTag(node.tag);
2869
3206
  const staticKey = resolveStaticKey(node, context, isComponent);
2870
3207
  const propsResult = buildProps(node, context, isComponent, isDynamicComponent, getEffectIndex);
2871
- const singleRoot = isSingleRoot(context);
3208
+ const singleRoot = context.isSingleRoot;
2872
3209
  if (isComponent) transformComponentElement(node, propsResult, staticKey, singleRoot, context, isDynamicComponent, useCreateElement);
2873
3210
  else transformNativeElement(node, propsResult, staticKey, singleRoot, context, getEffectIndex, context.root === context.effectiveParent || canOmitEndTag(node, context));
2874
3211
  if (parentSlots) context.slots = parentSlots;
@@ -2907,16 +3244,6 @@ function isInSameTemplateAsParent(context) {
2907
3244
  if (parentNode.type !== 1 || parentNode.tagType !== 0) return false;
2908
3245
  return !shouldUseCreateElement(parentNode, parent) && (0, _vue_compiler_dom.isValidHTMLNesting)(parentNode.tag, node.tag);
2909
3246
  }
2910
- function isSingleRoot(context) {
2911
- if (context.inVFor) return false;
2912
- let { parent } = context;
2913
- if (parent && !((0, _vue_compiler_dom.hasSingleChild)(parent.node) || (0, _vue_compiler_dom.isSingleIfBlock)(parent.node))) return false;
2914
- while (parent && parent.parent && parent.node.type === 1 && parent.node.tagType === 3) {
2915
- parent = parent.parent;
2916
- if (!((0, _vue_compiler_dom.hasSingleChild)(parent.node) || (0, _vue_compiler_dom.isSingleIfBlock)(parent.node))) return false;
2917
- }
2918
- return context.root === parent;
2919
- }
2920
3247
  function transformComponentElement(node, propsResult, staticKey, singleRoot, context, isDynamicComponent, useCreateElement) {
2921
3248
  const dynamicComponent = isDynamicComponent ? resolveDynamicComponent(node) : void 0;
2922
3249
  let { tag } = node;
@@ -3005,17 +3332,18 @@ function transformNativeElement(node, propsResult, staticKey, singleRoot, contex
3005
3332
  };
3006
3333
  for (const prop of propsResult[1]) {
3007
3334
  const { key, values } = prop;
3335
+ const canStringifyAttrName = key.isStatic && !UNSAFE_ATTR_NAME_RE.test(key.content);
3008
3336
  let foldedValue;
3009
- if (context.imports.some((imported) => values[0].content.includes(imported.exp.content))) {
3337
+ if (canStringifyAttrName && context.imports.some((imported) => values[0].content.includes(imported.exp.content))) {
3010
3338
  if (!prevWasQuoted) template += ` `;
3011
3339
  template += `${key.content}="${IMPORT_EXP_START}${values[0].content}${IMPORT_EXP_END}"`;
3012
3340
  prevWasQuoted = true;
3013
- } else if (key.isStatic && values.length === 1 && (values[0].isStatic || values[0].content === "''") && !dynamicKeys.includes(key.content)) {
3341
+ } else if (canStringifyAttrName && values.length === 1 && (values[0].isStatic || values[0].content === "''") && !dynamicKeys.includes(key.content)) {
3014
3342
  const value = values[0].content === "''" ? "" : values[0].content;
3015
3343
  appendTemplateProp(key.content, value);
3016
- } else if (key.isStatic && !prop.modifier && (0, _vue_shared.isBooleanAttr)(key.content) && (foldedValue = foldBooleanAttrValue(values)) != null) {
3344
+ } else if (canStringifyAttrName && !prop.modifier && (0, _vue_shared.isBooleanAttr)(key.content) && (foldedValue = foldBooleanAttrValue(values)) != null) {
3017
3345
  if (foldedValue) appendTemplateProp(key.content);
3018
- } else if (key.isStatic && !prop.modifier && hasBoundValue(values) && (foldedValue = key.content === "class" ? foldClassValues(values) : key.content === "style" ? foldStyleValues(values) : void 0) != null) {
3346
+ } else if (canStringifyAttrName && !prop.modifier && hasBoundValue(values) && (foldedValue = key.content === "class" ? foldClassValues(values) : key.content === "style" ? foldStyleValues(values) : void 0) != null) {
3019
3347
  if (foldedValue) appendTemplateProp(key.content, foldedValue, true);
3020
3348
  } else context.registerEffect(values, {
3021
3349
  type: 3,
@@ -3535,25 +3863,6 @@ const transformVOnce = (node, context) => {
3535
3863
  if (node.type === 1 && (0, _vue_compiler_dom.findDir)(node, "once", true)) context.inVOnce = true;
3536
3864
  };
3537
3865
  //#endregion
3538
- //#region packages/compiler-vapor/src/transforms/vHtml.ts
3539
- const transformVHtml = (dir, node, context) => {
3540
- let { exp, loc } = dir;
3541
- if (!exp) {
3542
- context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(54, loc));
3543
- exp = EMPTY_EXPRESSION;
3544
- }
3545
- if (node.children.length) {
3546
- context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(55, loc));
3547
- context.childrenTemplate.length = 0;
3548
- }
3549
- context.registerEffect([exp], {
3550
- type: 8,
3551
- element: context.reference(),
3552
- value: exp,
3553
- isComponent: node.tagType === 1
3554
- });
3555
- };
3556
- //#endregion
3557
3866
  //#region packages/shared/src/makeMap.ts
3558
3867
  /**
3559
3868
  * Make a map and return a function for checking if a key
@@ -3619,13 +3928,7 @@ const transformText = (node, context) => {
3619
3928
  };
3620
3929
  function processInterpolation(context) {
3621
3930
  const parentNode = context.parent.node;
3622
- const children = parentNode.children;
3623
- const nexts = children.slice(context.index);
3624
- const idx = nexts.findIndex((n) => !isTextLike(n));
3625
- const nodes = idx > -1 ? nexts.slice(0, idx) : nexts;
3626
- const prev = children[context.index - 1];
3627
- if (prev && prev.type === 2) nodes.unshift(prev);
3628
- const values = processTextLikeChildren(nodes, context);
3931
+ const values = processTextLikeChildren(collectAdjacentText(context), context);
3629
3932
  if (values.length === 0 && parentNode.type !== 0) return;
3630
3933
  const literalValues = values.map((v) => getLiteralExpressionValue(v));
3631
3934
  if (literalValues.every((v) => v != null) && parentNode.type !== 0) {
@@ -3647,6 +3950,18 @@ function processInterpolation(context) {
3647
3950
  values
3648
3951
  });
3649
3952
  }
3953
+ function collectAdjacentText(context) {
3954
+ const children = context.parent.node.children;
3955
+ const nodes = [];
3956
+ const prev = children[context.index - 1];
3957
+ let index = prev && prev.type === 2 ? context.index - 1 : context.index;
3958
+ for (; index < children.length; index++) {
3959
+ const child = children[index];
3960
+ if (!isTextLike(child)) break;
3961
+ nodes.push(child);
3962
+ }
3963
+ return nodes;
3964
+ }
3650
3965
  function processTextContainer(children, context) {
3651
3966
  const values = processTextLikeChildren(children, context);
3652
3967
  const literals = values.map((value) => getLiteralExpressionValue(value));
@@ -4195,7 +4510,7 @@ function createFallback(node, context) {
4195
4510
  //#region packages/compiler-vapor/src/transforms/vSlot.ts
4196
4511
  const transformVSlot = (node, context) => {
4197
4512
  if (node.type !== 1) return;
4198
- const dir = findDir$2(node, "slot", true);
4513
+ const dir = findDir$4(node, "slot", true);
4199
4514
  const { tagType, children } = node;
4200
4515
  const { parent } = context;
4201
4516
  const isComponent = tagType === 1;
@@ -4246,9 +4561,9 @@ function transformTemplateSlot(node, dir, context) {
4246
4561
  const resolvedArg = dir.arg && resolveExpression(dir.arg);
4247
4562
  let arg = resolvedArg;
4248
4563
  if (!arg) arg = (0, _vue_compiler_dom.createSimpleExpression)("default", true);
4249
- const vFor = findDir$2(node, "for");
4250
- const vIf = findDir$2(node, "if");
4251
- const vElse = findDir$2(node, /^else(-if)?$/, true);
4564
+ const vFor = findDir$4(node, "for");
4565
+ const vIf = findDir$4(node, "if");
4566
+ const vElse = findDir$4(node, /^else(-if)?$/, true);
4252
4567
  const { slots } = context;
4253
4568
  const [block, onExit] = createSlotBlock(node, dir, context);
4254
4569
  if (!vFor && !vIf && !vElse) {
@@ -4266,7 +4581,7 @@ function transformTemplateSlot(node, dir, context) {
4266
4581
  });
4267
4582
  else if (vElse) {
4268
4583
  const vIfSlot = slots[slots.length - 1];
4269
- if (vIfSlot.slotType === 3) {
4584
+ if (vIfSlot && vIfSlot.slotType === 3) {
4270
4585
  let ifNode = vIfSlot;
4271
4586
  while (ifNode.negative && ifNode.negative.slotType === 3) ifNode = ifNode.negative;
4272
4587
  const negative = vElse.exp ? {
@@ -4329,7 +4644,7 @@ function isNonWhitespaceContent(node) {
4329
4644
  return !!node.content.trim();
4330
4645
  }
4331
4646
  function isSlotTemplateChild(node) {
4332
- return node.type === 1 && (0, _vue_compiler_dom.isTemplateNode)(node) && !!findDir$2(node, "slot", true);
4647
+ return node.type === 1 && (0, _vue_compiler_dom.isTemplateNode)(node) && !!findDir$4(node, "slot", true);
4333
4648
  }
4334
4649
  //#endregion
4335
4650
  //#region packages/compiler-vapor/src/transforms/transformTransition.ts
@@ -4342,17 +4657,17 @@ function hasMultipleChildren(node) {
4342
4657
  const children = node.children = node.children.filter((c) => c.type !== 3 && !(c.type === 2 && !c.content.trim()));
4343
4658
  const first = children[0];
4344
4659
  if (children.length === 1 && first.type === 1) {
4345
- if (findDir$2(first, "for")) return true;
4660
+ if (findDir$4(first, "for")) return true;
4346
4661
  if ((0, _vue_compiler_dom.isTemplateNode)(first)) return hasMultipleChildren(first);
4347
4662
  }
4348
- const hasElse = (node) => findDir$2(node, "else-if") || findDir$2(node, "else", true);
4349
- if (children.length > 0 && children.every((c, index) => c.type === 1 && (!(0, _vue_compiler_dom.isTemplateNode)(c) || !hasMultipleChildren(c)) && !findDir$2(c, "for") && (index === 0 ? findDir$2(c, "if") : hasElse(c)))) return false;
4663
+ const hasElse = (node) => findDir$4(node, "else-if") || findDir$4(node, "else", true);
4664
+ if (children.length > 0 && children.every((c, index) => c.type === 1 && (!(0, _vue_compiler_dom.isTemplateNode)(c) || !hasMultipleChildren(c)) && !findDir$4(c, "for") && (index === 0 ? findDir$4(c, "if") : hasElse(c)))) return false;
4350
4665
  return children.length !== 1;
4351
4666
  }
4352
4667
  //#endregion
4353
4668
  //#region packages/compiler-vapor/src/transforms/transformKey.ts
4354
4669
  const transformKey = (node, context) => {
4355
- if (node.type !== 1 || context.inVOnce || findDir$2(node, "for")) return;
4670
+ if (node.type !== 1 || context.inVOnce || findDir$4(node, "for")) return;
4356
4671
  const dir = findProp$1(node, "key", true, true);
4357
4672
  if (!dir || dir.type === 6) return;
4358
4673
  let value;