@vue/compat 3.2.39 → 3.2.40

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.
@@ -38,6 +38,13 @@ const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED);
38
38
  */
39
39
  const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;
40
40
  const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs);
41
+ /**
42
+ * The full list is needed during SSR to produce the correct initial markup.
43
+ */
44
+ const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs +
45
+ `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` +
46
+ `loop,open,required,reversed,scoped,seamless,` +
47
+ `checked,muted,multiple,selected`);
41
48
  /**
42
49
  * Boolean attributes should be included if the value is truthy or ''.
43
50
  * e.g. `<select multiple>` compiles to `{ multiple: '' }`
@@ -3977,7 +3984,7 @@ function injectHook(type, hook, target = currentInstance, prepend = false) {
3977
3984
  const createHook = (lifecycle) => (hook, target = currentInstance) =>
3978
3985
  // post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
3979
3986
  (!isInSSRComponentSetup || lifecycle === "sp" /* LifecycleHooks.SERVER_PREFETCH */) &&
3980
- injectHook(lifecycle, hook, target);
3987
+ injectHook(lifecycle, (...args) => hook(...args), target);
3981
3988
  const onBeforeMount = createHook("bm" /* LifecycleHooks.BEFORE_MOUNT */);
3982
3989
  const onMounted = createHook("m" /* LifecycleHooks.MOUNTED */);
3983
3990
  const onBeforeUpdate = createHook("bu" /* LifecycleHooks.BEFORE_UPDATE */);
@@ -4509,7 +4516,10 @@ function createSlots(slots, dynamicSlots) {
4509
4516
  slots[slot.name] = slot.key
4510
4517
  ? (...args) => {
4511
4518
  const res = slot.fn(...args);
4512
- res.key = slot.key;
4519
+ // attach branch key so each conditional branch is considered a
4520
+ // different fragment
4521
+ if (res)
4522
+ res.key = slot.key;
4513
4523
  return res;
4514
4524
  }
4515
4525
  : slot.fn;
@@ -5874,7 +5884,7 @@ function createCompatVue(createApp, createSingletonApp) {
5874
5884
  return vm;
5875
5885
  }
5876
5886
  }
5877
- Vue.version = `2.6.14-compat:${"3.2.39"}`;
5887
+ Vue.version = `2.6.14-compat:${"3.2.40"}`;
5878
5888
  Vue.config = singletonApp.config;
5879
5889
  Vue.use = (p, ...options) => {
5880
5890
  if (p && isFunction(p.install)) {
@@ -6475,7 +6485,7 @@ function createHydrationFunctions(rendererInternals) {
6475
6485
  const isFragmentStart = isComment(node) && node.data === '[';
6476
6486
  const onMismatch = () => handleMismatch(node, vnode, parentComponent, parentSuspense, slotScopeIds, isFragmentStart);
6477
6487
  const { type, ref, shapeFlag, patchFlag } = vnode;
6478
- const domType = node.nodeType;
6488
+ let domType = node.nodeType;
6479
6489
  vnode.el = node;
6480
6490
  if (patchFlag === -2 /* PatchFlags.BAIL */) {
6481
6491
  optimized = false;
@@ -6512,10 +6522,12 @@ function createHydrationFunctions(rendererInternals) {
6512
6522
  }
6513
6523
  break;
6514
6524
  case Static:
6515
- if (domType !== 1 /* DOMNodeTypes.ELEMENT */ && domType !== 3 /* DOMNodeTypes.TEXT */) {
6516
- nextNode = onMismatch();
6525
+ if (isFragmentStart) {
6526
+ // entire template is static but SSRed as a fragment
6527
+ node = nextSibling(node);
6528
+ domType = node.nodeType;
6517
6529
  }
6518
- else {
6530
+ if (domType === 1 /* DOMNodeTypes.ELEMENT */ || domType === 3 /* DOMNodeTypes.TEXT */) {
6519
6531
  // determine anchor, adopt content
6520
6532
  nextNode = node;
6521
6533
  // if the static vnode has its content stripped during build,
@@ -6532,7 +6544,10 @@ function createHydrationFunctions(rendererInternals) {
6532
6544
  }
6533
6545
  nextNode = nextSibling(nextNode);
6534
6546
  }
6535
- return nextNode;
6547
+ return isFragmentStart ? nextSibling(nextNode) : nextNode;
6548
+ }
6549
+ else {
6550
+ onMismatch();
6536
6551
  }
6537
6552
  break;
6538
6553
  case Fragment:
@@ -6794,7 +6809,7 @@ function createHydrationRenderer(options) {
6794
6809
  function baseCreateRenderer(options, createHydrationFns) {
6795
6810
  const target = getGlobalThis();
6796
6811
  target.__VUE__ = true;
6797
- const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options;
6812
+ const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, insertStaticContent: hostInsertStaticContent } = options;
6798
6813
  // Note: functions inside this closure should use `const xxx = () => {}`
6799
6814
  // style in order to prevent being inlined by minifiers.
6800
6815
  const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, slotScopeIds = null, optimized = !!n2.dynamicChildren) => {
@@ -6900,55 +6915,44 @@ function baseCreateRenderer(options, createHydrationFns) {
6900
6915
  const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized) => {
6901
6916
  let el;
6902
6917
  let vnodeHook;
6903
- const { type, props, shapeFlag, transition, patchFlag, dirs } = vnode;
6904
- if (vnode.el &&
6905
- hostCloneNode !== undefined &&
6906
- patchFlag === -1 /* PatchFlags.HOISTED */) {
6907
- // If a vnode has non-null el, it means it's being reused.
6908
- // Only static vnodes can be reused, so its mounted DOM nodes should be
6909
- // exactly the same, and we can simply do a clone here.
6910
- // only do this in production since cloned trees cannot be HMR updated.
6911
- el = vnode.el = hostCloneNode(vnode.el);
6918
+ const { type, props, shapeFlag, transition, dirs } = vnode;
6919
+ el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is, props);
6920
+ // mount children first, since some props may rely on child content
6921
+ // being already rendered, e.g. `<select value>`
6922
+ if (shapeFlag & 8 /* ShapeFlags.TEXT_CHILDREN */) {
6923
+ hostSetElementText(el, vnode.children);
6912
6924
  }
6913
- else {
6914
- el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is, props);
6915
- // mount children first, since some props may rely on child content
6916
- // being already rendered, e.g. `<select value>`
6917
- if (shapeFlag & 8 /* ShapeFlags.TEXT_CHILDREN */) {
6918
- hostSetElementText(el, vnode.children);
6919
- }
6920
- else if (shapeFlag & 16 /* ShapeFlags.ARRAY_CHILDREN */) {
6921
- mountChildren(vnode.children, el, null, parentComponent, parentSuspense, isSVG && type !== 'foreignObject', slotScopeIds, optimized);
6922
- }
6923
- if (dirs) {
6924
- invokeDirectiveHook(vnode, null, parentComponent, 'created');
6925
- }
6926
- // props
6927
- if (props) {
6928
- for (const key in props) {
6929
- if (key !== 'value' && !isReservedProp(key)) {
6930
- hostPatchProp(el, key, null, props[key], isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
6931
- }
6932
- }
6933
- /**
6934
- * Special case for setting value on DOM elements:
6935
- * - it can be order-sensitive (e.g. should be set *after* min/max, #2325, #4024)
6936
- * - it needs to be forced (#1471)
6937
- * #2353 proposes adding another renderer option to configure this, but
6938
- * the properties affects are so finite it is worth special casing it
6939
- * here to reduce the complexity. (Special casing it also should not
6940
- * affect non-DOM renderers)
6941
- */
6942
- if ('value' in props) {
6943
- hostPatchProp(el, 'value', null, props.value);
6944
- }
6945
- if ((vnodeHook = props.onVnodeBeforeMount)) {
6946
- invokeVNodeHook(vnodeHook, parentComponent, vnode);
6947
- }
6948
- }
6949
- // scopeId
6950
- setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent);
6925
+ else if (shapeFlag & 16 /* ShapeFlags.ARRAY_CHILDREN */) {
6926
+ mountChildren(vnode.children, el, null, parentComponent, parentSuspense, isSVG && type !== 'foreignObject', slotScopeIds, optimized);
6927
+ }
6928
+ if (dirs) {
6929
+ invokeDirectiveHook(vnode, null, parentComponent, 'created');
6951
6930
  }
6931
+ // props
6932
+ if (props) {
6933
+ for (const key in props) {
6934
+ if (key !== 'value' && !isReservedProp(key)) {
6935
+ hostPatchProp(el, key, null, props[key], isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
6936
+ }
6937
+ }
6938
+ /**
6939
+ * Special case for setting value on DOM elements:
6940
+ * - it can be order-sensitive (e.g. should be set *after* min/max, #2325, #4024)
6941
+ * - it needs to be forced (#1471)
6942
+ * #2353 proposes adding another renderer option to configure this, but
6943
+ * the properties affects are so finite it is worth special casing it
6944
+ * here to reduce the complexity. (Special casing it also should not
6945
+ * affect non-DOM renderers)
6946
+ */
6947
+ if ('value' in props) {
6948
+ hostPatchProp(el, 'value', null, props.value);
6949
+ }
6950
+ if ((vnodeHook = props.onVnodeBeforeMount)) {
6951
+ invokeVNodeHook(vnodeHook, parentComponent, vnode);
6952
+ }
6953
+ }
6954
+ // scopeId
6955
+ setScopeId(el, vnode, vnode.scopeId, slotScopeIds, parentComponent);
6952
6956
  if (dirs) {
6953
6957
  invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount');
6954
6958
  }
@@ -7110,6 +7114,13 @@ function baseCreateRenderer(options, createHydrationFns) {
7110
7114
  };
7111
7115
  const patchProps = (el, vnode, oldProps, newProps, parentComponent, parentSuspense, isSVG) => {
7112
7116
  if (oldProps !== newProps) {
7117
+ if (oldProps !== EMPTY_OBJ) {
7118
+ for (const key in oldProps) {
7119
+ if (!isReservedProp(key) && !(key in newProps)) {
7120
+ hostPatchProp(el, key, oldProps[key], null, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
7121
+ }
7122
+ }
7123
+ }
7113
7124
  for (const key in newProps) {
7114
7125
  // empty string is not valid prop
7115
7126
  if (isReservedProp(key))
@@ -7121,13 +7132,6 @@ function baseCreateRenderer(options, createHydrationFns) {
7121
7132
  hostPatchProp(el, key, prev, next, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
7122
7133
  }
7123
7134
  }
7124
- if (oldProps !== EMPTY_OBJ) {
7125
- for (const key in oldProps) {
7126
- if (!isReservedProp(key) && !(key in newProps)) {
7127
- hostPatchProp(el, key, oldProps[key], null, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
7128
- }
7129
- }
7130
- }
7131
7135
  if ('value' in newProps) {
7132
7136
  hostPatchProp(el, 'value', oldProps.value, newProps.value);
7133
7137
  }
@@ -8563,7 +8567,10 @@ function normalizeVNode(child) {
8563
8567
  }
8564
8568
  // optimized normalization for template-compiled render fns
8565
8569
  function cloneIfMounted(child) {
8566
- return child.el === null || child.memo ? child : cloneVNode(child);
8570
+ return (child.el === null && child.patchFlag !== -1 /* PatchFlags.HOISTED */) ||
8571
+ child.memo
8572
+ ? child
8573
+ : cloneVNode(child);
8567
8574
  }
8568
8575
  function normalizeChildren(vnode, children) {
8569
8576
  let type = 0;
@@ -9179,7 +9186,7 @@ function isMemoSame(cached, memo) {
9179
9186
  }
9180
9187
 
9181
9188
  // Core API ------------------------------------------------------------------
9182
- const version = "3.2.39";
9189
+ const version = "3.2.40";
9183
9190
  const _ssrUtils = {
9184
9191
  createComponentInstance,
9185
9192
  setupComponent,
@@ -9245,22 +9252,6 @@ const nodeOps = {
9245
9252
  setScopeId(el, id) {
9246
9253
  el.setAttribute(id, '');
9247
9254
  },
9248
- cloneNode(el) {
9249
- const cloned = el.cloneNode(true);
9250
- // #3072
9251
- // - in `patchDOMProp`, we store the actual value in the `el._value` property.
9252
- // - normally, elements using `:value` bindings will not be hoisted, but if
9253
- // the bound value is a constant, e.g. `:value="true"` - they do get
9254
- // hoisted.
9255
- // - in production, hoisted nodes are cloned when subsequent inserts, but
9256
- // cloneNode() does not copy the custom property we attached.
9257
- // - This may need to account for other custom DOM properties we attach to
9258
- // elements in addition to `_value` in the future.
9259
- if (`_value` in el) {
9260
- cloned._value = el._value;
9261
- }
9262
- return cloned;
9263
- },
9264
9255
  // __UNSAFE__
9265
9256
  // Reason: innerHTML.
9266
9257
  // Static content here can only come from compiled templates.
@@ -9431,14 +9422,14 @@ const isEnumeratedAttr = /*#__PURE__*/ makeMap('contenteditable,draggable,spellc
9431
9422
  ;
9432
9423
  function compatCoerceAttr(el, key, value, instance = null) {
9433
9424
  if (isEnumeratedAttr(key)) {
9434
- const v2CocercedValue = value === null
9425
+ const v2CoercedValue = value === null
9435
9426
  ? 'false'
9436
9427
  : typeof value !== 'boolean' && value !== undefined
9437
9428
  ? 'true'
9438
9429
  : null;
9439
- if (v2CocercedValue &&
9440
- compatUtils.softAssertCompatEnabled("ATTR_ENUMERATED_COERCION" /* DeprecationTypes.ATTR_ENUMERATED_COERCION */, instance, key, value, v2CocercedValue)) {
9441
- el.setAttribute(key, v2CocercedValue);
9430
+ if (v2CoercedValue &&
9431
+ compatUtils.softAssertCompatEnabled("ATTR_ENUMERATED_COERCION" /* DeprecationTypes.ATTR_ENUMERATED_COERCION */, instance, key, value, v2CoercedValue)) {
9432
+ el.setAttribute(key, v2CoercedValue);
9442
9433
  return true;
9443
9434
  }
9444
9435
  }
@@ -9499,7 +9490,6 @@ prevChildren, parentComponent, parentSuspense, unmountChildren) {
9499
9490
  }
9500
9491
  else if (type === 'number') {
9501
9492
  // e.g. <img :width="null">
9502
- // the value of some IDL attr must be greater than 0, e.g. input.size = 0 -> error
9503
9493
  value = 0;
9504
9494
  needRemove = true;
9505
9495
  }
@@ -11787,34 +11777,42 @@ function parseChildren(context, mode, ancestors) {
11787
11777
  const shouldCondense = context.options.whitespace !== 'preserve';
11788
11778
  for (let i = 0; i < nodes.length; i++) {
11789
11779
  const node = nodes[i];
11790
- if (!context.inPre && node.type === 2 /* NodeTypes.TEXT */) {
11791
- if (!/[^\t\r\n\f ]/.test(node.content)) {
11792
- const prev = nodes[i - 1];
11793
- const next = nodes[i + 1];
11794
- // Remove if:
11795
- // - the whitespace is the first or last node, or:
11796
- // - (condense mode) the whitespace is adjacent to a comment, or:
11797
- // - (condense mode) the whitespace is between two elements AND contains newline
11798
- if (!prev ||
11799
- !next ||
11800
- (shouldCondense &&
11801
- (prev.type === 3 /* NodeTypes.COMMENT */ ||
11802
- next.type === 3 /* NodeTypes.COMMENT */ ||
11803
- (prev.type === 1 /* NodeTypes.ELEMENT */ &&
11804
- next.type === 1 /* NodeTypes.ELEMENT */ &&
11805
- /[\r\n]/.test(node.content))))) {
11806
- removedWhitespace = true;
11807
- nodes[i] = null;
11780
+ if (node.type === 2 /* NodeTypes.TEXT */) {
11781
+ if (!context.inPre) {
11782
+ if (!/[^\t\r\n\f ]/.test(node.content)) {
11783
+ const prev = nodes[i - 1];
11784
+ const next = nodes[i + 1];
11785
+ // Remove if:
11786
+ // - the whitespace is the first or last node, or:
11787
+ // - (condense mode) the whitespace is adjacent to a comment, or:
11788
+ // - (condense mode) the whitespace is between two elements AND contains newline
11789
+ if (!prev ||
11790
+ !next ||
11791
+ (shouldCondense &&
11792
+ (prev.type === 3 /* NodeTypes.COMMENT */ ||
11793
+ next.type === 3 /* NodeTypes.COMMENT */ ||
11794
+ (prev.type === 1 /* NodeTypes.ELEMENT */ &&
11795
+ next.type === 1 /* NodeTypes.ELEMENT */ &&
11796
+ /[\r\n]/.test(node.content))))) {
11797
+ removedWhitespace = true;
11798
+ nodes[i] = null;
11799
+ }
11800
+ else {
11801
+ // Otherwise, the whitespace is condensed into a single space
11802
+ node.content = ' ';
11803
+ }
11808
11804
  }
11809
- else {
11810
- // Otherwise, the whitespace is condensed into a single space
11811
- node.content = ' ';
11805
+ else if (shouldCondense) {
11806
+ // in condense mode, consecutive whitespaces in text are condensed
11807
+ // down to a single space.
11808
+ node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');
11812
11809
  }
11813
11810
  }
11814
- else if (shouldCondense) {
11815
- // in condense mode, consecutive whitespaces in text are condensed
11816
- // down to a single space.
11817
- node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');
11811
+ else {
11812
+ // #6410 normalize windows newlines in <pre>:
11813
+ // in SSR, browsers normalize server-rendered \r\n into a single \n
11814
+ // in the DOM
11815
+ node.content = node.content.replace(/\r\n/g, '\n');
11818
11816
  }
11819
11817
  }
11820
11818
  // Remove comment nodes if desired by configuration.
@@ -12479,11 +12477,6 @@ function walk$1(node, context, doNotHoistNode = false) {
12479
12477
  }
12480
12478
  }
12481
12479
  }
12482
- else if (child.type === 12 /* NodeTypes.TEXT_CALL */ &&
12483
- getConstantType(child.content, context) >= 2 /* ConstantTypes.CAN_HOIST */) {
12484
- child.codegenNode = context.hoist(child.codegenNode);
12485
- hoistedCount++;
12486
- }
12487
12480
  // walk further
12488
12481
  if (child.type === 1 /* NodeTypes.ELEMENT */) {
12489
12482
  const isComponent = child.tagType === 1 /* ElementTypes.COMPONENT */;
@@ -15289,6 +15282,14 @@ function buildProps(node, context, props = node.props, isComponent, isDynamicCom
15289
15282
  let hasDynamicKeys = false;
15290
15283
  let hasVnodeHook = false;
15291
15284
  const dynamicPropNames = [];
15285
+ const pushMergeArg = (arg) => {
15286
+ if (properties.length) {
15287
+ mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));
15288
+ properties = [];
15289
+ }
15290
+ if (arg)
15291
+ mergeArgs.push(arg);
15292
+ };
15292
15293
  const analyzePatchFlag = ({ key, value }) => {
15293
15294
  if (isStaticExp(key)) {
15294
15295
  const name = key.content;
@@ -15410,11 +15411,9 @@ function buildProps(node, context, props = node.props, isComponent, isDynamicCom
15410
15411
  if (!arg && (isVBind || isVOn)) {
15411
15412
  hasDynamicKeys = true;
15412
15413
  if (exp) {
15413
- if (properties.length) {
15414
- mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));
15415
- properties = [];
15416
- }
15417
15414
  if (isVBind) {
15415
+ // have to merge early for compat build check
15416
+ pushMergeArg();
15418
15417
  {
15419
15418
  if (isCompatEnabled$1("COMPILER_V_BIND_OBJECT_ORDER" /* CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER */, context)) {
15420
15419
  mergeArgs.unshift(exp);
@@ -15425,7 +15424,7 @@ function buildProps(node, context, props = node.props, isComponent, isDynamicCom
15425
15424
  }
15426
15425
  else {
15427
15426
  // v-on="obj" -> toHandlers(obj)
15428
- mergeArgs.push({
15427
+ pushMergeArg({
15429
15428
  type: 14 /* NodeTypes.JS_CALL_EXPRESSION */,
15430
15429
  loc,
15431
15430
  callee: context.helper(TO_HANDLERS),
@@ -15445,7 +15444,12 @@ function buildProps(node, context, props = node.props, isComponent, isDynamicCom
15445
15444
  // has built-in directive transform.
15446
15445
  const { props, needRuntime } = directiveTransform(prop, node, context);
15447
15446
  !ssr && props.forEach(analyzePatchFlag);
15448
- properties.push(...props);
15447
+ if (isVOn && arg && !isStaticExp(arg)) {
15448
+ pushMergeArg(createObjectExpression(props, elementLoc));
15449
+ }
15450
+ else {
15451
+ properties.push(...props);
15452
+ }
15449
15453
  if (needRuntime) {
15450
15454
  runtimeDirectives.push(prop);
15451
15455
  if (isSymbol(needRuntime)) {
@@ -15467,9 +15471,8 @@ function buildProps(node, context, props = node.props, isComponent, isDynamicCom
15467
15471
  let propsExpression = undefined;
15468
15472
  // has v-bind="object" or v-on="object", wrap with mergeProps
15469
15473
  if (mergeArgs.length) {
15470
- if (properties.length) {
15471
- mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));
15472
- }
15474
+ // close up any not-yet-merged props
15475
+ pushMergeArg();
15473
15476
  if (mergeArgs.length > 1) {
15474
15477
  propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);
15475
15478
  }
@@ -19303,6 +19306,11 @@ function stringifyElement(node, context) {
19303
19306
  res += ` ${p.arg.content}="__VUE_EXP_START__${exp.content}__VUE_EXP_END__"`;
19304
19307
  continue;
19305
19308
  }
19309
+ // #6568
19310
+ if (isBooleanAttr(p.arg.content) &&
19311
+ exp.content === 'false') {
19312
+ continue;
19313
+ }
19306
19314
  // constant v-bind, e.g. :foo="1"
19307
19315
  let evaluated = evaluateConstant(exp);
19308
19316
  if (evaluated != null) {