svelte2tsx 0.7.23 → 0.7.25

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 (3) hide show
  1. package/index.js +419 -121
  2. package/index.mjs +419 -121
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -4166,17 +4166,17 @@ function eventMapEntryToString([eventName, expression]) {
4166
4166
  * Creates a hidden folder in the user's node_modules if `hiddenFolderPath` is provided.
4167
4167
  */
4168
4168
  function get_global_types(tsSystem, isSvelte3, sveltePath, typesPath, hiddenFolderPath) {
4169
- const svelteHtmlPath = isSvelte3 ? undefined : path.join(sveltePath, 'svelte-html.d.ts');
4170
- const svelteHtmlPathExists = svelteHtmlPath && tsSystem.fileExists(svelteHtmlPath);
4171
- const svelteHtmlFile = svelteHtmlPathExists ? svelteHtmlPath : './svelte-jsx-v4.d.ts';
4169
+ let svelteHtmlPath = isSvelte3 ? undefined : path.join(sveltePath, 'svelte-html.d.ts');
4170
+ svelteHtmlPath =
4171
+ svelteHtmlPath && tsSystem.fileExists(svelteHtmlPath) ? svelteHtmlPath : undefined;
4172
4172
  let svelteTsxFiles;
4173
4173
  if (isSvelte3) {
4174
4174
  svelteTsxFiles = ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'];
4175
4175
  }
4176
4176
  else {
4177
4177
  svelteTsxFiles = ['./svelte-shims-v4.d.ts', './svelte-native-jsx.d.ts'];
4178
- if (!svelteHtmlPathExists) {
4179
- svelteTsxFiles.push(svelteHtmlPath);
4178
+ if (!svelteHtmlPath) {
4179
+ svelteTsxFiles.push('./svelte-jsx-v4.d.ts');
4180
4180
  }
4181
4181
  }
4182
4182
  svelteTsxFiles = svelteTsxFiles.map((f) => tsSystem.resolvePath(path.resolve(typesPath, f)));
@@ -4203,9 +4203,16 @@ function get_global_types(tsSystem, isSvelte3, sveltePath, typesPath, hiddenFold
4203
4203
  for (const f of svelteTsxFiles) {
4204
4204
  const hiddenFile = path.resolve(hiddenPath, path.basename(f));
4205
4205
  const existing = tsSystem.readFile(hiddenFile);
4206
- const toWrite = tsSystem.readFile(f) || '';
4206
+ const toWrite = tsSystem.readFile(f);
4207
+ if (!toWrite) {
4208
+ throw new Error(`Could not read file: ${f}`);
4209
+ }
4207
4210
  if (existing !== toWrite) {
4208
4211
  tsSystem.writeFile(hiddenFile, toWrite);
4212
+ // TS doesn't throw an error if the file wasn't written
4213
+ if (!tsSystem.fileExists(hiddenFile)) {
4214
+ throw new Error(`Could not write file: ${hiddenFile}`);
4215
+ }
4209
4216
  }
4210
4217
  newFiles.push(hiddenFile);
4211
4218
  }
@@ -4214,8 +4221,8 @@ function get_global_types(tsSystem, isSvelte3, sveltePath, typesPath, hiddenFold
4214
4221
  }
4215
4222
  catch (e) { }
4216
4223
  }
4217
- if (svelteHtmlPathExists) {
4218
- svelteTsxFiles.push(tsSystem.resolvePath(path.resolve(typesPath, svelteHtmlFile)));
4224
+ if (svelteHtmlPath) {
4225
+ svelteTsxFiles.push(tsSystem.resolvePath(path.resolve(typesPath, svelteHtmlPath)));
4219
4226
  }
4220
4227
  return svelteTsxFiles;
4221
4228
  }
@@ -4612,6 +4619,270 @@ function getCurrentPrepends(str, index) {
4612
4619
  return ((_a = str.__prepends__) === null || _a === void 0 ? void 0 : _a.get(index)) || [];
4613
4620
  }
4614
4621
 
4622
+ /**
4623
+ * Collects all imports and module-level declarations to then find out which interfaces/types are hoistable.
4624
+ */
4625
+ class HoistableInterfaces {
4626
+ constructor() {
4627
+ this.import_value_set = new Set();
4628
+ this.import_type_set = new Set();
4629
+ this.interface_map = new Map();
4630
+ this.props_interface = {
4631
+ name: '',
4632
+ node: null,
4633
+ type_deps: new Set(),
4634
+ value_deps: new Set()
4635
+ };
4636
+ }
4637
+ analyzeModuleScriptNode(node) {
4638
+ // Handle Import Declarations
4639
+ if (ts.isImportDeclaration(node) && node.importClause) {
4640
+ const is_type_only = node.importClause.isTypeOnly;
4641
+ if (node.importClause.namedBindings &&
4642
+ ts.isNamedImports(node.importClause.namedBindings)) {
4643
+ node.importClause.namedBindings.elements.forEach((element) => {
4644
+ const import_name = element.name.text;
4645
+ if (is_type_only || element.isTypeOnly) {
4646
+ this.import_type_set.add(import_name);
4647
+ }
4648
+ else {
4649
+ this.import_value_set.add(import_name);
4650
+ }
4651
+ });
4652
+ }
4653
+ // Handle default imports
4654
+ if (node.importClause.name) {
4655
+ const default_import = node.importClause.name.text;
4656
+ if (is_type_only) {
4657
+ this.import_type_set.add(default_import);
4658
+ }
4659
+ else {
4660
+ this.import_value_set.add(default_import);
4661
+ }
4662
+ }
4663
+ // Handle namespace imports
4664
+ if (node.importClause.namedBindings &&
4665
+ ts.isNamespaceImport(node.importClause.namedBindings)) {
4666
+ const namespace_import = node.importClause.namedBindings.name.text;
4667
+ if (is_type_only) {
4668
+ this.import_type_set.add(namespace_import);
4669
+ }
4670
+ else {
4671
+ this.import_value_set.add(namespace_import);
4672
+ }
4673
+ }
4674
+ }
4675
+ // Handle top-level declarations
4676
+ if (ts.isVariableStatement(node)) {
4677
+ node.declarationList.declarations.forEach((declaration) => {
4678
+ if (ts.isIdentifier(declaration.name)) {
4679
+ this.import_value_set.add(declaration.name.text);
4680
+ }
4681
+ });
4682
+ }
4683
+ if (ts.isFunctionDeclaration(node) && node.name) {
4684
+ this.import_value_set.add(node.name.text);
4685
+ }
4686
+ if (ts.isClassDeclaration(node) && node.name) {
4687
+ this.import_value_set.add(node.name.text);
4688
+ }
4689
+ if (ts.isEnumDeclaration(node)) {
4690
+ this.import_value_set.add(node.name.text);
4691
+ }
4692
+ if (ts.isTypeAliasDeclaration(node)) {
4693
+ this.import_type_set.add(node.name.text);
4694
+ }
4695
+ if (ts.isInterfaceDeclaration(node)) {
4696
+ this.import_type_set.add(node.name.text);
4697
+ }
4698
+ }
4699
+ analyzeInstanceScriptNode(node) {
4700
+ var _a, _b, _c, _d;
4701
+ // Handle Import Declarations
4702
+ if (ts.isImportDeclaration(node) && node.importClause) {
4703
+ const is_type_only = node.importClause.isTypeOnly;
4704
+ if (node.importClause.namedBindings &&
4705
+ ts.isNamedImports(node.importClause.namedBindings)) {
4706
+ node.importClause.namedBindings.elements.forEach((element) => {
4707
+ const import_name = element.name.text;
4708
+ if (is_type_only) {
4709
+ this.import_type_set.add(import_name);
4710
+ }
4711
+ else {
4712
+ this.import_value_set.add(import_name);
4713
+ }
4714
+ });
4715
+ }
4716
+ // Handle default imports
4717
+ if (node.importClause.name) {
4718
+ const default_import = node.importClause.name.text;
4719
+ if (is_type_only) {
4720
+ this.import_type_set.add(default_import);
4721
+ }
4722
+ else {
4723
+ this.import_value_set.add(default_import);
4724
+ }
4725
+ }
4726
+ // Handle namespace imports
4727
+ if (node.importClause.namedBindings &&
4728
+ ts.isNamespaceImport(node.importClause.namedBindings)) {
4729
+ const namespace_import = node.importClause.namedBindings.name.text;
4730
+ if (is_type_only) {
4731
+ this.import_type_set.add(namespace_import);
4732
+ }
4733
+ else {
4734
+ this.import_value_set.add(namespace_import);
4735
+ }
4736
+ }
4737
+ }
4738
+ // Handle Interface Declarations
4739
+ if (ts.isInterfaceDeclaration(node)) {
4740
+ const interface_name = node.name.text;
4741
+ const type_dependencies = new Set();
4742
+ const value_dependencies = new Set();
4743
+ const generics = (_b = (_a = node.typeParameters) === null || _a === void 0 ? void 0 : _a.map((param) => param.name.text)) !== null && _b !== void 0 ? _b : [];
4744
+ node.members.forEach((member) => {
4745
+ if (ts.isPropertySignature(member) && member.type) {
4746
+ this.collectTypeDependencies(member.type, type_dependencies, value_dependencies, generics);
4747
+ }
4748
+ else if (ts.isIndexSignatureDeclaration(member)) {
4749
+ this.collectTypeDependencies(member.type, type_dependencies, value_dependencies, generics);
4750
+ member.parameters.forEach((param) => {
4751
+ this.collectTypeDependencies(param.type, type_dependencies, value_dependencies, generics);
4752
+ });
4753
+ }
4754
+ });
4755
+ this.interface_map.set(interface_name, {
4756
+ type_deps: type_dependencies,
4757
+ value_deps: value_dependencies,
4758
+ node
4759
+ });
4760
+ }
4761
+ // Handle Type Alias Declarations
4762
+ if (ts.isTypeAliasDeclaration(node)) {
4763
+ const alias_name = node.name.text;
4764
+ const type_dependencies = new Set();
4765
+ const value_dependencies = new Set();
4766
+ const generics = (_d = (_c = node.typeParameters) === null || _c === void 0 ? void 0 : _c.map((param) => param.name.text)) !== null && _d !== void 0 ? _d : [];
4767
+ this.collectTypeDependencies(node.type, type_dependencies, value_dependencies, generics);
4768
+ this.interface_map.set(alias_name, {
4769
+ type_deps: type_dependencies,
4770
+ value_deps: value_dependencies,
4771
+ node
4772
+ });
4773
+ }
4774
+ }
4775
+ analyze$propsRune(node) {
4776
+ var _a, _b;
4777
+ if (((_a = node.initializer.typeArguments) === null || _a === void 0 ? void 0 : _a.length) > 0 || node.type) {
4778
+ const generic_arg = ((_b = node.initializer.typeArguments) === null || _b === void 0 ? void 0 : _b[0]) || node.type;
4779
+ if (ts.isTypeReferenceNode(generic_arg)) {
4780
+ const name = this.getEntityNameText(generic_arg.typeName);
4781
+ const interface_node = this.interface_map.get(name);
4782
+ if (interface_node) {
4783
+ this.props_interface.name = name;
4784
+ this.props_interface.type_deps = interface_node.type_deps;
4785
+ this.props_interface.value_deps = interface_node.value_deps;
4786
+ }
4787
+ }
4788
+ else {
4789
+ this.props_interface.name = '$$ComponentProps';
4790
+ this.props_interface.node = generic_arg;
4791
+ this.collectTypeDependencies(generic_arg, this.props_interface.type_deps, this.props_interface.value_deps, []);
4792
+ }
4793
+ }
4794
+ }
4795
+ /**
4796
+ * Traverses the AST to collect import statements and top-level interfaces,
4797
+ * then determines which interfaces can be hoisted.
4798
+ * @param source_file The TypeScript source file to analyze.
4799
+ * @returns An object containing sets of value imports, type imports, and hoistable interfaces.
4800
+ */
4801
+ determineHoistableInterfaces() {
4802
+ const hoistable_interfaces = new Map();
4803
+ let progress = true;
4804
+ while (progress) {
4805
+ progress = false;
4806
+ for (const [interface_name, deps] of this.interface_map.entries()) {
4807
+ if (hoistable_interfaces.has(interface_name)) {
4808
+ continue;
4809
+ }
4810
+ const can_hoist = [...deps.type_deps, ...deps.value_deps].every((dep) => {
4811
+ return (this.import_type_set.has(dep) ||
4812
+ this.import_value_set.has(dep) ||
4813
+ hoistable_interfaces.has(dep));
4814
+ });
4815
+ if (can_hoist) {
4816
+ hoistable_interfaces.set(interface_name, deps.node);
4817
+ progress = true;
4818
+ }
4819
+ }
4820
+ }
4821
+ if (this.props_interface.name === '$$ComponentProps') {
4822
+ const can_hoist = [
4823
+ ...this.props_interface.type_deps,
4824
+ ...this.props_interface.value_deps
4825
+ ].every((dep) => {
4826
+ return (this.import_type_set.has(dep) ||
4827
+ this.import_value_set.has(dep) ||
4828
+ hoistable_interfaces.has(dep));
4829
+ });
4830
+ if (can_hoist) {
4831
+ hoistable_interfaces.set(this.props_interface.name, this.props_interface.node);
4832
+ }
4833
+ }
4834
+ return hoistable_interfaces;
4835
+ }
4836
+ /**
4837
+ * Moves all interfaces that can be hoisted to the top of the script, if the $props rune's type is hoistable.
4838
+ */
4839
+ moveHoistableInterfaces(str, astOffset, scriptStart) {
4840
+ if (!this.props_interface.name)
4841
+ return;
4842
+ const hoistable = this.determineHoistableInterfaces();
4843
+ if (hoistable.has(this.props_interface.name)) {
4844
+ for (const [, node] of hoistable) {
4845
+ str.move(node.pos + astOffset, node.end + astOffset, scriptStart);
4846
+ }
4847
+ }
4848
+ }
4849
+ /**
4850
+ * Collects type and value dependencies from a given TypeNode.
4851
+ * @param type_node The TypeNode to analyze.
4852
+ * @param type_dependencies The set to collect type dependencies into.
4853
+ * @param value_dependencies The set to collect value dependencies into.
4854
+ */
4855
+ collectTypeDependencies(type_node, type_dependencies, value_dependencies, generics) {
4856
+ const walk = (node) => {
4857
+ if (ts.isTypeReferenceNode(node)) {
4858
+ const type_name = this.getEntityNameText(node.typeName);
4859
+ if (!generics.includes(type_name)) {
4860
+ type_dependencies.add(type_name);
4861
+ }
4862
+ }
4863
+ else if (ts.isTypeQueryNode(node)) {
4864
+ // Handle 'typeof' expressions: e.g., foo: typeof bar
4865
+ value_dependencies.add(this.getEntityNameText(node.exprName));
4866
+ }
4867
+ ts.forEachChild(node, walk);
4868
+ };
4869
+ walk(type_node);
4870
+ }
4871
+ /**
4872
+ * Retrieves the full text of an EntityName (handles nested names).
4873
+ * @param entity_name The EntityName to extract text from.
4874
+ * @returns The full name as a string.
4875
+ */
4876
+ getEntityNameText(entity_name) {
4877
+ if (ts.isIdentifier(entity_name)) {
4878
+ return entity_name.text;
4879
+ }
4880
+ else {
4881
+ return this.getEntityNameText(entity_name.left) + '.' + entity_name.right.text;
4882
+ }
4883
+ }
4884
+ }
4885
+
4615
4886
  function is$$PropsDeclaration(node) {
4616
4887
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Props';
4617
4888
  }
@@ -4623,6 +4894,7 @@ class ExportedNames {
4623
4894
  this.isTsFile = isTsFile;
4624
4895
  this.isSvelte5Plus = isSvelte5Plus;
4625
4896
  this.isRunes = isRunes;
4897
+ this.hoistableInterfaces = new HoistableInterfaces();
4626
4898
  this.usesAccessors = false;
4627
4899
  /**
4628
4900
  * Uses the `$$Props` type
@@ -4637,7 +4909,9 @@ class ExportedNames {
4637
4909
  * If using TS, this returns the generic string, if using JS, returns the `@type {..}` string.
4638
4910
  */
4639
4911
  this.$props = {
4912
+ /** The JSDoc type; not set when TS type exists */
4640
4913
  comment: '',
4914
+ /** The TS type */
4641
4915
  type: '',
4642
4916
  bindings: []
4643
4917
  };
@@ -4741,10 +5015,12 @@ class ExportedNames {
4741
5015
  }
4742
5016
  }
4743
5017
  }
5018
+ // Easy mode: User uses TypeScript and typed the $props() rune
4744
5019
  if (((_a = node.initializer.typeArguments) === null || _a === void 0 ? void 0 : _a.length) > 0 || node.type) {
5020
+ this.hoistableInterfaces.analyze$propsRune(node);
4745
5021
  const generic_arg = ((_b = node.initializer.typeArguments) === null || _b === void 0 ? void 0 : _b[0]) || node.type;
4746
5022
  const generic = generic_arg.getText();
4747
- if (!generic.includes('{')) {
5023
+ if (ts.isTypeReferenceNode(generic_arg)) {
4748
5024
  this.$props.type = generic;
4749
5025
  }
4750
5026
  else {
@@ -4758,14 +5034,26 @@ class ExportedNames {
4758
5034
  // so that semantic tokens ignore it, preventing an overlap of tokens
4759
5035
  surroundWithIgnoreComments(this.$props.type));
4760
5036
  }
5037
+ return;
4761
5038
  }
4762
- else {
4763
- if (!this.isTsFile) {
4764
- const text = node.getSourceFile().getFullText();
4765
- let start = -1;
4766
- let comment;
4767
- // reverse because we want to look at the last comment before the node first
4768
- for (const c of [...(ts.getLeadingCommentRanges(text, node.pos) || [])].reverse()) {
5039
+ // Hard mode: User uses JSDoc or didn't type the $props() rune
5040
+ if (!this.isTsFile) {
5041
+ const text = node.getSourceFile().getFullText();
5042
+ let start = -1;
5043
+ let comment;
5044
+ // reverse because we want to look at the last comment before the node first
5045
+ for (const c of [...(ts.getLeadingCommentRanges(text, node.pos) || [])].reverse()) {
5046
+ const potential_match = text.substring(c.pos, c.end);
5047
+ if (/@type\b/.test(potential_match)) {
5048
+ comment = potential_match;
5049
+ start = c.pos + this.astOffset;
5050
+ break;
5051
+ }
5052
+ }
5053
+ if (!comment) {
5054
+ for (const c of [
5055
+ ...(ts.getLeadingCommentRanges(text, node.parent.pos) || []).reverse()
5056
+ ]) {
4769
5057
  const potential_match = text.substring(c.pos, c.end);
4770
5058
  if (/@type\b/.test(potential_match)) {
4771
5059
  comment = potential_match;
@@ -4773,117 +5061,115 @@ class ExportedNames {
4773
5061
  break;
4774
5062
  }
4775
5063
  }
4776
- if (!comment) {
4777
- for (const c of [
4778
- ...(ts.getLeadingCommentRanges(text, node.parent.pos) || []).reverse()
4779
- ]) {
4780
- const potential_match = text.substring(c.pos, c.end);
4781
- if (/@type\b/.test(potential_match)) {
4782
- comment = potential_match;
4783
- start = c.pos + this.astOffset;
4784
- break;
4785
- }
4786
- }
4787
- }
4788
- if (comment && /\/\*\*[^@]*?@type\s*{\s*{.*}\s*}\s*\*\//.test(comment)) {
4789
- // Create a virtual type alias for the unnamed generic and reuse it for the props return type
4790
- // so that rename, find references etc works seamlessly across components
4791
- this.$props.comment = '/** @type {$$ComponentProps} */';
4792
- const type_start = this.str.original.indexOf('@type', start);
4793
- this.str.overwrite(type_start, type_start + 5, '@typedef');
4794
- const end = this.str.original.indexOf('*/', start);
4795
- this.str.overwrite(end, end + 2, ' $$ComponentProps */' + this.$props.comment);
4796
- }
4797
- else {
4798
- // Complex comment or simple `@type {AType}` comment which we just use as-is.
4799
- // For the former this means things like rename won't work properly across components.
4800
- this.$props.comment = comment || '';
4801
- }
4802
5064
  }
4803
- if (this.$props.comment) {
4804
- return;
5065
+ if (comment && /\/\*\*[^@]*?@type\s*{\s*{.*}\s*}\s*\*\//.test(comment)) {
5066
+ // Create a virtual type alias for the unnamed generic and reuse it for the props return type
5067
+ // so that rename, find references etc works seamlessly across components
5068
+ this.$props.comment = '/** @type {$$ComponentProps} */';
5069
+ const type_start = this.str.original.indexOf('@type', start);
5070
+ this.str.overwrite(type_start, type_start + 5, '@typedef');
5071
+ const end = this.str.original.indexOf('*/', start);
5072
+ this.str.overwrite(end, end + 2, ' $$ComponentProps */' + this.$props.comment);
4805
5073
  }
4806
- // Do a best-effort to extract the props from the object literal
4807
- let propsStr = '';
4808
- let withUnknown = false;
4809
- let props = [];
4810
- const isKitRouteFile = internalHelpers.isKitRouteFile(this.basename);
4811
- const isKitLayoutFile = isKitRouteFile && this.basename.includes('layout');
4812
- if (ts.isObjectBindingPattern(node.name)) {
4813
- for (const element of node.name.elements) {
4814
- if (!ts.isIdentifier(element.name) ||
4815
- (element.propertyName && !ts.isIdentifier(element.propertyName)) ||
4816
- !!element.dotDotDotToken) {
4817
- withUnknown = true;
4818
- }
4819
- else {
4820
- const name = element.propertyName
4821
- ? element.propertyName.text
4822
- : element.name.text;
4823
- if (isKitRouteFile) {
4824
- if (name === 'data') {
4825
- props.push(`data: import('./$types.js').${isKitLayoutFile ? 'LayoutData' : 'PageData'}`);
4826
- }
4827
- if (name === 'form' && !isKitLayoutFile) {
4828
- props.push(`form: import('./$types.js').ActionData`);
4829
- }
5074
+ else {
5075
+ // Complex comment or simple `@type {AType}` comment which we just use as-is.
5076
+ // For the former this means things like rename won't work properly across components.
5077
+ this.$props.comment = comment || '';
5078
+ }
5079
+ }
5080
+ if (this.$props.comment) {
5081
+ // User uses JsDoc
5082
+ return;
5083
+ }
5084
+ // Do a best-effort to extract the props from the object literal
5085
+ let propsStr = '';
5086
+ let withUnknown = false;
5087
+ let props = [];
5088
+ const isKitRouteFile = internalHelpers.isKitRouteFile(this.basename);
5089
+ const isKitLayoutFile = isKitRouteFile && this.basename.includes('layout');
5090
+ if (ts.isObjectBindingPattern(node.name)) {
5091
+ for (const element of node.name.elements) {
5092
+ if (!ts.isIdentifier(element.name) ||
5093
+ (element.propertyName && !ts.isIdentifier(element.propertyName)) ||
5094
+ !!element.dotDotDotToken) {
5095
+ withUnknown = true;
5096
+ }
5097
+ else {
5098
+ const name = element.propertyName
5099
+ ? element.propertyName.text
5100
+ : element.name.text;
5101
+ if (isKitRouteFile) {
5102
+ if (name === 'data') {
5103
+ props.push(`data: import('./$types.js').${isKitLayoutFile ? 'LayoutData' : 'PageData'}`);
5104
+ }
5105
+ if (name === 'form' && !isKitLayoutFile) {
5106
+ props.push(`form: import('./$types.js').ActionData`);
4830
5107
  }
4831
- else if (element.initializer) {
4832
- const type = ts.isAsExpression(element.initializer)
4833
- ? element.initializer.type.getText()
4834
- : ts.isStringLiteral(element.initializer)
5108
+ }
5109
+ else if (element.initializer) {
5110
+ const initializer = ts.isCallExpression(element.initializer) &&
5111
+ ts.isIdentifier(element.initializer.expression) &&
5112
+ element.initializer.expression.text === '$bindable'
5113
+ ? element.initializer.arguments[0]
5114
+ : element.initializer;
5115
+ const type = !initializer
5116
+ ? 'any'
5117
+ : ts.isAsExpression(initializer)
5118
+ ? initializer.type.getText()
5119
+ : ts.isStringLiteral(initializer)
4835
5120
  ? 'string'
4836
- : ts.isNumericLiteral(element.initializer)
5121
+ : ts.isNumericLiteral(initializer)
4837
5122
  ? 'number'
4838
- : element.initializer.kind === ts.SyntaxKind.TrueKeyword ||
4839
- element.initializer.kind === ts.SyntaxKind.FalseKeyword
5123
+ : initializer.kind === ts.SyntaxKind.TrueKeyword ||
5124
+ initializer.kind === ts.SyntaxKind.FalseKeyword
4840
5125
  ? 'boolean'
4841
- : ts.isIdentifier(element.initializer)
4842
- ? `typeof ${element.initializer.text}`
4843
- : ts.isObjectLiteralExpression(element.initializer)
4844
- ? 'Record<string, unknown>'
4845
- : ts.isArrayLiteralExpression(element.initializer)
4846
- ? 'unknown[]'
4847
- : 'unknown';
4848
- props.push(`${name}?: ${type}`);
4849
- }
4850
- else {
4851
- props.push(`${name}: unknown`);
4852
- }
5126
+ : ts.isIdentifier(initializer) &&
5127
+ initializer.text !== 'undefined'
5128
+ ? `typeof ${initializer.text}`
5129
+ : ts.isArrowFunction(initializer)
5130
+ ? 'Function'
5131
+ : ts.isObjectLiteralExpression(initializer)
5132
+ ? 'Record<string, any>'
5133
+ : ts.isArrayLiteralExpression(initializer)
5134
+ ? 'any[]'
5135
+ : 'any';
5136
+ props.push(`${name}?: ${type}`);
5137
+ }
5138
+ else {
5139
+ props.push(`${name}: any`);
4853
5140
  }
4854
- }
4855
- if (isKitLayoutFile) {
4856
- props.push(`children: import('svelte').Snippet`);
4857
- }
4858
- if (props.length > 0) {
4859
- propsStr =
4860
- `{ ${props.join(', ')} }` +
4861
- (withUnknown ? ' & Record<string, unknown>' : '');
4862
- }
4863
- else if (withUnknown) {
4864
- propsStr = 'Record<string, unknown>';
4865
- }
4866
- else {
4867
- propsStr = 'Record<string, never>';
4868
5141
  }
4869
5142
  }
4870
- else {
4871
- propsStr = 'Record<string, unknown>';
5143
+ if (isKitLayoutFile) {
5144
+ props.push(`children: import('svelte').Snippet`);
4872
5145
  }
4873
- // Create a virtual type alias for the unnamed generic and reuse it for the props return type
4874
- // so that rename, find references etc works seamlessly across components
4875
- if (this.isTsFile) {
4876
- this.$props.type = '$$ComponentProps';
4877
- if (props.length > 0 || withUnknown) {
4878
- preprendStr(this.str, node.parent.pos + this.astOffset, surroundWithIgnoreComments(`;type $$ComponentProps = ${propsStr};`));
4879
- preprendStr(this.str, node.name.end + this.astOffset, `: ${this.$props.type}`);
4880
- }
5146
+ if (props.length > 0) {
5147
+ propsStr =
5148
+ `{ ${props.join(', ')} }` + (withUnknown ? ' & Record<string, any>' : '');
5149
+ }
5150
+ else if (withUnknown) {
5151
+ propsStr = 'Record<string, any>';
4881
5152
  }
4882
5153
  else {
4883
- this.$props.comment = '/** @type {$$ComponentProps} */';
4884
- if (props.length > 0 || withUnknown) {
4885
- preprendStr(this.str, node.pos + this.astOffset, `/** @typedef {${propsStr}} $$ComponentProps */${this.$props.comment}`);
4886
- }
5154
+ propsStr = 'Record<string, never>';
5155
+ }
5156
+ }
5157
+ else {
5158
+ propsStr = 'Record<string, any>';
5159
+ }
5160
+ // Create a virtual type alias for the unnamed generic and reuse it for the props return type
5161
+ // so that rename, find references etc works seamlessly across components
5162
+ if (this.isTsFile) {
5163
+ this.$props.type = '$$ComponentProps';
5164
+ if (props.length > 0 || withUnknown) {
5165
+ preprendStr(this.str, node.parent.pos + this.astOffset, surroundWithIgnoreComments(`;type $$ComponentProps = ${propsStr};`));
5166
+ preprendStr(this.str, node.name.end + this.astOffset, `: ${this.$props.type}`);
5167
+ }
5168
+ }
5169
+ else {
5170
+ this.$props.comment = '/** @type {$$ComponentProps} */';
5171
+ if (props.length > 0 || withUnknown) {
5172
+ preprendStr(this.str, node.pos + this.astOffset, `/** @typedef {${propsStr}} $$ComponentProps */${this.$props.comment}`);
4887
5173
  }
4888
5174
  }
4889
5175
  }
@@ -6209,7 +6495,7 @@ class InterfacesAndTypes {
6209
6495
  }
6210
6496
  }
6211
6497
 
6212
- function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript, isTSFile, basename, isSvelte5Plus, isRunes) {
6498
+ function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, moduleAst, isTSFile, basename, isSvelte5Plus, isRunes) {
6213
6499
  const htmlx = str.original;
6214
6500
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6215
6501
  const tsAst = ts.createSourceFile('component.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
@@ -6217,6 +6503,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6217
6503
  const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus, isRunes);
6218
6504
  const generics = new Generics(str, astOffset, script);
6219
6505
  const interfacesAndTypes = new InterfacesAndTypes();
6506
+ if (moduleAst) {
6507
+ moduleAst.tsAst.forEachChild((n) => exportedNames.hoistableInterfaces.analyzeModuleScriptNode(n));
6508
+ }
6220
6509
  const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
6221
6510
  let uses$$props = false;
6222
6511
  let uses$$restProps = false;
@@ -6296,6 +6585,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6296
6585
  const walk = (node, parent) => {
6297
6586
  var _a, _b, _c;
6298
6587
  const onLeaveCallbacks = [];
6588
+ if (parent === tsAst) {
6589
+ exportedNames.hoistableInterfaces.analyzeInstanceScriptNode(node);
6590
+ }
6299
6591
  generics.addIfIsGeneric(node);
6300
6592
  if (is$$EventsDeclaration(node)) {
6301
6593
  events.setComponentEventsInterface(node, astOffset);
@@ -6400,7 +6692,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6400
6692
  // declare implicit reactive variables we found in the script
6401
6693
  implicitTopLevelNames.modifyCode(rootScope.declared);
6402
6694
  implicitStoreValues.modifyCode(astOffset, str);
6403
- handleFirstInstanceImport(tsAst, astOffset, hasModuleScript, str);
6695
+ handleFirstInstanceImport(tsAst, astOffset, !!moduleAst, str);
6404
6696
  // move interfaces and types out of the render function if they are referenced
6405
6697
  // by a $$Generic, otherwise it will be used before being defined after the transformation
6406
6698
  const nodesToMove = interfacesAndTypes.getNodesWithNames(generics.getTypeReferences());
@@ -6414,6 +6706,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6414
6706
  // break dts generation (file will not be generated).
6415
6707
  transformInterfacesToTypes(tsAst, str, astOffset, nodesToMove);
6416
6708
  }
6709
+ exportedNames.hoistableInterfaces.moveHoistableInterfaces(str, astOffset, script.start);
6417
6710
  return {
6418
6711
  exportedNames,
6419
6712
  events,
@@ -6448,11 +6741,15 @@ function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
6448
6741
  });
6449
6742
  }
6450
6743
 
6451
- function processModuleScriptTag(str, script, implicitStoreValues) {
6744
+ function createModuleAst(str, script) {
6452
6745
  const htmlx = str.original;
6453
6746
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6454
6747
  const tsAst = ts.createSourceFile('component.module.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
6455
6748
  const astOffset = script.content.start;
6749
+ return { htmlx, tsAst, astOffset };
6750
+ }
6751
+ function processModuleScriptTag(str, script, implicitStoreValues, moduleAst) {
6752
+ const { htmlx, tsAst, astOffset } = moduleAst;
6456
6753
  const generics = new Generics(str, astOffset, script);
6457
6754
  if (generics.genericsAttr) {
6458
6755
  const start = htmlx.indexOf('generics', script.start);
@@ -7085,7 +7382,9 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7085
7382
  * In this case we instead have to move it to moduleScriptTag.end. We track the location for the script move in the MoveInstanceScriptTarget var
7086
7383
  */
7087
7384
  let instanceScriptTarget = 0;
7385
+ let moduleAst;
7088
7386
  if (moduleScriptTag) {
7387
+ moduleAst = createModuleAst(str, moduleScriptTag);
7089
7388
  if (moduleScriptTag.start != 0) {
7090
7389
  //move our module tag to the top
7091
7390
  str.move(moduleScriptTag.start, moduleScriptTag.end, 0);
@@ -7108,8 +7407,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7108
7407
  if (scriptTag.start != instanceScriptTarget) {
7109
7408
  str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
7110
7409
  }
7111
- const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
7112
- /**hasModuleScripts */ !!moduleScriptTag, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus, isRunes);
7410
+ const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode, moduleAst, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus, isRunes);
7113
7411
  uses$$props = uses$$props || res.uses$$props;
7114
7412
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7115
7413
  uses$$slots = uses$$slots || res.uses$$slots;
@@ -7138,7 +7436,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7138
7436
  });
7139
7437
  // we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items
7140
7438
  if (moduleScriptTag) {
7141
- processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`));
7439
+ processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`), moduleAst);
7142
7440
  }
7143
7441
  addComponentExport({
7144
7442
  str,