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.
- package/index.js +419 -121
- package/index.mjs +419 -121
- 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
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
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 (!
|
|
4179
|
-
svelteTsxFiles.push(
|
|
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 (
|
|
4218
|
-
svelteTsxFiles.push(tsSystem.resolvePath(path.resolve(typesPath,
|
|
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 (
|
|
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
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
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 (
|
|
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
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
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
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
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(
|
|
5121
|
+
: ts.isNumericLiteral(initializer)
|
|
4837
5122
|
? 'number'
|
|
4838
|
-
:
|
|
4839
|
-
|
|
5123
|
+
: initializer.kind === ts.SyntaxKind.TrueKeyword ||
|
|
5124
|
+
initializer.kind === ts.SyntaxKind.FalseKeyword
|
|
4840
5125
|
? 'boolean'
|
|
4841
|
-
: ts.isIdentifier(
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
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
|
-
|
|
4871
|
-
|
|
5143
|
+
if (isKitLayoutFile) {
|
|
5144
|
+
props.push(`children: import('svelte').Snippet`);
|
|
4872
5145
|
}
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
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
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
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,
|
|
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,
|
|
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
|
|
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,
|