@solidjs/babel-plugin 2.0.0-rc.17 → 2.0.0-rc.19

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.
@@ -7,4 +7,4 @@ src/shared/transform.ts -> src/dom/element.ts -> src/universal/element.ts -> src
7
7
  src/shared/transform.ts -> src/ssr/element.ts -> src/shared/transform.ts
8
8
  src/shared/transform.ts -> src/shared/component.ts -> src/shared/transform.ts
9
9
  src/shared/transform.ts -> src/shared/fragment.ts -> src/shared/transform.ts
10
- created index.js in 2.3s
10
+ created index.js in 2.2s
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @solidjs/babel-plugin
2
2
 
3
+ ## 2.0.0-rc.19
4
+
5
+ ### Patch Changes
6
+
7
+ - 8cff139: Evaluated negative and non-finite numbers (`c={-1}`, `d={NaN}`) are static again. Since Babel 8 support, `evaluateAndInline` built them with `t.valueToNode`, which gives `-1` / `0 / 0` expressions rather than numeric literals, so they stopped being inlined into templates (SSR emitted `ssrAttribute("c", -1)` instead of `c="-1"`) and diverged from `@solidjs/compiler` (the parity probes' "exotic literal holes"). They are now NumericLiteral nodes again, built directly where @babel/types 8's builder would reject the value; both Babel majors print them as before.
8
+ - 55c7329: Support `@babel/core` 8 alongside 7: the peer range is now `^7.20.12 || ^8.0.0`. SSR no longer reads `Scope#uids` (removed in Babel 8), evaluated negative or non-finite numbers are built with `valueToNode`, `import()` parsed as `ImportExpression` stays dynamic, and TSRX emits the AST shape of the running Babel major (type arguments, type parameter names, `import()`, enums, heritage). TSRX also keeps `import()` options and class method type parameters, which it dropped before.
9
+ - 9e1edbc: A lone dynamic spread on an SSR element (`<label {...props()} />`) now defers behind a thunk like a spread beside other attributes, so it runs after the element's hydration key. A spread that created a memo shifted the element's key on the server only, and hydration missed the element (#4240).
10
+
11
+ ## 2.0.0-rc.18
12
+
3
13
  ## 2.0.0-rc.17
4
14
 
5
15
  ### Patch Changes
package/index.js CHANGED
@@ -329,6 +329,13 @@ path)
329
329
  return hasStaticMarker(object.expression, path);
330
330
  }
331
331
 
332
+ /** `import()`: an `ImportExpression` on Babel 8 (and 7 with
333
+ * `createImportExpressions`), a `CallExpression` with an `Import` callee
334
+ * otherwise. Checked by type so older `@babel/types` builds still match. */
335
+ function isImportExpression(node) {
336
+ return node.type === "ImportExpression";
337
+ }
338
+
332
339
  function isDynamic(
333
340
  path,
334
341
  { checkMember, checkTags, checkCallExpressions = true })
@@ -348,7 +355,8 @@ path,
348
355
  checkCallExpressions && (
349
356
  t__namespace.isCallExpression(expr) ||
350
357
  t__namespace.isOptionalCallExpression(expr) ||
351
- t__namespace.isTaggedTemplateExpression(expr)))
358
+ t__namespace.isTaggedTemplateExpression(expr) ||
359
+ isImportExpression(expr)))
352
360
  {
353
361
  return true;
354
362
  }
@@ -391,6 +399,11 @@ path,
391
399
 
392
400
  let dynamic;
393
401
  const visitor = {
402
+ // `ImportExpression` is matched by type rather than visitor key: a Babel
403
+ // core older than 7.23 rejects visitors for node types it doesn't know.
404
+ enter(p) {
405
+ checkCallExpressions && isImportExpression(p.node) && (dynamic = true) && p.stop();
406
+ },
394
407
  Function(p) {
395
408
  if (t__namespace.isObjectMethod(p.node) && p.node.computed) {
396
409
  dynamic = isDynamic(p.get("key"), { checkMember, checkTags, checkCallExpressions });
@@ -945,6 +958,18 @@ const templateEscapes = new Map([
945
958
  ["\u2029", "\\u2029"]]
946
959
  );
947
960
 
961
+ // A NumericLiteral for any evaluated number, so `-1` and `NaN` stay static
962
+ // literals downstream. @babel/types 8's builder rejects negative and
963
+ // non-finite values (`t.valueToNode` builds `-1` / `0 / 0` expressions
964
+ // instead), so those are built as plain nodes; generators print them as
965
+ // `-1` / `NaN` / `Infinity`, as Babel 7's builder did.
966
+ function numberLiteral(value) {
967
+ if (value >= 0 && Number.isFinite(value) && !Object.is(value, -0)) return t__namespace.numericLiteral(value);
968
+ const node = { type: "NumericLiteral", value };
969
+ if (Object.is(value, -0)) node.extra = { raw: "-0", rawValue: -0 };
970
+ return node;
971
+ }
972
+
948
973
  function evaluateAndInline(
949
974
  value,
950
975
  valueNode)
@@ -969,7 +994,7 @@ valueNode)
969
994
  if (typeof r.value === "string") {
970
995
  valueNode.replaceWith(t__namespace.stringLiteral(r.value));
971
996
  } else if (typeof r.value === "number") {
972
- valueNode.replaceWith(t__namespace.numericLiteral(r.value));
997
+ valueNode.replaceWith(numberLiteral(r.value));
973
998
  } else if (typeof r.value === "boolean") {
974
999
  valueNode.replaceWith(t__namespace.booleanLiteral(r.value));
975
1000
  }
@@ -2116,7 +2141,7 @@ info = {})
2116
2141
  }
2117
2142
  if (value)
2118
2143
  a.get("value").replaceWith(
2119
- t$1.jSXExpressionContainer(t$1.callExpression(t$1.arrowFunctionExpression([], value), []))
2144
+ t$1.jsxExpressionContainer(t$1.callExpression(t$1.arrowFunctionExpression([], value), []))
2120
2145
  );
2121
2146
  }
2122
2147
  });
@@ -2868,7 +2893,7 @@ results)
2868
2893
  (type = typeof evaluated) === "string" || type === "number" || type === "boolean"))
2869
2894
  {
2870
2895
  if (type === "number" && key.startsWith("prop:")) {
2871
- value = t$1.jsxExpressionContainer(t$1.numericLiteral(evaluated));
2896
+ value = t$1.jsxExpressionContainer(numberLiteral(evaluated));
2872
2897
  } else if (type === "boolean") {
2873
2898
  value = t$1.jsxExpressionContainer(t$1.booleanLiteral(evaluated));
2874
2899
  } else value = t$1.stringLiteral(String(evaluated));
@@ -4306,8 +4331,10 @@ function hoistProps(program, config) {
4306
4331
  // program scope's `uids` (the names generateUid handed out — `hasUid` is
4307
4332
  // how a compiler temp is told from user code below) and `data` (imports,
4308
4333
  // templates, events — what postprocess is about to place); both survive.
4309
- const uids = program.scope.uids;
4334
+ const scope = program.scope;
4335
+ const uids = scope.uidsSet ? new Set(scope.uidsSet) : scope.uids;
4310
4336
  program.scope.crawl();
4337
+ if (uids instanceof Set) for (const name of uids) scope.uidsSet.add(name);else
4311
4338
  Object.assign(program.scope.uids, uids);
4312
4339
  program.scope.data = data;
4313
4340
 
@@ -5780,7 +5807,15 @@ path,
5780
5807
  refs.push(node.value.expression);
5781
5808
  }
5782
5809
  if (propAttributes.length === 1 && t.isJSXSpreadAttribute(propAttributes[0].node)) {
5783
- props = [propAttributes[0].node.argument];
5810
+ // A lone dynamic spread defers behind a thunk too (#4240): see the
5811
+ // source loop below. `ssrElement` calls a function props argument after
5812
+ // allocating the key.
5813
+ const argument = propAttributes[0].node.argument;
5814
+ props = [
5815
+ isDynamic(propAttributes[0].get("argument"), { checkMember: true }) ?
5816
+ inlineCallExpression(argument) :
5817
+ argument];
5818
+
5784
5819
  } else {
5785
5820
  props = [];
5786
5821
  let runningObject = [],
@@ -5929,7 +5964,8 @@ function callsOutsideFunctions(node) {
5929
5964
  t.isCallExpression(node) ||
5930
5965
  t.isOptionalCallExpression(node) ||
5931
5966
  t.isNewExpression(node) ||
5932
- t.isTaggedTemplateExpression(node))
5967
+ t.isTaggedTemplateExpression(node) ||
5968
+ isImportExpression(node))
5933
5969
 
5934
5970
  return true;
5935
5971
  if (t.isFunction(node)) return false;
@@ -16375,6 +16411,16 @@ const STRIP_KEYS = new Set([
16375
16411
  "directive"]
16376
16412
  );
16377
16413
 
16414
+ /** Which Babel AST shape to emit. Babel 8 keeps `typeArguments`,
16415
+ * `ImportExpression`, Identifier type-parameter names and `TSEnumBody`;
16416
+ * Babel 7 wants the older forms. Set for the length of one `toBabelFile`. */
16417
+ let babel8 = false;
16418
+
16419
+ /** The key Babel expects for a node's type arguments. */
16420
+ function typeArgsKey() {
16421
+ return babel8 ? "typeArguments" : "typeParameters";
16422
+ }
16423
+
16378
16424
  function isNode$2(value) {
16379
16425
  return (
16380
16426
  typeof value === "object" &&
@@ -16401,19 +16447,32 @@ function convertValue(value) {
16401
16447
  }
16402
16448
 
16403
16449
  /** Shallow-map every kept key, renaming typescript-eslint's `typeArguments`
16404
- * to Babel 7's `typeParameters` along the way. */
16450
+ * to Babel 7's `typeParameters` along the way (Babel 8 keeps the name). */
16405
16451
  function convertGeneric(node, overrideType) {
16406
16452
  const out = { type: overrideType ?? node.type };
16407
16453
  copyLoc(node, out);
16408
16454
  for (const key of Object.keys(node)) {
16409
16455
  if (STRIP_KEYS.has(key)) continue;
16410
16456
  const outKey =
16411
- key === "typeArguments" && node.typeParameters === undefined ? "typeParameters" : key;
16457
+ !babel8 && key === "typeArguments" && node.typeParameters === undefined ?
16458
+ "typeParameters" :
16459
+ key;
16412
16460
  out[outKey] = convertValue(node[key]);
16413
16461
  }
16414
16462
  return out;
16415
16463
  }
16416
16464
 
16465
+ /** Convert a node whose type arguments typescript-eslint spells
16466
+ * `typeParameters`, moving them to the key the target Babel expects. */
16467
+ function convertTypeArgsHolder(node, type) {
16468
+ const out = convertGeneric(node, type);
16469
+ const args = out.typeParameters ?? out.typeArguments;
16470
+ delete out.typeParameters;
16471
+ delete out.typeArguments;
16472
+ if (args !== undefined) out[typeArgsKey()] = args;
16473
+ return out;
16474
+ }
16475
+
16417
16476
  function convertLiteral(node) {
16418
16477
  const out = {};
16419
16478
  copyLoc(node, out);
@@ -16506,7 +16565,7 @@ function convertChainLink(node) {
16506
16565
  };
16507
16566
  copyLoc(node, out);
16508
16567
  if (node.typeParameters !== undefined || node.typeArguments !== undefined) {
16509
- out.typeParameters = convertValue(node.typeParameters ?? node.typeArguments);
16568
+ out[typeArgsKey()] = convertValue(node.typeParameters ?? node.typeArguments);
16510
16569
  }
16511
16570
  return out;
16512
16571
  }
@@ -16589,6 +16648,9 @@ function convertNode(node) {
16589
16648
  };
16590
16649
  copyLoc(node, out);
16591
16650
  convertFunctionParts(fn, out);
16651
+ if (node.typeParameters != null && out.typeParameters === undefined) {
16652
+ out.typeParameters = convertValue(node.typeParameters);
16653
+ }
16592
16654
  if (node.accessibility !== undefined) out.accessibility = node.accessibility;
16593
16655
  if (node.override !== undefined) out.override = node.override;
16594
16656
  if (node.optional !== undefined) out.optional = node.optional;
@@ -16631,10 +16693,22 @@ function convertNode(node) {
16631
16693
  return convertChainLink(node.expression);
16632
16694
 
16633
16695
  case "ImportExpression":{
16696
+ // `@tsrx/core` puts the options object in `arguments[0]`; acorn uses `options`.
16697
+ const options = node.options ?? node.arguments?.[0];
16698
+ if (babel8) {
16699
+ const out = {
16700
+ type: "ImportExpression",
16701
+ source: convertValue(node.source),
16702
+ options: options != null ? convertValue(options) : null
16703
+ };
16704
+ if (node.phase != null) out.phase = node.phase;
16705
+ copyLoc(node, out);
16706
+ return out;
16707
+ }
16634
16708
  const importCallee = { type: "Import" };
16635
16709
  copyLoc(node, importCallee);
16636
16710
  const args = [convertValue(node.source)];
16637
- if (node.options != null) args.push(convertValue(node.options));
16711
+ if (options != null) args.push(convertValue(options));
16638
16712
  const out = {
16639
16713
  type: "CallExpression",
16640
16714
  callee: importCallee,
@@ -16653,12 +16727,71 @@ function convertNode(node) {
16653
16727
 
16654
16728
  case "TSTypeParameter":{
16655
16729
  const out = convertGeneric(node);
16656
- if (isNode$2(out.name)) out.name = out.name.name;
16730
+ if (babel8) {
16731
+ if (typeof out.name === "string") {
16732
+ const id = { type: "Identifier", name: out.name };
16733
+ copyLoc(node, id);
16734
+ out.name = id;
16735
+ }
16736
+ } else if (isNode$2(out.name)) out.name = out.name.name;
16657
16737
  return out;
16658
16738
  }
16659
16739
 
16660
16740
  case "TSInterfaceHeritage":
16661
- return convertGeneric(node, "TSExpressionWithTypeArguments");
16741
+ return convertTypeArgsHolder(
16742
+ node,
16743
+ babel8 ? "TSInterfaceHeritage" : "TSExpressionWithTypeArguments"
16744
+ );
16745
+
16746
+ // `implements` entries arrive in the pre-split typescript-eslint shape.
16747
+ case "TSExpressionWithTypeArguments":
16748
+ case "TSClassImplements":
16749
+ return convertTypeArgsHolder(
16750
+ node,
16751
+ babel8 ? "TSClassImplements" : "TSExpressionWithTypeArguments"
16752
+ );
16753
+
16754
+ case "ClassDeclaration":
16755
+ case "ClassExpression":{
16756
+ const out = convertGeneric(node);
16757
+ const superArgs = out.superTypeParameters ?? out.superTypeArguments;
16758
+ delete out.superTypeParameters;
16759
+ delete out.superTypeArguments;
16760
+ if (superArgs !== undefined) {
16761
+ out[babel8 ? "superTypeArguments" : "superTypeParameters"] = superArgs;
16762
+ }
16763
+ return out;
16764
+ }
16765
+
16766
+ case "TSInterfaceDeclaration":{
16767
+ const out = convertGeneric(node);
16768
+ // Interface heritage can arrive in the class-implements shape.
16769
+ if (babel8 && Array.isArray(out.extends)) {
16770
+ for (const heritage of out.extends) {
16771
+ heritage.type = "TSInterfaceHeritage";
16772
+ }
16773
+ }
16774
+ return out;
16775
+ }
16776
+
16777
+ case "TSImportType":{
16778
+ const out = convertGeneric(node);
16779
+ if (babel8 && out.argument !== undefined) {
16780
+ out.source = out.argument;
16781
+ delete out.argument;
16782
+ }
16783
+ return out;
16784
+ }
16785
+
16786
+ case "TSEnumDeclaration":{
16787
+ const out = convertGeneric(node);
16788
+ if (babel8 && out.body === undefined) {
16789
+ const body = { type: "TSEnumBody", members: out.members };
16790
+ delete out.members;
16791
+ out.body = body;
16792
+ }
16793
+ return out;
16794
+ }
16662
16795
 
16663
16796
  case "TSAbstractMethodDefinition":
16664
16797
  case "TSAbstractPropertyDefinition":
@@ -16681,15 +16814,20 @@ function convertNode(node) {
16681
16814
  }
16682
16815
  }
16683
16816
 
16684
- function toBabelFile(program) {
16685
- const file = {
16686
- type: "File",
16687
- program: convertNode(program),
16688
- comments: [],
16689
- tokens: []
16690
- };
16691
- copyLoc(program, file);
16692
- return file;
16817
+ function toBabelFile(program, babelMajor = 7) {
16818
+ babel8 = babelMajor >= 8;
16819
+ try {
16820
+ const file = {
16821
+ type: "File",
16822
+ program: convertNode(program),
16823
+ comments: [],
16824
+ tokens: []
16825
+ };
16826
+ copyLoc(program, file);
16827
+ return file;
16828
+ } finally {
16829
+ babel8 = false;
16830
+ }
16693
16831
  }
16694
16832
 
16695
16833
  /**
@@ -17256,7 +17394,7 @@ function isTsrxSource(syntax, filename) {
17256
17394
 
17257
17395
  /** Parse TSRX source text into a Babel `File` with all TSRX constructs
17258
17396
  * lowered to Solid builtIn JSX. */
17259
- function parseTsrx(code, filename) {
17397
+ function parseTsrx(code, filename, babelMajor = 7) {
17260
17398
  const tsrx = loadTsrxCore();
17261
17399
  const program = tsrx.parseModule(code, filename ?? "module.tsrx");
17262
17400
  rejectAuthoredLazyDestructuring(program);
@@ -17266,7 +17404,7 @@ function parseTsrx(code, filename) {
17266
17404
 
17267
17405
  desugarProgram(program);
17268
17406
 
17269
- const file = toBabelFile(program);
17407
+ const file = toBabelFile(program, babelMajor);
17270
17408
  // Babel's default AST clone preserves enumerable string keys. Program.enter
17271
17409
  // lifts this temporary payload into transform metadata and removes it from
17272
17410
  // the AST, avoiding mutable plugin-factory state (and concurrent-run races).
@@ -17275,7 +17413,7 @@ function parseTsrx(code, filename) {
17275
17413
  }
17276
17414
 
17277
17415
  var index = (
17278
- _api,
17416
+ api,
17279
17417
  options = {}) =>
17280
17418
 
17281
17419
 
@@ -17283,12 +17421,14 @@ options = {}) =>
17283
17421
 
17284
17422
 
17285
17423
  {
17424
+ // TSRX builds its own AST, so it has to match the running core's shape.
17425
+ const babelMajor = parseInt(api?.version ?? "7", 10) || 7;
17286
17426
  return {
17287
17427
  name: "@solidjs/babel-plugin",
17288
17428
  inherits: SyntaxJSX.default,
17289
17429
  parserOverride(code, parserOpts, parse) {
17290
17430
  if (isTsrxSource(options.syntax, parserOpts?.sourceFileName)) {
17291
- return parseTsrx(code, parserOpts?.sourceFileName);
17431
+ return parseTsrx(code, parserOpts?.sourceFileName, babelMajor);
17292
17432
  }
17293
17433
  return parse(code, parserOpts);
17294
17434
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/babel-plugin",
3
3
  "description": "Babel compiler plugin for Solid templates",
4
- "version": "2.0.0-rc.17",
4
+ "version": "2.0.0-rc.19",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -27,7 +27,7 @@
27
27
  "parse5": "^7.1.2"
28
28
  },
29
29
  "peerDependencies": {
30
- "@babel/core": "^7.20.12",
30
+ "@babel/core": "^7.20.12 || ^8.0.0",
31
31
  "@tsrx/core": "0.1.63"
32
32
  },
33
33
  "peerDependenciesMeta": {