solid-refresh 0.6.3 → 0.7.0

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.
Files changed (44) hide show
  1. package/README.md +38 -10
  2. package/dist/babel.cjs +580 -283
  3. package/dist/babel.mjs +580 -283
  4. package/dist/types/src/babel/core/checks.d.ts +4 -0
  5. package/dist/types/src/babel/core/checks.d.ts.map +1 -0
  6. package/dist/types/src/babel/core/constants.d.ts +8 -0
  7. package/dist/types/src/babel/core/constants.d.ts.map +1 -0
  8. package/dist/types/src/babel/core/create-registry.d.ts +5 -0
  9. package/dist/types/src/babel/core/create-registry.d.ts.map +1 -0
  10. package/dist/types/src/babel/core/generate-unique-name.d.ts +4 -0
  11. package/dist/types/src/babel/core/generate-unique-name.d.ts.map +1 -0
  12. package/dist/types/src/babel/core/generator.d.ts +3 -0
  13. package/dist/types/src/babel/core/generator.d.ts.map +1 -0
  14. package/dist/types/src/babel/core/get-descriptive-name.d.ts +3 -0
  15. package/dist/types/src/babel/core/get-descriptive-name.d.ts.map +1 -0
  16. package/dist/types/src/babel/core/get-foreign-bindings.d.ts +4 -0
  17. package/dist/types/src/babel/core/get-foreign-bindings.d.ts.map +1 -0
  18. package/dist/types/src/babel/core/get-hmr-decline-call.d.ts +4 -0
  19. package/dist/types/src/babel/core/get-hmr-decline-call.d.ts.map +1 -0
  20. package/dist/types/src/babel/core/get-hot-identifier.d.ts +4 -0
  21. package/dist/types/src/babel/core/get-hot-identifier.d.ts.map +1 -0
  22. package/dist/types/src/babel/core/get-import-identifier.d.ts +5 -0
  23. package/dist/types/src/babel/core/get-import-identifier.d.ts.map +1 -0
  24. package/dist/types/src/babel/core/get-root-statement-path.d.ts +3 -0
  25. package/dist/types/src/babel/core/get-root-statement-path.d.ts.map +1 -0
  26. package/dist/types/src/babel/core/get-statement-path.d.ts +3 -0
  27. package/dist/types/src/babel/core/get-statement-path.d.ts.map +1 -0
  28. package/dist/types/src/babel/core/get-vite-hmr-requirement.d.ts +4 -0
  29. package/dist/types/src/babel/core/get-vite-hmr-requirement.d.ts.map +1 -0
  30. package/dist/types/src/babel/core/is-valid-callee.d.ts +5 -0
  31. package/dist/types/src/babel/core/is-valid-callee.d.ts.map +1 -0
  32. package/dist/types/src/babel/core/register-import-specifiers.d.ts +5 -0
  33. package/dist/types/src/babel/core/register-import-specifiers.d.ts.map +1 -0
  34. package/dist/types/src/babel/core/transform-jsx.d.ts +4 -0
  35. package/dist/types/src/babel/core/transform-jsx.d.ts.map +1 -0
  36. package/dist/types/src/babel/core/types.d.ts +41 -0
  37. package/dist/types/src/babel/core/types.d.ts.map +1 -0
  38. package/dist/types/src/babel/core/unwrap.d.ts +11 -0
  39. package/dist/types/src/babel/core/unwrap.d.ts.map +1 -0
  40. package/dist/types/src/babel/core/xxhash32.d.ts +7 -0
  41. package/dist/types/src/babel/core/xxhash32.d.ts.map +1 -0
  42. package/dist/types/src/babel/index.d.ts +1 -24
  43. package/dist/types/src/babel/index.d.ts.map +1 -1
  44. package/package.json +1 -1
package/dist/babel.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  var path = require('path');
4
4
  var t = require('@babel/types');
5
- var _generator = require('@babel/generator');
6
5
  var helperModuleImports = require('@babel/helper-module-imports');
6
+ var _generator = require('@babel/generator');
7
7
 
8
8
  function _interopNamespaceDefault(e) {
9
9
  var n = Object.create(null);
@@ -211,79 +211,244 @@ function xxHash32(buffer, seed = 0) {
211
211
  return acc < 0 ? acc + 4294967296 : acc;
212
212
  }
213
213
 
214
- // https://github.com/babel/babel/issues/15269
215
- let generator;
216
- if (typeof _generator !== 'function') {
217
- generator = _generator.default;
218
- }
219
- else {
220
- generator = _generator;
221
- }
222
- const CWD = process.cwd();
223
- function getFile(filename) {
224
- return path.relative(CWD, filename);
225
- }
226
214
  // This is just a Pascal heuristic
227
215
  // we only assume a function is a component
228
216
  // if the first character is in uppercase
229
217
  function isComponentishName(name) {
230
218
  return name[0] >= 'A' && name[0] <= 'Z';
231
219
  }
232
- function isESMHMR(bundler) {
233
- // The currently known ESM HMR implementations
234
- // esm - the original ESM HMR Spec
235
- // vite - Vite's implementation
236
- return bundler === 'esm' || bundler === 'vite';
220
+ function getImportSpecifierName(specifier) {
221
+ if (t__namespace.isIdentifier(specifier.imported)) {
222
+ return specifier.imported.name;
223
+ }
224
+ return specifier.imported.value;
237
225
  }
238
- // Source of solid-refresh (for import)
239
- const SOLID_REFRESH_MODULE = 'solid-refresh';
240
- // Exported names from solid-refresh that will be imported
241
- const IMPORTS = {
242
- registry: '$$registry',
243
- refresh: '$$refresh',
244
- component: '$$component',
245
- context: '$$context',
246
- decline: '$$decline',
247
- };
248
- function getSolidRefreshIdentifier(state, path, name) {
249
- const target = `${name}`;
250
- const current = state.hooks.get(target);
251
- if (current) {
252
- return current;
226
+
227
+ function registerImportSpecifier(state, id, specifier) {
228
+ if (t__namespace.isImportDefaultSpecifier(specifier)) {
229
+ if (id.definition.kind === 'default') {
230
+ state.registrations.identifiers.set(specifier.local, id);
231
+ }
232
+ return;
253
233
  }
254
- const newID = helperModuleImports.addNamed(path, name, SOLID_REFRESH_MODULE);
255
- state.hooks.set(target, newID);
256
- return newID;
234
+ if (t__namespace.isImportSpecifier(specifier)) {
235
+ if ((id.definition.kind === 'named' &&
236
+ getImportSpecifierName(specifier) === id.definition.name) ||
237
+ (id.definition.kind === 'default' &&
238
+ getImportSpecifierName(specifier) === 'default')) {
239
+ state.registrations.identifiers.set(specifier.local, id);
240
+ }
241
+ return;
242
+ }
243
+ let current = state.registrations.namespaces.get(specifier.local);
244
+ if (!current) {
245
+ current = [];
246
+ }
247
+ current.push(id);
248
+ state.registrations.namespaces.set(specifier.local, current);
257
249
  }
250
+ function registerImportSpecifiers(state, path, definitions) {
251
+ for (let i = 0, len = definitions.length; i < len; i++) {
252
+ const id = definitions[i];
253
+ if (path.node.source.value === id.definition.source) {
254
+ for (let k = 0, klen = path.node.specifiers.length; k < klen; k++) {
255
+ registerImportSpecifier(state, id, path.node.specifiers[k]);
256
+ }
257
+ }
258
+ }
259
+ }
260
+
258
261
  function getHotIdentifier(state) {
259
- const bundler = state.opts.bundler;
260
- // vite/esm uses `import.meta.hot`
261
- if (isESMHMR(bundler)) {
262
- return t__namespace.memberExpression(t__namespace.memberExpression(t__namespace.identifier('import'), t__namespace.identifier('meta')), t__namespace.identifier('hot'));
262
+ switch (state.bundler) {
263
+ // vite/esm uses `import.meta.hot`
264
+ case 'esm':
265
+ case 'vite':
266
+ return t__namespace.memberExpression(t__namespace.memberExpression(t__namespace.identifier('import'), t__namespace.identifier('meta')), t__namespace.identifier('hot'));
267
+ // webpack 5 uses `import.meta.webpackHot`
268
+ // rspack does as well
269
+ case 'webpack5':
270
+ case 'rspack-esm':
271
+ return t__namespace.memberExpression(t__namespace.memberExpression(t__namespace.identifier('import'), t__namespace.identifier('meta')), t__namespace.identifier('webpackHot'));
272
+ default:
273
+ // `module.hot` is the default.
274
+ return t__namespace.memberExpression(t__namespace.identifier('module'), t__namespace.identifier('hot'));
263
275
  }
264
- // webpack 5 uses `import.meta.webpackHot`
265
- // rspack does as well
266
- if (bundler === 'webpack5' || bundler === 'rspack-esm') {
267
- return t__namespace.memberExpression(t__namespace.memberExpression(t__namespace.identifier('import'), t__namespace.identifier('meta')), t__namespace.identifier('webpackHot'));
276
+ }
277
+
278
+ function getImportIdentifier(state, path, registration) {
279
+ const name = registration.kind === 'named' ? registration.name : 'default';
280
+ const target = `${registration.source}[${name}]`;
281
+ const current = state.imports.get(target);
282
+ if (current) {
283
+ return current;
268
284
  }
269
- // `module.hot` is the default.
270
- return t__namespace.memberExpression(t__namespace.identifier('module'), t__namespace.identifier('hot'));
285
+ const newID = registration.kind === 'named'
286
+ ? helperModuleImports.addNamed(path, registration.name, registration.source)
287
+ : helperModuleImports.addDefault(path, registration.source);
288
+ state.imports.set(target, newID);
289
+ return newID;
271
290
  }
272
- function generateViteRequirement(state, statements, pathToHot) {
273
- if (state.opts.bundler === 'vite') {
291
+
292
+ // Source of solid-refresh (for import)
293
+ const SOLID_REFRESH_MODULE = 'solid-refresh';
294
+ // Exported names from solid-refresh that will be imported
295
+ const IMPORT_REGISTRY = {
296
+ kind: 'named',
297
+ name: '$$registry',
298
+ source: SOLID_REFRESH_MODULE,
299
+ };
300
+ const IMPORT_REFRESH = {
301
+ kind: 'named',
302
+ name: '$$refresh',
303
+ source: SOLID_REFRESH_MODULE,
304
+ };
305
+ const IMPORT_COMPONENT = {
306
+ kind: 'named',
307
+ name: '$$component',
308
+ source: SOLID_REFRESH_MODULE,
309
+ };
310
+ const IMPORT_CONTEXT = {
311
+ kind: 'named',
312
+ name: '$$context',
313
+ source: SOLID_REFRESH_MODULE,
314
+ };
315
+ const IMPORT_DECLINE = {
316
+ kind: 'named',
317
+ name: '$$decline',
318
+ source: SOLID_REFRESH_MODULE,
319
+ };
320
+ const IMPORT_SPECIFIERS = [
321
+ {
322
+ type: 'render',
323
+ definition: { name: 'render', kind: 'named', source: 'solid-js/web' },
324
+ },
325
+ {
326
+ type: 'render',
327
+ definition: { name: 'hydrate', kind: 'named', source: 'solid-js/web' },
328
+ },
329
+ {
330
+ type: 'createContext',
331
+ definition: {
332
+ name: 'createContext',
333
+ kind: 'named',
334
+ source: 'solid-js',
335
+ },
336
+ },
337
+ {
338
+ type: 'createContext',
339
+ definition: {
340
+ name: 'createContext',
341
+ kind: 'named',
342
+ source: 'solid-js/web',
343
+ },
344
+ },
345
+ ];
346
+
347
+ function generateViteHMRRequirement(state, statements, pathToHot) {
348
+ if (state.bundler === 'vite') {
274
349
  // Vite requires that the owner module has an `import.meta.hot.accept()` call
275
350
  statements.push(t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.memberExpression(pathToHot, t__namespace.identifier('accept')), [])));
276
351
  }
277
352
  }
353
+
278
354
  function getHMRDeclineCall(state, path) {
279
- var _a;
280
355
  const pathToHot = getHotIdentifier(state);
281
356
  const statements = [
282
- t__namespace.expressionStatement(t__namespace.callExpression(getSolidRefreshIdentifier(state, path, IMPORTS.decline), [t__namespace.stringLiteral((_a = state.opts.bundler) !== null && _a !== void 0 ? _a : 'standard'), pathToHot])),
357
+ t__namespace.expressionStatement(t__namespace.callExpression(getImportIdentifier(state, path, IMPORT_DECLINE), [
358
+ t__namespace.stringLiteral(state.bundler),
359
+ pathToHot,
360
+ ])),
283
361
  ];
284
- generateViteRequirement(state, statements, pathToHot);
362
+ generateViteHMRRequirement(state, statements, pathToHot);
285
363
  return t__namespace.ifStatement(pathToHot, t__namespace.blockStatement(statements));
286
364
  }
365
+
366
+ function isPathValid(path, key) {
367
+ return key(path.node);
368
+ }
369
+ function isNestedExpression(node) {
370
+ switch (node.type) {
371
+ case 'ParenthesizedExpression':
372
+ case 'TypeCastExpression':
373
+ case 'TSAsExpression':
374
+ case 'TSSatisfiesExpression':
375
+ case 'TSNonNullExpression':
376
+ case 'TSTypeAssertion':
377
+ case 'TSInstantiationExpression':
378
+ return true;
379
+ default:
380
+ return false;
381
+ }
382
+ }
383
+ function unwrapNode(node, key) {
384
+ if (key(node)) {
385
+ return node;
386
+ }
387
+ if (isNestedExpression(node)) {
388
+ return unwrapNode(node.expression, key);
389
+ }
390
+ return undefined;
391
+ }
392
+
393
+ function isIdentifierValidCallee(state, path, callee, target) {
394
+ const binding = path.scope.getBindingIdentifier(callee.name);
395
+ if (binding) {
396
+ const result = state.registrations.identifiers.get(binding);
397
+ if (result && result.type === target) {
398
+ return true;
399
+ }
400
+ }
401
+ return false;
402
+ }
403
+ function isPropertyValidCallee(result, target, propName) {
404
+ for (let i = 0, len = result.length; i < len; i++) {
405
+ const registration = result[i];
406
+ if (registration.type === target) {
407
+ if (registration.definition.kind === 'named') {
408
+ if (registration.definition.name === propName) {
409
+ return true;
410
+ }
411
+ }
412
+ else if (propName === 'default') {
413
+ return true;
414
+ }
415
+ }
416
+ }
417
+ return false;
418
+ }
419
+ function isMemberExpressionValidCallee(state, path, member, target) {
420
+ if (!t__namespace.isIdentifier(member.property)) {
421
+ return false;
422
+ }
423
+ const trueObject = unwrapNode(member.object, t__namespace.isIdentifier);
424
+ if (!trueObject) {
425
+ return false;
426
+ }
427
+ const binding = path.scope.getBindingIdentifier(trueObject.name);
428
+ if (!binding) {
429
+ return false;
430
+ }
431
+ const result = state.registrations.namespaces.get(binding);
432
+ if (!result) {
433
+ return false;
434
+ }
435
+ return isPropertyValidCallee(result, target, member.property.name);
436
+ }
437
+ function isValidCallee(state, path, { callee }, target) {
438
+ if (t__namespace.isV8IntrinsicIdentifier(callee)) {
439
+ return false;
440
+ }
441
+ const trueCallee = unwrapNode(callee, t__namespace.isIdentifier);
442
+ if (trueCallee) {
443
+ return isIdentifierValidCallee(state, path, trueCallee, target);
444
+ }
445
+ const trueMember = unwrapNode(callee, t__namespace.isMemberExpression);
446
+ if (trueMember && !trueMember.computed) {
447
+ return isMemberExpressionValidCallee(state, path, trueMember, target);
448
+ }
449
+ return false;
450
+ }
451
+
287
452
  function getStatementPath(path) {
288
453
  if (t__namespace.isStatement(path.node)) {
289
454
  return path;
@@ -293,40 +458,46 @@ function getStatementPath(path) {
293
458
  }
294
459
  return null;
295
460
  }
461
+
462
+ function getRootStatementPath(path) {
463
+ let current = path.parentPath;
464
+ while (current) {
465
+ const next = current.parentPath;
466
+ if (next && t__namespace.isProgram(next.node)) {
467
+ return current;
468
+ }
469
+ current = next;
470
+ }
471
+ return path;
472
+ }
473
+
296
474
  const REGISTRY = 'REGISTRY';
297
475
  function createRegistry(state, path) {
298
- var _a;
299
- const current = state.hooks.get(REGISTRY);
476
+ const current = state.imports.get(REGISTRY);
300
477
  if (current) {
301
478
  return current;
302
479
  }
303
- const program = path.scope.getProgramParent();
304
- const identifier = program.generateUidIdentifier(REGISTRY);
305
- program.push({
306
- id: identifier,
307
- kind: 'const',
308
- init: t__namespace.callExpression(getSolidRefreshIdentifier(state, path, IMPORTS.registry), []),
309
- });
480
+ const root = getRootStatementPath(path);
481
+ const identifier = path.scope.generateUidIdentifier(REGISTRY);
482
+ root.insertBefore(t__namespace.variableDeclaration('const', [
483
+ t__namespace.variableDeclarator(identifier, t__namespace.callExpression(getImportIdentifier(state, path, IMPORT_REGISTRY), [])),
484
+ ]));
310
485
  const pathToHot = getHotIdentifier(state);
311
486
  const statements = [
312
- t__namespace.expressionStatement(t__namespace.callExpression(getSolidRefreshIdentifier(state, path, IMPORTS.refresh), [
313
- t__namespace.stringLiteral((_a = state.opts.bundler) !== null && _a !== void 0 ? _a : 'standard'),
487
+ t__namespace.expressionStatement(t__namespace.callExpression(getImportIdentifier(state, path, IMPORT_REFRESH), [
488
+ t__namespace.stringLiteral(state.bundler),
314
489
  pathToHot,
315
490
  identifier,
316
491
  ])),
317
492
  ];
318
- generateViteRequirement(state, statements, pathToHot);
319
- program.path.pushContainer('body', [
493
+ generateViteHMRRequirement(state, statements, pathToHot);
494
+ path.scope.getProgramParent().path.pushContainer('body', [
320
495
  t__namespace.ifStatement(pathToHot, t__namespace.blockStatement(statements)),
321
496
  ]);
322
- state.hooks.set(REGISTRY, identifier);
497
+ state.imports.set(REGISTRY, identifier);
323
498
  return identifier;
324
499
  }
325
- function createSignatureValue(node) {
326
- const code = generator(node);
327
- const result = xxHash32(code.code).toString(16);
328
- return result;
329
- }
500
+
330
501
  function isForeignBinding(source, current, name) {
331
502
  if (source === current) {
332
503
  return true;
@@ -349,13 +520,15 @@ function isInTypescript(path) {
349
520
  }
350
521
  return false;
351
522
  }
352
- function getBindings(path) {
523
+ function getForeignBindings(path) {
353
524
  const identifiers = new Set();
354
525
  path.traverse({
355
526
  ReferencedIdentifier(p) {
356
527
  // Check identifiers that aren't in a TS expression
357
528
  if (!isInTypescript(p) && isForeignBinding(path, p, p.node.name)) {
358
- identifiers.add(p.node.name);
529
+ if (p.isIdentifier() || p.parentPath.isJSXMemberExpression()) {
530
+ identifiers.add(p.node.name);
531
+ }
359
532
  }
360
533
  },
361
534
  });
@@ -365,149 +538,266 @@ function getBindings(path) {
365
538
  }
366
539
  return collected;
367
540
  }
368
- const IMPORT_IDENTITIES = [
369
- {
370
- type: 'createContext',
371
- name: 'createContext',
372
- kind: 'named',
373
- source: 'solid-js',
374
- },
375
- {
376
- type: 'createContext',
377
- name: 'createContext',
378
- kind: 'named',
379
- source: 'solid-js/web',
380
- },
381
- { type: 'render', name: 'render', kind: 'named', source: 'solid-js/web' },
382
- { type: 'render', name: 'hydrate', kind: 'named', source: 'solid-js/web' },
383
- ];
384
- function getImportSpecifierName(specifier) {
385
- switch (specifier.imported.type) {
386
- case 'Identifier':
387
- return specifier.imported.name;
388
- case 'StringLiteral':
389
- return specifier.imported.value;
390
- }
391
- }
392
- function registerImportSpecifier(state, id, specifier) {
393
- switch (specifier.type) {
394
- case 'ImportDefaultSpecifier': {
395
- if (id.kind === 'default') {
396
- state.registrations.identifiers.set(specifier.local, id);
541
+
542
+ function getDescriptiveName(path, defaultName) {
543
+ let current = path;
544
+ while (current) {
545
+ switch (current.node.type) {
546
+ case 'FunctionDeclaration':
547
+ case 'FunctionExpression': {
548
+ if (current.node.id) {
549
+ return current.node.id.name;
550
+ }
551
+ break;
397
552
  }
398
- break;
399
- }
400
- case 'ImportSpecifier': {
401
- if ((id.kind === 'named' &&
402
- getImportSpecifierName(specifier) === id.name) ||
403
- (id.kind === 'default' &&
404
- getImportSpecifierName(specifier) === 'default')) {
405
- state.registrations.identifiers.set(specifier.local, id);
553
+ case 'VariableDeclarator': {
554
+ if (current.node.id.type === 'Identifier') {
555
+ return current.node.id.name;
556
+ }
557
+ break;
406
558
  }
407
- break;
408
- }
409
- case 'ImportNamespaceSpecifier': {
410
- let current = state.registrations.namespaces.get(specifier.local);
411
- if (!current) {
412
- current = [];
559
+ case 'ClassPrivateMethod':
560
+ case 'ClassMethod':
561
+ case 'ObjectMethod': {
562
+ switch (current.node.key.type) {
563
+ case 'Identifier':
564
+ return current.node.key.name;
565
+ case 'PrivateName':
566
+ return current.node.key.id.name;
567
+ }
568
+ break;
413
569
  }
414
- current.push(id);
415
- state.registrations.namespaces.set(specifier.local, current);
416
- break;
417
570
  }
571
+ current = current.parentPath;
418
572
  }
573
+ return defaultName;
419
574
  }
420
- function registerImportSpecifiers(state, p) {
421
- for (let i = 0, len = state.imports.length; i < len; i++) {
422
- const id = state.imports[i];
423
- if (p.node.source.value === id.source) {
424
- for (let k = 0, klen = p.node.specifiers.length; k < klen; k++) {
425
- registerImportSpecifier(state, id, p.node.specifiers[k]);
575
+
576
+ function generateUniqueName(path, name) {
577
+ let uid;
578
+ let i = 1;
579
+ do {
580
+ uid = name + '_' + i;
581
+ i++;
582
+ } while (path.scope.hasLabel(uid) ||
583
+ path.scope.hasBinding(uid) ||
584
+ path.scope.hasGlobal(uid) ||
585
+ path.scope.hasReference(uid));
586
+ const program = path.scope.getProgramParent();
587
+ program.references[uid] = true;
588
+ program.uids[uid] = true;
589
+ return t__namespace.identifier(uid);
590
+ }
591
+
592
+ const REFRESH_JSX_SKIP = /^\s*@refresh jsx-skip\s*$/;
593
+ function shouldSkipJSX(node) {
594
+ // Node without leading comments shouldn't be skipped
595
+ if (node.leadingComments) {
596
+ for (let i = 0, len = node.leadingComments.length; i < len; i++) {
597
+ if (REFRESH_JSX_SKIP.test(node.leadingComments[i].value)) {
598
+ return true;
426
599
  }
427
600
  }
428
601
  }
602
+ return false;
429
603
  }
430
- function captureIdentifiers(state, path) {
431
- path.traverse({
432
- ImportDeclaration(p) {
433
- if (p.node.importKind === 'value') {
434
- registerImportSpecifiers(state, p);
604
+ function skippableJSX(node) {
605
+ return t__namespace.addComment(node, 'leading', '@refresh jsx-skip');
606
+ }
607
+ function pushAttribute(state, replacement) {
608
+ const key = 'v' + state.attributes.length;
609
+ state.attributes.push(t__namespace.jsxAttribute(t__namespace.jsxIdentifier(key), t__namespace.jsxExpressionContainer(replacement)));
610
+ return key;
611
+ }
612
+ function pushAttributeAndReplace(state, target, replacement) {
613
+ const key = pushAttribute(state, replacement);
614
+ target.replaceWith(t__namespace.memberExpression(state.props, t__namespace.identifier(key)));
615
+ }
616
+ function extractJSXExpressionFromNormalAttribute(state, attr) {
617
+ const value = attr.get('value');
618
+ if (isPathValid(value, t__namespace.isJSXElement) ||
619
+ isPathValid(value, t__namespace.isJSXFragment)) {
620
+ value.replaceWith(t__namespace.jsxExpressionContainer(value.node));
621
+ }
622
+ if (isPathValid(value, t__namespace.isJSXExpressionContainer)) {
623
+ extractJSXExpressionsFromJSXExpressionContainer(state, value);
624
+ }
625
+ }
626
+ function extractJSXExpressionFromRef(state, attr) {
627
+ const value = attr.get('value');
628
+ if (isPathValid(value, t__namespace.isJSXExpressionContainer)) {
629
+ const expr = value.get('expression');
630
+ if (isPathValid(expr, t__namespace.isExpression)) {
631
+ const unwrappedIdentifier = unwrapNode(expr.node, t__namespace.isIdentifier);
632
+ let replacement;
633
+ if (unwrappedIdentifier) {
634
+ const arg = expr.scope.generateUidIdentifier('arg');
635
+ replacement = t__namespace.arrowFunctionExpression([arg], t__namespace.blockStatement([
636
+ t__namespace.ifStatement(t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', unwrappedIdentifier), t__namespace.stringLiteral('function')), t__namespace.blockStatement([
637
+ t__namespace.expressionStatement(t__namespace.callExpression(unwrappedIdentifier, [arg])),
638
+ ]), t__namespace.blockStatement([
639
+ t__namespace.expressionStatement(t__namespace.assignmentExpression('=', unwrappedIdentifier, arg)),
640
+ ])),
641
+ ]));
435
642
  }
436
- },
437
- });
643
+ else {
644
+ replacement = expr.node;
645
+ }
646
+ pushAttributeAndReplace(state, expr, replacement);
647
+ }
648
+ }
438
649
  }
439
- function unwrapExpression(node, key) {
440
- switch (node.type) {
441
- case 'ParenthesizedExpression':
442
- case 'TypeCastExpression':
443
- case 'TSAsExpression':
444
- case 'TSSatisfiesExpression':
445
- case 'TSNonNullExpression':
446
- case 'TSInstantiationExpression':
447
- case 'TSTypeAssertion':
448
- return unwrapExpression(node.expression, key);
449
- default:
450
- return key(node) ? node : undefined;
650
+ function extractJSXExpressionFromUseDirective(state, id, attr) {
651
+ const value = attr.get('value');
652
+ if (isPathValid(value, t__namespace.isJSXExpressionContainer)) {
653
+ extractJSXExpressionsFromJSXExpressionContainer(state, value);
451
654
  }
655
+ const key = pushAttribute(state, t__namespace.identifier(id.name));
656
+ state.vars.push(t__namespace.variableDeclarator(t__namespace.identifier(id.name), t__namespace.memberExpression(state.props, t__namespace.identifier(key))));
452
657
  }
453
- function isIdentifierValidCallee(state, path, callee, target) {
454
- const binding = path.scope.getBindingIdentifier(callee.name);
455
- if (binding) {
456
- const result = state.registrations.identifiers.get(binding);
457
- if (result && result.type === target) {
458
- return true;
658
+ function extractJSXExpressionFromAttribute(state, attr) {
659
+ const key = attr.get('name');
660
+ if (isPathValid(key, t__namespace.isJSXIdentifier)) {
661
+ if (key.node.name === 'ref') {
662
+ extractJSXExpressionFromRef(state, attr);
663
+ }
664
+ else {
665
+ extractJSXExpressionFromNormalAttribute(state, attr);
666
+ }
667
+ }
668
+ else if (isPathValid(key, t__namespace.isJSXNamespacedName)) {
669
+ if (key.node.namespace.name === 'use') {
670
+ extractJSXExpressionFromUseDirective(state, key.node.name, attr);
671
+ }
672
+ else {
673
+ extractJSXExpressionFromNormalAttribute(state, attr);
459
674
  }
460
675
  }
461
- return false;
462
676
  }
463
- function isPropertyValidCallee(result, target, propName) {
464
- for (let i = 0, len = result.length; i < len; i++) {
465
- const registration = result[i];
466
- if (registration.type === target) {
467
- if (registration.kind === 'default') {
468
- if (propName === 'default') {
469
- return true;
470
- }
471
- }
472
- else if (registration.kind === 'named' &&
473
- registration.name === propName) {
474
- return true;
475
- }
677
+ function extractJSXExpressionsFromAttributes(state, path) {
678
+ const openingElement = path.get('openingElement');
679
+ const attrs = openingElement.get('attributes');
680
+ for (let i = 0, len = attrs.length; i < len; i++) {
681
+ const attr = attrs[i];
682
+ if (isPathValid(attr, t__namespace.isJSXAttribute)) {
683
+ extractJSXExpressionFromAttribute(state, attr);
684
+ }
685
+ if (isPathValid(attr, t__namespace.isJSXSpreadAttribute)) {
686
+ const arg = attr.get('argument');
687
+ pushAttributeAndReplace(state, arg, arg.node);
476
688
  }
477
689
  }
478
- return false;
479
690
  }
480
- function isMemberExpressionValidCallee(state, path, member, target) {
481
- if (!t__namespace.isIdentifier(member.property)) {
482
- return false;
691
+ function convertJSXOpeningToExpression(node) {
692
+ if (t__namespace.isJSXIdentifier(node)) {
693
+ return t__namespace.identifier(node.name);
483
694
  }
484
- const trueObject = unwrapExpression(member.object, t__namespace.isIdentifier);
485
- if (!trueObject) {
486
- return false;
695
+ return t__namespace.memberExpression(convertJSXOpeningToExpression(node.object), convertJSXOpeningToExpression(node.property));
696
+ }
697
+ function extractJSXExpressionsFromJSXElement(state, path) {
698
+ const openingElement = path.get('openingElement');
699
+ const openingName = openingElement.get('name');
700
+ if ((isPathValid(openingName, t__namespace.isJSXIdentifier) &&
701
+ /^[A-Z_]/.test(openingName.node.name)) ||
702
+ isPathValid(openingName, t__namespace.isJSXMemberExpression)) {
703
+ const key = pushAttribute(state, convertJSXOpeningToExpression(openingName.node));
704
+ const replacement = t__namespace.jsxMemberExpression(t__namespace.jsxIdentifier(state.props.name), t__namespace.jsxIdentifier(key));
705
+ openingName.replaceWith(replacement);
706
+ const closingElement = path.get('closingElement');
707
+ if (isPathValid(closingElement, t__namespace.isJSXClosingElement)) {
708
+ closingElement.get('name').replaceWith(replacement);
709
+ }
487
710
  }
488
- const binding = path.scope.getBindingIdentifier(trueObject.name);
489
- if (!binding) {
490
- return false;
711
+ extractJSXExpressionsFromAttributes(state, path);
712
+ }
713
+ function extractJSXExpressionsFromJSXExpressionContainer(state, child) {
714
+ const expr = child.get('expression');
715
+ if (isPathValid(expr, t__namespace.isExpression)) {
716
+ pushAttributeAndReplace(state, expr, expr.node);
491
717
  }
492
- const result = state.registrations.namespaces.get(binding);
493
- if (!result) {
494
- return false;
718
+ }
719
+ function extractJSXExpressionsFromJSXSpreadChild(state, child) {
720
+ const arg = child.get('expression');
721
+ pushAttributeAndReplace(state, arg, arg.node);
722
+ }
723
+ function extractJSXExpressions(state, path) {
724
+ if (isPathValid(path, t__namespace.isJSXElement)) {
725
+ extractJSXExpressionsFromJSXElement(state, path);
726
+ }
727
+ const children = path.get('children');
728
+ for (let i = 0, len = children.length; i < len; i++) {
729
+ const child = children[i];
730
+ if (isPathValid(child, t__namespace.isJSXElement) ||
731
+ isPathValid(child, t__namespace.isJSXFragment)) {
732
+ extractJSXExpressions(state, child);
733
+ }
734
+ else if (isPathValid(child, t__namespace.isJSXExpressionContainer)) {
735
+ extractJSXExpressionsFromJSXExpressionContainer(state, child);
736
+ }
737
+ else if (isPathValid(child, t__namespace.isJSXSpreadChild)) {
738
+ extractJSXExpressionsFromJSXSpreadChild(state, child);
739
+ }
495
740
  }
496
- return isPropertyValidCallee(result, target, member.property.name);
497
741
  }
498
- function isValidCallee(state, path, { callee }, target) {
499
- if (t__namespace.isV8IntrinsicIdentifier(callee)) {
500
- return false;
742
+ function transformJSX(path) {
743
+ if (shouldSkipJSX(path.node)) {
744
+ return;
501
745
  }
502
- const trueCallee = unwrapExpression(callee, t__namespace.isIdentifier);
503
- if (trueCallee) {
504
- return isIdentifierValidCallee(state, path, trueCallee, target);
746
+ const state = {
747
+ props: path.scope.generateUidIdentifier('props'),
748
+ attributes: [],
749
+ vars: [],
750
+ };
751
+ extractJSXExpressions(state, path);
752
+ const descriptiveName = getDescriptiveName(path, 'template');
753
+ const id = generateUniqueName(path, isComponentishName(descriptiveName)
754
+ ? descriptiveName
755
+ : 'JSX_' + descriptiveName);
756
+ const rootPath = getRootStatementPath(path);
757
+ let template = skippableJSX(t__namespace.cloneNode(path.node));
758
+ if (state.vars.length) {
759
+ template = t__namespace.blockStatement([
760
+ t__namespace.variableDeclaration('const', state.vars),
761
+ t__namespace.returnStatement(template),
762
+ ]);
505
763
  }
506
- const trueMember = unwrapExpression(callee, t__namespace.isMemberExpression);
507
- if (trueMember && !trueMember.computed) {
508
- return isMemberExpressionValidCallee(state, path, trueMember, target);
764
+ const templateComp = t__namespace.arrowFunctionExpression([state.props], template);
765
+ if (path.node.loc) {
766
+ templateComp.loc = path.node.loc;
509
767
  }
510
- return false;
768
+ rootPath.insertBefore(t__namespace.variableDeclaration('const', [t__namespace.variableDeclarator(id, templateComp)]));
769
+ path.replaceWith(skippableJSX(t__namespace.jsxElement(t__namespace.jsxOpeningElement(t__namespace.jsxIdentifier(id.name), [...state.attributes], true), t__namespace.jsxClosingElement(t__namespace.jsxIdentifier(id.name)), [], true)));
770
+ }
771
+
772
+ // https://github.com/babel/babel/issues/15269
773
+ let generator;
774
+ if (typeof _generator !== 'function') {
775
+ generator = _generator.default;
776
+ }
777
+ else {
778
+ generator = _generator;
779
+ }
780
+ function generateCode(node) {
781
+ return generator(node).code;
782
+ }
783
+
784
+ const CWD = process.cwd();
785
+ function getFile(filename) {
786
+ return path.relative(CWD, filename);
787
+ }
788
+ function createSignatureValue(node) {
789
+ const code = generateCode(node);
790
+ const result = xxHash32(code).toString(16);
791
+ return result;
792
+ }
793
+ function captureIdentifiers(state, path) {
794
+ path.traverse({
795
+ ImportDeclaration(p) {
796
+ if (p.node.importKind === 'value') {
797
+ registerImportSpecifiers(state, p, state.specifiers);
798
+ }
799
+ },
800
+ });
511
801
  }
512
802
  function checkValidRenderCall(path) {
513
803
  let currentPath = path.parentPath;
@@ -525,7 +815,7 @@ function checkValidRenderCall(path) {
525
815
  function fixRenderCalls(state, path) {
526
816
  path.traverse({
527
817
  ExpressionStatement(p) {
528
- const trueCallExpr = unwrapExpression(p.node.expression, t__namespace.isCallExpression);
818
+ const trueCallExpr = unwrapNode(p.node.expression, t__namespace.isCallExpression);
529
819
  if (trueCallExpr &&
530
820
  checkValidRenderCall(p) &&
531
821
  isValidCallee(state, p, trueCallExpr, 'render')) {
@@ -546,7 +836,7 @@ function wrapComponent(state, path, identifier, component, original = component)
546
836
  if (statementPath) {
547
837
  const registry = createRegistry(state, statementPath);
548
838
  const hotName = t__namespace.stringLiteral(identifier.name);
549
- const componentCall = getSolidRefreshIdentifier(state, statementPath, IMPORTS.component);
839
+ const componentCall = getImportIdentifier(state, statementPath, IMPORT_COMPONENT);
550
840
  const properties = [];
551
841
  if (state.filename && original.loc) {
552
842
  const filePath = getFile(state.filename);
@@ -554,7 +844,7 @@ function wrapComponent(state, path, identifier, component, original = component)
554
844
  }
555
845
  if (state.granular) {
556
846
  properties.push(t__namespace.objectProperty(t__namespace.identifier('signature'), t__namespace.stringLiteral(createSignatureValue(component))));
557
- const dependencies = getBindings(path);
847
+ const dependencies = getForeignBindings(path);
558
848
  if (dependencies.length) {
559
849
  const dependencyKeys = [];
560
850
  let id;
@@ -564,18 +854,12 @@ function wrapComponent(state, path, identifier, component, original = component)
564
854
  }
565
855
  properties.push(t__namespace.objectProperty(t__namespace.identifier('dependencies'), t__namespace.arrowFunctionExpression([], t__namespace.objectExpression(dependencyKeys))));
566
856
  }
567
- return t__namespace.callExpression(componentCall, [
568
- registry,
569
- hotName,
570
- component,
571
- t__namespace.objectExpression(properties),
572
- ]);
573
857
  }
574
858
  return t__namespace.callExpression(componentCall, [
575
859
  registry,
576
860
  hotName,
577
861
  component,
578
- ...(properties.length ? [t__namespace.objectExpression(properties)] : []),
862
+ t__namespace.objectExpression(properties),
579
863
  ]);
580
864
  }
581
865
  return component;
@@ -585,21 +869,15 @@ function wrapContext(state, path, identifier, context) {
585
869
  if (statementPath) {
586
870
  const registry = createRegistry(state, statementPath);
587
871
  const hotName = t__namespace.stringLiteral(identifier.name);
588
- const contextCall = getSolidRefreshIdentifier(state, statementPath, IMPORTS.context);
872
+ const contextCall = getImportIdentifier(state, statementPath, IMPORT_CONTEXT);
589
873
  return t__namespace.callExpression(contextCall, [registry, hotName, context]);
590
874
  }
591
875
  return context;
592
876
  }
593
- function setupProgram(state, path) {
594
- var _a;
877
+ function setupProgram(state, path, comments) {
595
878
  let shouldSkip = false;
596
- const comments = state.file.ast.comments;
597
879
  if (comments) {
598
880
  for (const { value: comment } of comments) {
599
- if (/^\s*@refresh granular\s*$/.test(comment)) {
600
- state.granular = true;
601
- break;
602
- }
603
881
  if (/^\s*@refresh skip\s*$/.test(comment)) {
604
882
  state.processed = true;
605
883
  shouldSkip = true;
@@ -613,39 +891,20 @@ function setupProgram(state, path) {
613
891
  }
614
892
  }
615
893
  captureIdentifiers(state, path);
616
- if (!shouldSkip && ((_a = state.opts.fixRender) !== null && _a !== void 0 ? _a : true)) {
894
+ if (!shouldSkip && state.fixRender) {
617
895
  fixRenderCalls(state, path);
618
896
  }
619
897
  }
620
- function transformExportNamedDeclaration(state, path) {
621
- if (state.processed) {
622
- return;
623
- }
624
- const decl = path.node.declaration;
625
- // Check if declaration is FunctionDeclaration
626
- if (t__namespace.isFunctionDeclaration(decl) &&
627
- !(decl.generator || decl.async) &&
628
- // Might be component-like, but the only valid components
629
- // have zero or one parameter
630
- decl.params.length < 2) {
631
- // Check if the declaration has an identifier, and then check
632
- // if the name is component-ish
633
- if (decl.id && isComponentishName(decl.id.name)) {
634
- path.node.declaration = t__namespace.variableDeclaration('const', [
635
- t__namespace.variableDeclarator(decl.id, wrapComponent(state, path, decl.id, t__namespace.functionExpression(decl.id, decl.params, decl.body), decl)),
636
- ]);
637
- }
638
- }
639
- }
640
898
  function isStatementTopLevel(path) {
899
+ let blockParent = path.scope.getBlockParent();
641
900
  const programParent = path.scope.getProgramParent();
642
- const blockParent = path.scope.getBlockParent();
901
+ // a FunctionDeclaration binding refers to itself as the block parent
902
+ if (blockParent.path === path) {
903
+ blockParent = blockParent.parent;
904
+ }
643
905
  return programParent === blockParent;
644
906
  }
645
907
  function transformVariableDeclarator(state, path) {
646
- if (state.processed) {
647
- return;
648
- }
649
908
  if (path.parentPath.isVariableDeclaration() &&
650
909
  !isStatementTopLevel(path.parentPath)) {
651
910
  return;
@@ -656,8 +915,8 @@ function transformVariableDeclarator(state, path) {
656
915
  return;
657
916
  }
658
917
  if (isComponentishName(identifier.name)) {
659
- const trueFuncExpr = unwrapExpression(init, t__namespace.isFunctionExpression) ||
660
- unwrapExpression(init, t__namespace.isArrowFunctionExpression);
918
+ const trueFuncExpr = unwrapNode(init, t__namespace.isFunctionExpression) ||
919
+ unwrapNode(init, t__namespace.isArrowFunctionExpression);
661
920
  // Check for valid FunctionExpression or ArrowFunctionExpression
662
921
  if (trueFuncExpr &&
663
922
  // Must not be async or generator
@@ -669,73 +928,111 @@ function transformVariableDeclarator(state, path) {
669
928
  }
670
929
  }
671
930
  // For `createContext` calls
672
- const trueCallExpr = unwrapExpression(init, t__namespace.isCallExpression);
931
+ const trueCallExpr = unwrapNode(init, t__namespace.isCallExpression);
673
932
  if (trueCallExpr &&
674
933
  isValidCallee(state, path, trueCallExpr, 'createContext')) {
675
934
  path.node.init = wrapContext(state, path, identifier, trueCallExpr);
676
935
  }
936
+ path.skip();
937
+ }
938
+ function transformFunctionDeclaration(state, path) {
939
+ if (isStatementTopLevel(path)) {
940
+ const decl = path.node;
941
+ // Check if declaration is FunctionDeclaration
942
+ if (
943
+ // Check if the declaration has an identifier, and then check
944
+ decl.id &&
945
+ // if the name is component-ish
946
+ isComponentishName(decl.id.name) &&
947
+ !(decl.generator || decl.async) &&
948
+ // Might be component-like, but the only valid components
949
+ // have zero or one parameter
950
+ decl.params.length < 2) {
951
+ path.replaceWith(t__namespace.variableDeclaration('const', [
952
+ t__namespace.variableDeclarator(decl.id, wrapComponent(state, path, decl.id, t__namespace.functionExpression(decl.id, decl.params, decl.body), decl)),
953
+ ]));
954
+ path.skip();
955
+ }
956
+ }
957
+ }
958
+ function bubbleFunctionDeclaration(program, path) {
959
+ if (isStatementTopLevel(path)) {
960
+ const decl = path.node;
961
+ // Check if declaration is FunctionDeclaration
962
+ if (
963
+ // Check if the declaration has an identifier, and then check
964
+ decl.id &&
965
+ // if the name is component-ish
966
+ isComponentishName(decl.id.name) &&
967
+ !(decl.generator || decl.async) &&
968
+ // Might be component-like, but the only valid components
969
+ // have zero or one parameter
970
+ decl.params.length < 2) {
971
+ const first = program.get('body')[0];
972
+ const [tmp] = first.insertBefore(decl);
973
+ tmp.skip();
974
+ if (path.parentPath.isExportNamedDeclaration()) {
975
+ path.parentPath.replaceWith(t__namespace.exportNamedDeclaration(undefined, [
976
+ t__namespace.exportSpecifier(decl.id, decl.id),
977
+ ]));
978
+ }
979
+ else if (path.parentPath.isExportDefaultDeclaration()) {
980
+ path.replaceWith(decl.id);
981
+ }
982
+ else {
983
+ path.remove();
984
+ }
985
+ }
986
+ }
677
987
  }
678
988
  function solidRefreshPlugin() {
679
989
  return {
680
- name: 'Solid Refresh',
681
- pre() {
682
- this.hooks = new Map();
683
- this.processed = false;
684
- this.granular = false;
685
- this.registrations = {
686
- identifiers: new Map(),
687
- namespaces: new Map(),
688
- };
689
- this.imports = [...IMPORT_IDENTITIES, ...(this.opts.imports || [])];
690
- },
990
+ name: 'solid-refresh',
691
991
  visitor: {
692
- Program(programPath, state) {
693
- setupProgram(state, programPath);
992
+ Program(programPath, context) {
993
+ var _a, _b;
994
+ const state = {
995
+ granular: (_a = context.opts.granular) !== null && _a !== void 0 ? _a : true,
996
+ opts: context.opts,
997
+ specifiers: [...IMPORT_SPECIFIERS],
998
+ imports: new Map(),
999
+ registrations: {
1000
+ identifiers: new Map(),
1001
+ namespaces: new Map(),
1002
+ },
1003
+ processed: false,
1004
+ filename: context.filename,
1005
+ bundler: context.opts.bundler || 'standard',
1006
+ fixRender: (_b = context.opts.fixRender) !== null && _b !== void 0 ? _b : true,
1007
+ };
1008
+ setupProgram(state, programPath, context.file.ast.comments);
1009
+ if (state.processed) {
1010
+ return;
1011
+ }
1012
+ programPath.traverse({
1013
+ FunctionDeclaration(path) {
1014
+ bubbleFunctionDeclaration(programPath, path);
1015
+ },
1016
+ });
1017
+ programPath.scope.crawl();
694
1018
  programPath.traverse({
695
- ExportNamedDeclaration(path) {
696
- transformExportNamedDeclaration(state, path);
1019
+ JSXElement(path) {
1020
+ transformJSX(path);
1021
+ },
1022
+ JSXFragment(path) {
1023
+ transformJSX(path);
697
1024
  },
1025
+ });
1026
+ programPath.scope.crawl();
1027
+ programPath.traverse({
698
1028
  VariableDeclarator(path) {
699
1029
  transformVariableDeclarator(state, path);
700
1030
  },
701
1031
  FunctionDeclaration(path) {
702
- if (state.processed) {
703
- return;
704
- }
705
- if (path.parentPath.isProgram() ||
706
- path.parentPath.isExportDefaultDeclaration()) {
707
- const decl = path.node;
708
- // Check if declaration is FunctionDeclaration
709
- if (
710
- // Check if the declaration has an identifier, and then check
711
- decl.id &&
712
- // if the name is component-ish
713
- isComponentishName(decl.id.name) &&
714
- !(decl.generator || decl.async) &&
715
- // Might be component-like, but the only valid components
716
- // have zero or one parameter
717
- decl.params.length < 2) {
718
- const replacement = wrapComponent(state, path, decl.id, t__namespace.functionExpression(decl.id, decl.params, decl.body), decl);
719
- const newDecl = t__namespace.variableDeclaration('var', [
720
- t__namespace.variableDeclarator(decl.id, replacement),
721
- ]);
722
- if (path.parentPath.isExportDefaultDeclaration()) {
723
- const parent = path.parentPath
724
- .parentPath;
725
- const first = parent.get('body')[0];
726
- first.insertBefore(newDecl);
727
- path.replaceWith(decl.id);
728
- }
729
- else {
730
- const parent = path.parentPath;
731
- const first = parent.get('body')[0];
732
- first.insertBefore(newDecl);
733
- path.remove();
734
- }
735
- }
736
- }
1032
+ transformFunctionDeclaration(state, path);
737
1033
  },
738
1034
  });
1035
+ programPath.scope.crawl();
739
1036
  },
740
1037
  },
741
1038
  };