svelte2tsx 0.7.24 → 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 +421 -133
- package/index.mjs +421 -133
- 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,127 +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
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
: element.initializer;
|
|
4837
|
-
const type = !initializer
|
|
4838
|
-
? 'unknown'
|
|
4839
|
-
: ts.isAsExpression(initializer)
|
|
4840
|
-
? initializer.type.getText()
|
|
4841
|
-
: ts.isStringLiteral(initializer)
|
|
4842
|
-
? 'string'
|
|
4843
|
-
: ts.isNumericLiteral(initializer)
|
|
4844
|
-
? 'number'
|
|
4845
|
-
: initializer.kind === ts.SyntaxKind.TrueKeyword ||
|
|
4846
|
-
initializer.kind === ts.SyntaxKind.FalseKeyword
|
|
4847
|
-
? 'boolean'
|
|
4848
|
-
: ts.isIdentifier(initializer) &&
|
|
4849
|
-
initializer.text !== 'undefined'
|
|
4850
|
-
? `typeof ${initializer.text}`
|
|
4851
|
-
: ts.isArrowFunction(initializer)
|
|
4852
|
-
? 'Function'
|
|
4853
|
-
: ts.isObjectLiteralExpression(initializer)
|
|
4854
|
-
? 'Record<string, unknown>'
|
|
4855
|
-
: ts.isArrayLiteralExpression(initializer)
|
|
4856
|
-
? 'unknown[]'
|
|
4857
|
-
: 'unknown';
|
|
4858
|
-
props.push(`${name}?: ${type}`);
|
|
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'}`);
|
|
4859
5104
|
}
|
|
4860
|
-
|
|
4861
|
-
props.push(
|
|
5105
|
+
if (name === 'form' && !isKitLayoutFile) {
|
|
5106
|
+
props.push(`form: import('./$types.js').ActionData`);
|
|
4862
5107
|
}
|
|
4863
5108
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
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)
|
|
5120
|
+
? 'string'
|
|
5121
|
+
: ts.isNumericLiteral(initializer)
|
|
5122
|
+
? 'number'
|
|
5123
|
+
: initializer.kind === ts.SyntaxKind.TrueKeyword ||
|
|
5124
|
+
initializer.kind === ts.SyntaxKind.FalseKeyword
|
|
5125
|
+
? 'boolean'
|
|
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`);
|
|
5140
|
+
}
|
|
4878
5141
|
}
|
|
4879
5142
|
}
|
|
4880
|
-
|
|
4881
|
-
|
|
5143
|
+
if (isKitLayoutFile) {
|
|
5144
|
+
props.push(`children: import('svelte').Snippet`);
|
|
4882
5145
|
}
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
preprendStr(this.str, node.name.end + this.astOffset, `: ${this.$props.type}`);
|
|
4890
|
-
}
|
|
5146
|
+
if (props.length > 0) {
|
|
5147
|
+
propsStr =
|
|
5148
|
+
`{ ${props.join(', ')} }` + (withUnknown ? ' & Record<string, any>' : '');
|
|
5149
|
+
}
|
|
5150
|
+
else if (withUnknown) {
|
|
5151
|
+
propsStr = 'Record<string, any>';
|
|
4891
5152
|
}
|
|
4892
5153
|
else {
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
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}`);
|
|
4897
5173
|
}
|
|
4898
5174
|
}
|
|
4899
5175
|
}
|
|
@@ -6219,7 +6495,7 @@ class InterfacesAndTypes {
|
|
|
6219
6495
|
}
|
|
6220
6496
|
}
|
|
6221
6497
|
|
|
6222
|
-
function processInstanceScriptContent(str, script, events, implicitStoreValues, mode,
|
|
6498
|
+
function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, moduleAst, isTSFile, basename, isSvelte5Plus, isRunes) {
|
|
6223
6499
|
const htmlx = str.original;
|
|
6224
6500
|
const scriptContent = htmlx.substring(script.content.start, script.content.end);
|
|
6225
6501
|
const tsAst = ts.createSourceFile('component.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
@@ -6227,6 +6503,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
|
|
|
6227
6503
|
const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus, isRunes);
|
|
6228
6504
|
const generics = new Generics(str, astOffset, script);
|
|
6229
6505
|
const interfacesAndTypes = new InterfacesAndTypes();
|
|
6506
|
+
if (moduleAst) {
|
|
6507
|
+
moduleAst.tsAst.forEachChild((n) => exportedNames.hoistableInterfaces.analyzeModuleScriptNode(n));
|
|
6508
|
+
}
|
|
6230
6509
|
const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
|
|
6231
6510
|
let uses$$props = false;
|
|
6232
6511
|
let uses$$restProps = false;
|
|
@@ -6306,6 +6585,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
|
|
|
6306
6585
|
const walk = (node, parent) => {
|
|
6307
6586
|
var _a, _b, _c;
|
|
6308
6587
|
const onLeaveCallbacks = [];
|
|
6588
|
+
if (parent === tsAst) {
|
|
6589
|
+
exportedNames.hoistableInterfaces.analyzeInstanceScriptNode(node);
|
|
6590
|
+
}
|
|
6309
6591
|
generics.addIfIsGeneric(node);
|
|
6310
6592
|
if (is$$EventsDeclaration(node)) {
|
|
6311
6593
|
events.setComponentEventsInterface(node, astOffset);
|
|
@@ -6410,7 +6692,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
|
|
|
6410
6692
|
// declare implicit reactive variables we found in the script
|
|
6411
6693
|
implicitTopLevelNames.modifyCode(rootScope.declared);
|
|
6412
6694
|
implicitStoreValues.modifyCode(astOffset, str);
|
|
6413
|
-
handleFirstInstanceImport(tsAst, astOffset,
|
|
6695
|
+
handleFirstInstanceImport(tsAst, astOffset, !!moduleAst, str);
|
|
6414
6696
|
// move interfaces and types out of the render function if they are referenced
|
|
6415
6697
|
// by a $$Generic, otherwise it will be used before being defined after the transformation
|
|
6416
6698
|
const nodesToMove = interfacesAndTypes.getNodesWithNames(generics.getTypeReferences());
|
|
@@ -6424,6 +6706,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
|
|
|
6424
6706
|
// break dts generation (file will not be generated).
|
|
6425
6707
|
transformInterfacesToTypes(tsAst, str, astOffset, nodesToMove);
|
|
6426
6708
|
}
|
|
6709
|
+
exportedNames.hoistableInterfaces.moveHoistableInterfaces(str, astOffset, script.start);
|
|
6427
6710
|
return {
|
|
6428
6711
|
exportedNames,
|
|
6429
6712
|
events,
|
|
@@ -6458,11 +6741,15 @@ function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
|
|
|
6458
6741
|
});
|
|
6459
6742
|
}
|
|
6460
6743
|
|
|
6461
|
-
function
|
|
6744
|
+
function createModuleAst(str, script) {
|
|
6462
6745
|
const htmlx = str.original;
|
|
6463
6746
|
const scriptContent = htmlx.substring(script.content.start, script.content.end);
|
|
6464
6747
|
const tsAst = ts.createSourceFile('component.module.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
6465
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;
|
|
6466
6753
|
const generics = new Generics(str, astOffset, script);
|
|
6467
6754
|
if (generics.genericsAttr) {
|
|
6468
6755
|
const start = htmlx.indexOf('generics', script.start);
|
|
@@ -7095,7 +7382,9 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
|
|
|
7095
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
|
|
7096
7383
|
*/
|
|
7097
7384
|
let instanceScriptTarget = 0;
|
|
7385
|
+
let moduleAst;
|
|
7098
7386
|
if (moduleScriptTag) {
|
|
7387
|
+
moduleAst = createModuleAst(str, moduleScriptTag);
|
|
7099
7388
|
if (moduleScriptTag.start != 0) {
|
|
7100
7389
|
//move our module tag to the top
|
|
7101
7390
|
str.move(moduleScriptTag.start, moduleScriptTag.end, 0);
|
|
@@ -7118,8 +7407,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
|
|
|
7118
7407
|
if (scriptTag.start != instanceScriptTarget) {
|
|
7119
7408
|
str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
|
|
7120
7409
|
}
|
|
7121
|
-
const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
|
|
7122
|
-
/**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);
|
|
7123
7411
|
uses$$props = uses$$props || res.uses$$props;
|
|
7124
7412
|
uses$$restProps = uses$$restProps || res.uses$$restProps;
|
|
7125
7413
|
uses$$slots = uses$$slots || res.uses$$slots;
|
|
@@ -7148,7 +7436,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
|
|
|
7148
7436
|
});
|
|
7149
7437
|
// we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items
|
|
7150
7438
|
if (moduleScriptTag) {
|
|
7151
|
-
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);
|
|
7152
7440
|
}
|
|
7153
7441
|
addComponentExport({
|
|
7154
7442
|
str,
|