babel-plugin-essor 0.0.17-beta.5 → 0.0.17-beta.6

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.
package/dist/index.cjs CHANGED
@@ -609,6 +609,8 @@ function checkHasJSXReturn(path) {
609
609
  var HMR_COMPONENT_NAME = "__$createHMRComponent$__";
610
610
  var WHITESPACE_REGEX = /\s+/g;
611
611
  var PATH_SEPARATOR_REGEX = /[/\\]/;
612
+ var ESSOR_IMPORT = "essor";
613
+ var HMR_IMPORTS = /* @__PURE__ */ new Set(["createApp", "hydrate", "createComponent"]);
612
614
  function getFileBasename(ctx) {
613
615
  const filename = ctx.options.filename;
614
616
  const segments = filename.split(PATH_SEPARATOR_REGEX);
@@ -675,6 +677,65 @@ function collectFromStatement(statementPath, ctx) {
675
677
  }
676
678
  }
677
679
  }
680
+ function isComponentDeclarationExport(statementPath) {
681
+ const declarationPath = unwrapTopLevelDeclaration(statementPath);
682
+ if (!declarationPath) {
683
+ return false;
684
+ }
685
+ if (declarationPath.isFunctionDeclaration()) {
686
+ return checkHasJSXReturn(declarationPath);
687
+ }
688
+ if (!declarationPath.isVariableDeclaration()) {
689
+ return false;
690
+ }
691
+ const declarations = declarationPath.get("declarations");
692
+ if (declarations.length === 0) {
693
+ return false;
694
+ }
695
+ return declarations.every((variablePath) => {
696
+ const initPath = variablePath.get("init");
697
+ return isFunctionLikeExpressionPath(initPath) && checkHasJSXReturn(initPath);
698
+ });
699
+ }
700
+ function hasOnlyComponentSpecifiers(statementPath, componentNames) {
701
+ const { node } = statementPath;
702
+ if (node.declaration || node.source || node.specifiers.length === 0) {
703
+ return false;
704
+ }
705
+ return node.specifiers.every((specifier) => {
706
+ return core.types.isExportSpecifier(specifier) && core.types.isIdentifier(specifier.local) && componentNames.has(specifier.local.name);
707
+ });
708
+ }
709
+ function hasNonComponentExport(programPath, componentNames) {
710
+ for (const statementPath of programPath.get("body")) {
711
+ if (!statementPath.isExportNamedDeclaration() && !statementPath.isExportDefaultDeclaration()) {
712
+ continue;
713
+ }
714
+ if (isTypeOnlyExport(statementPath)) {
715
+ continue;
716
+ }
717
+ if (statementPath.isExportNamedDeclaration() && hasOnlyComponentSpecifiers(statementPath, componentNames)) {
718
+ continue;
719
+ }
720
+ if (!isComponentDeclarationExport(statementPath)) {
721
+ return true;
722
+ }
723
+ }
724
+ return false;
725
+ }
726
+ function isTypeOnlyExport(statementPath) {
727
+ if (!statementPath.isExportNamedDeclaration()) {
728
+ return false;
729
+ }
730
+ const { declaration, exportKind, specifiers } = statementPath.node;
731
+ if (exportKind === "type") {
732
+ return true;
733
+ }
734
+ if (core.types.isTSTypeAliasDeclaration(declaration) || core.types.isTSInterfaceDeclaration(declaration)) {
735
+ return true;
736
+ }
737
+ return specifiers.length > 0 && specifiers.every((specifier) => "exportKind" in specifier && specifier.exportKind === "type");
738
+ }
678
739
  function getMetadataTargets(statementPath, ctx) {
679
740
  const declarationPath = unwrapTopLevelDeclaration(statementPath);
680
741
  if (!declarationPath) {
@@ -747,22 +808,101 @@ function isCreateHMRComponentCall(value) {
747
808
  function canWrapArgument(value) {
748
809
  return !!value && !core.types.isSpreadElement(value) && !core.types.isArgumentPlaceholder(value);
749
810
  }
750
- function wrapComponentCreationCalls(programPath, ctx) {
811
+ function getEssorHmrBindings(programPath) {
812
+ const bindings = {
813
+ createComponent: /* @__PURE__ */ new Map(),
814
+ mount: /* @__PURE__ */ new Map()
815
+ };
816
+ for (const statementPath of programPath.get("body")) {
817
+ if (!statementPath.isImportDeclaration() || statementPath.node.source.value !== ESSOR_IMPORT) {
818
+ continue;
819
+ }
820
+ for (const specifier of statementPath.node.specifiers) {
821
+ if (!core.types.isImportSpecifier(specifier)) {
822
+ continue;
823
+ }
824
+ const imported = specifier.imported;
825
+ const name = core.types.isIdentifier(imported) ? imported.name : imported.value;
826
+ if (!HMR_IMPORTS.has(name)) {
827
+ continue;
828
+ }
829
+ if (name === "createComponent") {
830
+ const binding = statementPath.scope.getBinding(specifier.local.name);
831
+ if (binding) {
832
+ bindings.createComponent.set(specifier.local.name, binding);
833
+ }
834
+ } else {
835
+ const binding = statementPath.scope.getBinding(specifier.local.name);
836
+ if (binding) {
837
+ bindings.mount.set(specifier.local.name, binding);
838
+ }
839
+ }
840
+ }
841
+ }
842
+ return bindings;
843
+ }
844
+ function hasImportBinding(path, name, bindings) {
845
+ return bindings.has(name) && path.scope.getBinding(name) === bindings.get(name);
846
+ }
847
+ function isMountCallee(callPath, bindings) {
848
+ const { callee } = callPath.node;
849
+ return core.types.isIdentifier(callee) && hasImportBinding(callPath, callee.name, bindings.mount);
850
+ }
851
+ function createImportMetaHot() {
852
+ return core.types.memberExpression(
853
+ core.types.metaProperty(core.types.identifier("import"), core.types.identifier("meta")),
854
+ core.types.identifier("hot")
855
+ );
856
+ }
857
+ function createDisposeStatement(appId) {
858
+ const dispose = core.types.optionalMemberExpression(
859
+ createImportMetaHot(),
860
+ core.types.identifier("dispose"),
861
+ false,
862
+ true
863
+ );
864
+ const unmount = core.types.optionalCallExpression(
865
+ core.types.optionalMemberExpression(appId, core.types.identifier("unmount"), false, true),
866
+ [],
867
+ true
868
+ );
869
+ return core.types.expressionStatement(
870
+ core.types.optionalCallExpression(dispose, [core.types.arrowFunctionExpression([], unmount)], false)
871
+ );
872
+ }
873
+ function wrapTopLevelMountDisposals(programPath, bindings) {
874
+ const nextBody = [];
875
+ for (const statementPath of programPath.get("body")) {
876
+ const statement = statementPath.node;
877
+ const expressionPath = statementPath.isExpressionStatement() ? statementPath.get("expression") : null;
878
+ if ((expressionPath == null ? void 0 : expressionPath.isCallExpression()) && isMountCallee(expressionPath, bindings)) {
879
+ const appId = programPath.scope.generateUidIdentifier("app");
880
+ nextBody.push(
881
+ core.types.variableDeclaration("const", [core.types.variableDeclarator(appId, expressionPath.node)])
882
+ );
883
+ nextBody.push(createDisposeStatement(appId));
884
+ continue;
885
+ }
886
+ nextBody.push(statement);
887
+ }
888
+ programPath.node.body = nextBody;
889
+ }
890
+ function wrapComponentCreationCalls(programPath, ctx, bindings) {
751
891
  programPath.traverse({
752
892
  /**
753
- * Rewrites `createComponent` and `createApp` calls for HMR tracking.
893
+ * Rewrites `createComponent`, `createApp`, and `hydrate` calls for HMR tracking.
754
894
  */
755
895
  CallExpression(callPath) {
756
896
  const { callee } = callPath.node;
757
897
  if (!core.types.isIdentifier(callee)) return;
758
- if (callee.name === ctx.importIdentifiers.createComponent.name) {
898
+ if (callee.name === ctx.importIdentifiers.createComponent.name || hasImportBinding(callPath, callee.name, bindings.createComponent)) {
759
899
  const firstArg = callPath.node.arguments[0];
760
900
  if (canWrapArgument(firstArg)) {
761
901
  callPath.node.callee = core.types.identifier(HMR_COMPONENT_NAME);
762
902
  }
763
903
  return;
764
904
  }
765
- if (callee.name === "createApp") {
905
+ if (isMountCallee(callPath, bindings)) {
766
906
  const args = callPath.node.arguments;
767
907
  if (args.length === 0) return;
768
908
  if (isCreateHMRComponentCall(args[0])) {
@@ -782,6 +922,10 @@ function collectTopLevelHmrComponents(programPath, ctx) {
782
922
  for (const statementPath of programPath.get("body")) {
783
923
  collectFromStatement(statementPath, ctx);
784
924
  }
925
+ if (hasNonComponentExport(programPath, ctx.hmrComponents)) {
926
+ ctx.hmrComponents.clear();
927
+ ctx.hmrSignatures.clear();
928
+ }
785
929
  }
786
930
  function applyHmr(programPath, ctx) {
787
931
  if (!ctx.options.hmr || !ctx.options.bundler) {
@@ -790,10 +934,12 @@ function applyHmr(programPath, ctx) {
790
934
  if (ctx.hmrComponents.size > 0) {
791
935
  injectComponentMetadata(programPath, ctx);
792
936
  }
793
- wrapComponentCreationCalls(programPath, ctx);
937
+ const bindings = getEssorHmrBindings(programPath);
938
+ wrapComponentCreationCalls(programPath, ctx, bindings);
794
939
  if (ctx.hmrComponents.size === 0) {
795
940
  return;
796
941
  }
942
+ wrapTopLevelMountDisposals(programPath, bindings);
797
943
  programPath.node.body.push(
798
944
  core.types.variableDeclaration("const", [
799
945
  core.types.variableDeclarator(
package/dist/index.js CHANGED
@@ -607,6 +607,8 @@ function checkHasJSXReturn(path) {
607
607
  var HMR_COMPONENT_NAME = "__$createHMRComponent$__";
608
608
  var WHITESPACE_REGEX = /\s+/g;
609
609
  var PATH_SEPARATOR_REGEX = /[/\\]/;
610
+ var ESSOR_IMPORT = "essor";
611
+ var HMR_IMPORTS = /* @__PURE__ */ new Set(["createApp", "hydrate", "createComponent"]);
610
612
  function getFileBasename(ctx) {
611
613
  const filename = ctx.options.filename;
612
614
  const segments = filename.split(PATH_SEPARATOR_REGEX);
@@ -673,6 +675,65 @@ function collectFromStatement(statementPath, ctx) {
673
675
  }
674
676
  }
675
677
  }
678
+ function isComponentDeclarationExport(statementPath) {
679
+ const declarationPath = unwrapTopLevelDeclaration(statementPath);
680
+ if (!declarationPath) {
681
+ return false;
682
+ }
683
+ if (declarationPath.isFunctionDeclaration()) {
684
+ return checkHasJSXReturn(declarationPath);
685
+ }
686
+ if (!declarationPath.isVariableDeclaration()) {
687
+ return false;
688
+ }
689
+ const declarations = declarationPath.get("declarations");
690
+ if (declarations.length === 0) {
691
+ return false;
692
+ }
693
+ return declarations.every((variablePath) => {
694
+ const initPath = variablePath.get("init");
695
+ return isFunctionLikeExpressionPath(initPath) && checkHasJSXReturn(initPath);
696
+ });
697
+ }
698
+ function hasOnlyComponentSpecifiers(statementPath, componentNames) {
699
+ const { node } = statementPath;
700
+ if (node.declaration || node.source || node.specifiers.length === 0) {
701
+ return false;
702
+ }
703
+ return node.specifiers.every((specifier) => {
704
+ return types.isExportSpecifier(specifier) && types.isIdentifier(specifier.local) && componentNames.has(specifier.local.name);
705
+ });
706
+ }
707
+ function hasNonComponentExport(programPath, componentNames) {
708
+ for (const statementPath of programPath.get("body")) {
709
+ if (!statementPath.isExportNamedDeclaration() && !statementPath.isExportDefaultDeclaration()) {
710
+ continue;
711
+ }
712
+ if (isTypeOnlyExport(statementPath)) {
713
+ continue;
714
+ }
715
+ if (statementPath.isExportNamedDeclaration() && hasOnlyComponentSpecifiers(statementPath, componentNames)) {
716
+ continue;
717
+ }
718
+ if (!isComponentDeclarationExport(statementPath)) {
719
+ return true;
720
+ }
721
+ }
722
+ return false;
723
+ }
724
+ function isTypeOnlyExport(statementPath) {
725
+ if (!statementPath.isExportNamedDeclaration()) {
726
+ return false;
727
+ }
728
+ const { declaration, exportKind, specifiers } = statementPath.node;
729
+ if (exportKind === "type") {
730
+ return true;
731
+ }
732
+ if (types.isTSTypeAliasDeclaration(declaration) || types.isTSInterfaceDeclaration(declaration)) {
733
+ return true;
734
+ }
735
+ return specifiers.length > 0 && specifiers.every((specifier) => "exportKind" in specifier && specifier.exportKind === "type");
736
+ }
676
737
  function getMetadataTargets(statementPath, ctx) {
677
738
  const declarationPath = unwrapTopLevelDeclaration(statementPath);
678
739
  if (!declarationPath) {
@@ -745,22 +806,101 @@ function isCreateHMRComponentCall(value) {
745
806
  function canWrapArgument(value) {
746
807
  return !!value && !types.isSpreadElement(value) && !types.isArgumentPlaceholder(value);
747
808
  }
748
- function wrapComponentCreationCalls(programPath, ctx) {
809
+ function getEssorHmrBindings(programPath) {
810
+ const bindings = {
811
+ createComponent: /* @__PURE__ */ new Map(),
812
+ mount: /* @__PURE__ */ new Map()
813
+ };
814
+ for (const statementPath of programPath.get("body")) {
815
+ if (!statementPath.isImportDeclaration() || statementPath.node.source.value !== ESSOR_IMPORT) {
816
+ continue;
817
+ }
818
+ for (const specifier of statementPath.node.specifiers) {
819
+ if (!types.isImportSpecifier(specifier)) {
820
+ continue;
821
+ }
822
+ const imported = specifier.imported;
823
+ const name = types.isIdentifier(imported) ? imported.name : imported.value;
824
+ if (!HMR_IMPORTS.has(name)) {
825
+ continue;
826
+ }
827
+ if (name === "createComponent") {
828
+ const binding = statementPath.scope.getBinding(specifier.local.name);
829
+ if (binding) {
830
+ bindings.createComponent.set(specifier.local.name, binding);
831
+ }
832
+ } else {
833
+ const binding = statementPath.scope.getBinding(specifier.local.name);
834
+ if (binding) {
835
+ bindings.mount.set(specifier.local.name, binding);
836
+ }
837
+ }
838
+ }
839
+ }
840
+ return bindings;
841
+ }
842
+ function hasImportBinding(path, name, bindings) {
843
+ return bindings.has(name) && path.scope.getBinding(name) === bindings.get(name);
844
+ }
845
+ function isMountCallee(callPath, bindings) {
846
+ const { callee } = callPath.node;
847
+ return types.isIdentifier(callee) && hasImportBinding(callPath, callee.name, bindings.mount);
848
+ }
849
+ function createImportMetaHot() {
850
+ return types.memberExpression(
851
+ types.metaProperty(types.identifier("import"), types.identifier("meta")),
852
+ types.identifier("hot")
853
+ );
854
+ }
855
+ function createDisposeStatement(appId) {
856
+ const dispose = types.optionalMemberExpression(
857
+ createImportMetaHot(),
858
+ types.identifier("dispose"),
859
+ false,
860
+ true
861
+ );
862
+ const unmount = types.optionalCallExpression(
863
+ types.optionalMemberExpression(appId, types.identifier("unmount"), false, true),
864
+ [],
865
+ true
866
+ );
867
+ return types.expressionStatement(
868
+ types.optionalCallExpression(dispose, [types.arrowFunctionExpression([], unmount)], false)
869
+ );
870
+ }
871
+ function wrapTopLevelMountDisposals(programPath, bindings) {
872
+ const nextBody = [];
873
+ for (const statementPath of programPath.get("body")) {
874
+ const statement = statementPath.node;
875
+ const expressionPath = statementPath.isExpressionStatement() ? statementPath.get("expression") : null;
876
+ if ((expressionPath == null ? void 0 : expressionPath.isCallExpression()) && isMountCallee(expressionPath, bindings)) {
877
+ const appId = programPath.scope.generateUidIdentifier("app");
878
+ nextBody.push(
879
+ types.variableDeclaration("const", [types.variableDeclarator(appId, expressionPath.node)])
880
+ );
881
+ nextBody.push(createDisposeStatement(appId));
882
+ continue;
883
+ }
884
+ nextBody.push(statement);
885
+ }
886
+ programPath.node.body = nextBody;
887
+ }
888
+ function wrapComponentCreationCalls(programPath, ctx, bindings) {
749
889
  programPath.traverse({
750
890
  /**
751
- * Rewrites `createComponent` and `createApp` calls for HMR tracking.
891
+ * Rewrites `createComponent`, `createApp`, and `hydrate` calls for HMR tracking.
752
892
  */
753
893
  CallExpression(callPath) {
754
894
  const { callee } = callPath.node;
755
895
  if (!types.isIdentifier(callee)) return;
756
- if (callee.name === ctx.importIdentifiers.createComponent.name) {
896
+ if (callee.name === ctx.importIdentifiers.createComponent.name || hasImportBinding(callPath, callee.name, bindings.createComponent)) {
757
897
  const firstArg = callPath.node.arguments[0];
758
898
  if (canWrapArgument(firstArg)) {
759
899
  callPath.node.callee = types.identifier(HMR_COMPONENT_NAME);
760
900
  }
761
901
  return;
762
902
  }
763
- if (callee.name === "createApp") {
903
+ if (isMountCallee(callPath, bindings)) {
764
904
  const args = callPath.node.arguments;
765
905
  if (args.length === 0) return;
766
906
  if (isCreateHMRComponentCall(args[0])) {
@@ -780,6 +920,10 @@ function collectTopLevelHmrComponents(programPath, ctx) {
780
920
  for (const statementPath of programPath.get("body")) {
781
921
  collectFromStatement(statementPath, ctx);
782
922
  }
923
+ if (hasNonComponentExport(programPath, ctx.hmrComponents)) {
924
+ ctx.hmrComponents.clear();
925
+ ctx.hmrSignatures.clear();
926
+ }
783
927
  }
784
928
  function applyHmr(programPath, ctx) {
785
929
  if (!ctx.options.hmr || !ctx.options.bundler) {
@@ -788,10 +932,12 @@ function applyHmr(programPath, ctx) {
788
932
  if (ctx.hmrComponents.size > 0) {
789
933
  injectComponentMetadata(programPath, ctx);
790
934
  }
791
- wrapComponentCreationCalls(programPath, ctx);
935
+ const bindings = getEssorHmrBindings(programPath);
936
+ wrapComponentCreationCalls(programPath, ctx, bindings);
792
937
  if (ctx.hmrComponents.size === 0) {
793
938
  return;
794
939
  }
940
+ wrapTopLevelMountDisposals(programPath, bindings);
795
941
  programPath.node.body.push(
796
942
  types.variableDeclaration("const", [
797
943
  types.variableDeclarator(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babel-plugin-essor",
3
- "version": "0.0.17-beta.5",
3
+ "version": "0.0.17-beta.6",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@babel/core": "^7.29.7",
36
36
  "@babel/generator": "^7.29.7",
37
- "@estjs/shared": "0.0.17-beta.5"
37
+ "@estjs/shared": "0.0.17-beta.6"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@babel/traverse": "^7.29.7",