svelte2tsx 0.7.21 → 0.7.23

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 (4) hide show
  1. package/index.d.ts +7 -0
  2. package/index.js +109 -27
  3. package/index.mjs +110 -28
  4. package/package.json +2 -2
package/index.d.ts CHANGED
@@ -134,6 +134,13 @@ export function emitDts(config: EmitDtsConfig): Promise<void>;
134
134
  * static top level `ts` namespace, it must be passed as a parameter.
135
135
  */
136
136
  export const internalHelpers: {
137
+ get_global_types: (
138
+ tsSystem: ts.System,
139
+ isSvelte3: boolean,
140
+ sveltePath: string,
141
+ typesPath: string,
142
+ hiddenFolderPath?: string,
143
+ ) => string[],
137
144
  isKitFile: (
138
145
  fileName: string,
139
146
  options: InternalHelpers.KitFilesSettings
package/index.js CHANGED
@@ -4161,6 +4161,65 @@ function eventMapEntryToString([eventName, expression]) {
4161
4161
  return `'${eventName}':${Array.isArray(expression) ? `__sveltets_2_unionType(${expression.join(',')})` : expression}`;
4162
4162
  }
4163
4163
 
4164
+ /**
4165
+ * Returns the path to the global svelte2tsx files that should be included in the project.
4166
+ * Creates a hidden folder in the user's node_modules if `hiddenFolderPath` is provided.
4167
+ */
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';
4172
+ let svelteTsxFiles;
4173
+ if (isSvelte3) {
4174
+ svelteTsxFiles = ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'];
4175
+ }
4176
+ else {
4177
+ svelteTsxFiles = ['./svelte-shims-v4.d.ts', './svelte-native-jsx.d.ts'];
4178
+ if (!svelteHtmlPathExists) {
4179
+ svelteTsxFiles.push(svelteHtmlPath);
4180
+ }
4181
+ }
4182
+ svelteTsxFiles = svelteTsxFiles.map((f) => tsSystem.resolvePath(path.resolve(typesPath, f)));
4183
+ if (hiddenFolderPath) {
4184
+ try {
4185
+ // IDE context - the `import('svelte')` statements inside the d.ts files will load the Svelte version of
4186
+ // the extension, which can cause all sorts of problems. Therefore put the files into a hidden folder in
4187
+ // the user's node_modules, preferably next to the Svelte package.
4188
+ let path$1 = path.dirname(sveltePath);
4189
+ if (!tsSystem.directoryExists(path.resolve(path$1, 'node_modules'))) {
4190
+ path$1 = hiddenFolderPath;
4191
+ while (path$1 && !tsSystem.directoryExists(path.resolve(path$1, 'node_modules'))) {
4192
+ const parent = path.dirname(path$1);
4193
+ if (path$1 === parent) {
4194
+ path$1 = '';
4195
+ break;
4196
+ }
4197
+ path$1 = parent;
4198
+ }
4199
+ }
4200
+ if (path$1) {
4201
+ const hiddenPath = path.resolve(path$1, 'node_modules/.svelte2tsx-language-server-files');
4202
+ const newFiles = [];
4203
+ for (const f of svelteTsxFiles) {
4204
+ const hiddenFile = path.resolve(hiddenPath, path.basename(f));
4205
+ const existing = tsSystem.readFile(hiddenFile);
4206
+ const toWrite = tsSystem.readFile(f) || '';
4207
+ if (existing !== toWrite) {
4208
+ tsSystem.writeFile(hiddenFile, toWrite);
4209
+ }
4210
+ newFiles.push(hiddenFile);
4211
+ }
4212
+ svelteTsxFiles = newFiles;
4213
+ }
4214
+ }
4215
+ catch (e) { }
4216
+ }
4217
+ if (svelteHtmlPathExists) {
4218
+ svelteTsxFiles.push(tsSystem.resolvePath(path.resolve(typesPath, svelteHtmlFile)));
4219
+ }
4220
+ return svelteTsxFiles;
4221
+ }
4222
+
4164
4223
  /**
4165
4224
  * Finds the top level const/let/function exports of a source file.
4166
4225
  */
@@ -4209,7 +4268,8 @@ function findExports(ts, source, isTsFile) {
4209
4268
  hasTypeDefinition: hasTypeDefinition || hasTypedParameter(ts, node, isTsFile)
4210
4269
  });
4211
4270
  }
4212
- else {
4271
+ else if (ts.isIdentifier(declaration.name)) {
4272
+ // TODO support `export const { x, y } = ...` ?
4213
4273
  exports.set(declaration.name.getText(), {
4214
4274
  type: 'var',
4215
4275
  node: declaration,
@@ -4306,6 +4366,12 @@ function upsertKitRouteFile(ts, basename, getSource, surround) {
4306
4366
  const inserted = surround(`: import('./$types.js').${basename.includes('layout') ? 'Layout' : 'Page'}${basename.includes('server') ? 'Server' : ''}LoadEvent`);
4307
4367
  insert(pos, inserted);
4308
4368
  }
4369
+ else if ((load === null || load === void 0 ? void 0 : load.type) === 'var' && !load.hasTypeDefinition) {
4370
+ // "const load = ..." will be transformed into
4371
+ // "const load = (...) satisfies PageLoad"
4372
+ insert(load.node.initializer.getStart(), surround('('));
4373
+ insert(load.node.initializer.getEnd(), surround(`) satisfies import('./$types.js').${basename.includes('layout') ? 'Layout' : 'Page'}${basename.includes('server') ? 'Server' : ''}Load`));
4374
+ }
4309
4375
  // add type to entries function if not explicitly typed
4310
4376
  const entries = exports.get('entries');
4311
4377
  if ((entries === null || entries === void 0 ? void 0 : entries.type) === 'function' &&
@@ -4507,7 +4573,8 @@ const internalHelpers = {
4507
4573
  upsertKitFile,
4508
4574
  toVirtualPos,
4509
4575
  toOriginalPos,
4510
- findExports
4576
+ findExports,
4577
+ get_global_types
4511
4578
  };
4512
4579
 
4513
4580
  /**
@@ -4549,12 +4616,13 @@ function is$$PropsDeclaration(node) {
4549
4616
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Props';
4550
4617
  }
4551
4618
  class ExportedNames {
4552
- constructor(str, astOffset, basename, isTsFile, isSvelte5Plus) {
4619
+ constructor(str, astOffset, basename, isTsFile, isSvelte5Plus, isRunes) {
4553
4620
  this.str = str;
4554
4621
  this.astOffset = astOffset;
4555
4622
  this.basename = basename;
4556
4623
  this.isTsFile = isTsFile;
4557
4624
  this.isSvelte5Plus = isSvelte5Plus;
4625
+ this.isRunes = isRunes;
4558
4626
  this.usesAccessors = false;
4559
4627
  /**
4560
4628
  * Uses the `$$Props` type
@@ -4636,10 +4704,10 @@ class ExportedNames {
4636
4704
  if (ts.isNamedExports(exportClause)) {
4637
4705
  for (const ne of exportClause.elements) {
4638
4706
  if (ne.propertyName) {
4639
- this.addExport(ne.propertyName, false, ne.name);
4707
+ this.addExport(ne.propertyName, false, ne.name, undefined, undefined, true);
4640
4708
  }
4641
4709
  else {
4642
- this.addExport(ne.name, false);
4710
+ this.addExport(ne.name, false, undefined, undefined, undefined, true);
4643
4711
  }
4644
4712
  }
4645
4713
  //we can remove entire statement
@@ -4772,7 +4840,11 @@ class ExportedNames {
4772
4840
  ? 'boolean'
4773
4841
  : ts.isIdentifier(element.initializer)
4774
4842
  ? `typeof ${element.initializer.text}`
4775
- : 'unknown';
4843
+ : ts.isObjectLiteralExpression(element.initializer)
4844
+ ? 'Record<string, unknown>'
4845
+ : ts.isArrayLiteralExpression(element.initializer)
4846
+ ? 'unknown[]'
4847
+ : 'unknown';
4776
4848
  props.push(`${name}?: ${type}`);
4777
4849
  }
4778
4850
  else {
@@ -4976,7 +5048,7 @@ class ExportedNames {
4976
5048
  /**
4977
5049
  * Adds export to map
4978
5050
  */
4979
- addExport(name, isLet, target = null, type = null, required = false) {
5051
+ addExport(name, isLet, target = null, type = null, required = false, isNamedExport = false) {
4980
5052
  const existingDeclaration = this.possibleExports.get(name.text);
4981
5053
  if (target) {
4982
5054
  this.exports.set(name.text, {
@@ -4984,7 +5056,8 @@ class ExportedNames {
4984
5056
  type: (type === null || type === void 0 ? void 0 : type.getText()) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.type),
4985
5057
  identifierText: target.text,
4986
5058
  required: required || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.required),
4987
- doc: this.getDoc(target) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc)
5059
+ doc: this.getDoc(target) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc),
5060
+ isNamedExport
4988
5061
  });
4989
5062
  }
4990
5063
  else {
@@ -4992,7 +5065,8 @@ class ExportedNames {
4992
5065
  isLet: isLet || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.isLet),
4993
5066
  type: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.type,
4994
5067
  required: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.required,
4995
- doc: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc
5068
+ doc: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc,
5069
+ isNamedExport
4996
5070
  });
4997
5071
  }
4998
5072
  if (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.isLet) {
@@ -5103,7 +5177,7 @@ class ExportedNames {
5103
5177
  */
5104
5178
  createExportsStr() {
5105
5179
  const names = Array.from(this.exports.entries());
5106
- const others = names.filter(([, { isLet }]) => !isLet);
5180
+ const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.usesRunes() && isNamedExport));
5107
5181
  const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
5108
5182
  if (this.isSvelte5Plus) {
5109
5183
  let str = '';
@@ -5175,7 +5249,7 @@ class ExportedNames {
5175
5249
  this.isSvelte5Plus && globals.some((global) => runes.includes(global));
5176
5250
  }
5177
5251
  usesRunes() {
5178
- return this.hasRunesGlobals || this.hasPropsRune();
5252
+ return this.hasRunesGlobals || this.hasPropsRune() || this.isRunes;
5179
5253
  }
5180
5254
  }
5181
5255
 
@@ -6135,12 +6209,12 @@ class InterfacesAndTypes {
6135
6209
  }
6136
6210
  }
6137
6211
 
6138
- function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript, isTSFile, basename, isSvelte5Plus) {
6212
+ function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript, isTSFile, basename, isSvelte5Plus, isRunes) {
6139
6213
  const htmlx = str.original;
6140
6214
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6141
6215
  const tsAst = ts.createSourceFile('component.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
6142
6216
  const astOffset = script.content.start;
6143
- const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus);
6217
+ const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus, isRunes);
6144
6218
  const generics = new Generics(str, astOffset, script);
6145
6219
  const interfacesAndTypes = new InterfacesAndTypes();
6146
6220
  const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
@@ -6536,12 +6610,14 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
6536
6610
  const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), 'render()'));
6537
6611
  const doc = componentDocumentation.getFormatted();
6538
6612
  const className = fileName && classNameFromFilename(fileName, mode !== 'dts');
6613
+ const componentName = className || '$$Component';
6539
6614
  let statement;
6540
6615
  if (mode === 'dts') {
6541
6616
  if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
6542
6617
  statement =
6543
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` +
6544
- `export default ${className || '$$Component'};`;
6618
+ `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` +
6619
+ `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
6620
+ `export default ${componentName};`;
6545
6621
  }
6546
6622
  else if (isSvelte5) {
6547
6623
  // Inline definitions from Svelte shims; else dts files will reference the globals which will be unresolved
@@ -6565,9 +6641,9 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
6565
6641
  declare function $$__sveltets_2_isomorphic_component<
6566
6642
  Props extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>, Exports extends Record<string, any>, Bindings extends string
6567
6643
  >(klass: {props: Props, events: Events, slots: Slots, exports?: Exports, bindings?: Bindings }): $$__sveltets_2_IsomorphicComponent<Props, Events, Slots, Exports, Bindings>;\n`) +
6568
- `${doc}const ${className || '$$Component'} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6569
- surroundWithIgnoreComments(`type ${className || '$$Component'} = InstanceType<typeof ${className || '$$Component'}>;\n`) +
6570
- `export default ${className || '$$Component'};`;
6644
+ `${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6645
+ surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
6646
+ `export default ${componentName};`;
6571
6647
  }
6572
6648
  else if (isTsFile) {
6573
6649
  const svelteComponentClass = noSvelteComponentTyped
@@ -6602,14 +6678,15 @@ declare function $$__sveltets_2_isomorphic_component<
6602
6678
  if (isSvelte5) {
6603
6679
  if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
6604
6680
  statement =
6605
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` +
6606
- `export default ${className || '$$Component'};`;
6681
+ `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` +
6682
+ `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
6683
+ `export default ${componentName};`;
6607
6684
  }
6608
6685
  else {
6609
6686
  statement =
6610
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6611
- surroundWithIgnoreComments(`type ${className || '$$Component'} = InstanceType<typeof ${className || '$$Component'}>;\n`) +
6612
- `export default ${className || '$$Component'};`;
6687
+ `\n${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6688
+ surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
6689
+ `export default ${componentName};`;
6613
6690
  }
6614
6691
  }
6615
6692
  else {
@@ -6781,6 +6858,7 @@ function processSvelteTemplate(str, parse, options) {
6781
6858
  let uses$$restProps = false;
6782
6859
  let uses$$slots = false;
6783
6860
  let usesAccessors = !!options.accessors;
6861
+ let isRunes = false;
6784
6862
  const componentDocumentation = new ComponentDocumentation();
6785
6863
  //track if we are in a declaration scope
6786
6864
  const isDeclaration = { value: false };
@@ -6804,6 +6882,9 @@ function processSvelteTemplate(str, parse, options) {
6804
6882
  usesAccessors = true;
6805
6883
  }
6806
6884
  break;
6885
+ case 'runes':
6886
+ isRunes = true;
6887
+ break;
6807
6888
  }
6808
6889
  }
6809
6890
  };
@@ -6983,7 +7064,8 @@ function processSvelteTemplate(str, parse, options) {
6983
7064
  uses$$slots,
6984
7065
  componentDocumentation,
6985
7066
  resolvedStores,
6986
- usesAccessors
7067
+ usesAccessors,
7068
+ isRunes
6987
7069
  };
6988
7070
  }
6989
7071
  function svelte2tsx(svelte, options = { parse: compiler.parse }) {
@@ -6993,7 +7075,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
6993
7075
  const basename = path.basename(options.filename || '');
6994
7076
  const svelte5Plus = Number(options.version[0]) > 4;
6995
7077
  // process the htmlx as a svelte template
6996
- let { htmlAst, moduleScriptTag, scriptTag, rootSnippets, slots, uses$$props, uses$$slots, uses$$restProps, events, componentDocumentation, resolvedStores, usesAccessors } = processSvelteTemplate(str, options.parse || compiler.parse, {
7078
+ let { htmlAst, moduleScriptTag, scriptTag, rootSnippets, slots, uses$$props, uses$$slots, uses$$restProps, events, componentDocumentation, resolvedStores, usesAccessors, isRunes } = processSvelteTemplate(str, options.parse || compiler.parse, {
6997
7079
  ...options,
6998
7080
  svelte5Plus
6999
7081
  });
@@ -7018,7 +7100,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7018
7100
  : instanceScriptTarget;
7019
7101
  const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart);
7020
7102
  //move the instance script and process the content
7021
- let exportedNames = new ExportedNames(str, 0, basename, options === null || options === void 0 ? void 0 : options.isTsFile, svelte5Plus);
7103
+ let exportedNames = new ExportedNames(str, 0, basename, options === null || options === void 0 ? void 0 : options.isTsFile, svelte5Plus, isRunes);
7022
7104
  let generics = new Generics(str, 0, { attributes: [] });
7023
7105
  let uses$$SlotsInterface = false;
7024
7106
  if (scriptTag) {
@@ -7027,7 +7109,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7027
7109
  str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
7028
7110
  }
7029
7111
  const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
7030
- /**hasModuleScripts */ !!moduleScriptTag, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus);
7112
+ /**hasModuleScripts */ !!moduleScriptTag, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus, isRunes);
7031
7113
  uses$$props = uses$$props || res.uses$$props;
7032
7114
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7033
7115
  uses$$slots = uses$$slots || res.uses$$slots;
package/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import dedent from 'dedent-js';
2
2
  import ts from 'typescript';
3
3
  import * as path from 'path';
4
- import path__default from 'path';
4
+ import path__default, { join, resolve, dirname, basename } from 'path';
5
5
  import { pascalCase } from 'pascal-case';
6
6
  import { VERSION, parse } from 'svelte/compiler';
7
7
 
@@ -4141,6 +4141,65 @@ function eventMapEntryToString([eventName, expression]) {
4141
4141
  return `'${eventName}':${Array.isArray(expression) ? `__sveltets_2_unionType(${expression.join(',')})` : expression}`;
4142
4142
  }
4143
4143
 
4144
+ /**
4145
+ * Returns the path to the global svelte2tsx files that should be included in the project.
4146
+ * Creates a hidden folder in the user's node_modules if `hiddenFolderPath` is provided.
4147
+ */
4148
+ function get_global_types(tsSystem, isSvelte3, sveltePath, typesPath, hiddenFolderPath) {
4149
+ const svelteHtmlPath = isSvelte3 ? undefined : join(sveltePath, 'svelte-html.d.ts');
4150
+ const svelteHtmlPathExists = svelteHtmlPath && tsSystem.fileExists(svelteHtmlPath);
4151
+ const svelteHtmlFile = svelteHtmlPathExists ? svelteHtmlPath : './svelte-jsx-v4.d.ts';
4152
+ let svelteTsxFiles;
4153
+ if (isSvelte3) {
4154
+ svelteTsxFiles = ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts'];
4155
+ }
4156
+ else {
4157
+ svelteTsxFiles = ['./svelte-shims-v4.d.ts', './svelte-native-jsx.d.ts'];
4158
+ if (!svelteHtmlPathExists) {
4159
+ svelteTsxFiles.push(svelteHtmlPath);
4160
+ }
4161
+ }
4162
+ svelteTsxFiles = svelteTsxFiles.map((f) => tsSystem.resolvePath(resolve(typesPath, f)));
4163
+ if (hiddenFolderPath) {
4164
+ try {
4165
+ // IDE context - the `import('svelte')` statements inside the d.ts files will load the Svelte version of
4166
+ // the extension, which can cause all sorts of problems. Therefore put the files into a hidden folder in
4167
+ // the user's node_modules, preferably next to the Svelte package.
4168
+ let path = dirname(sveltePath);
4169
+ if (!tsSystem.directoryExists(resolve(path, 'node_modules'))) {
4170
+ path = hiddenFolderPath;
4171
+ while (path && !tsSystem.directoryExists(resolve(path, 'node_modules'))) {
4172
+ const parent = dirname(path);
4173
+ if (path === parent) {
4174
+ path = '';
4175
+ break;
4176
+ }
4177
+ path = parent;
4178
+ }
4179
+ }
4180
+ if (path) {
4181
+ const hiddenPath = resolve(path, 'node_modules/.svelte2tsx-language-server-files');
4182
+ const newFiles = [];
4183
+ for (const f of svelteTsxFiles) {
4184
+ const hiddenFile = resolve(hiddenPath, basename(f));
4185
+ const existing = tsSystem.readFile(hiddenFile);
4186
+ const toWrite = tsSystem.readFile(f) || '';
4187
+ if (existing !== toWrite) {
4188
+ tsSystem.writeFile(hiddenFile, toWrite);
4189
+ }
4190
+ newFiles.push(hiddenFile);
4191
+ }
4192
+ svelteTsxFiles = newFiles;
4193
+ }
4194
+ }
4195
+ catch (e) { }
4196
+ }
4197
+ if (svelteHtmlPathExists) {
4198
+ svelteTsxFiles.push(tsSystem.resolvePath(resolve(typesPath, svelteHtmlFile)));
4199
+ }
4200
+ return svelteTsxFiles;
4201
+ }
4202
+
4144
4203
  /**
4145
4204
  * Finds the top level const/let/function exports of a source file.
4146
4205
  */
@@ -4189,7 +4248,8 @@ function findExports(ts, source, isTsFile) {
4189
4248
  hasTypeDefinition: hasTypeDefinition || hasTypedParameter(ts, node, isTsFile)
4190
4249
  });
4191
4250
  }
4192
- else {
4251
+ else if (ts.isIdentifier(declaration.name)) {
4252
+ // TODO support `export const { x, y } = ...` ?
4193
4253
  exports.set(declaration.name.getText(), {
4194
4254
  type: 'var',
4195
4255
  node: declaration,
@@ -4286,6 +4346,12 @@ function upsertKitRouteFile(ts, basename, getSource, surround) {
4286
4346
  const inserted = surround(`: import('./$types.js').${basename.includes('layout') ? 'Layout' : 'Page'}${basename.includes('server') ? 'Server' : ''}LoadEvent`);
4287
4347
  insert(pos, inserted);
4288
4348
  }
4349
+ else if ((load === null || load === void 0 ? void 0 : load.type) === 'var' && !load.hasTypeDefinition) {
4350
+ // "const load = ..." will be transformed into
4351
+ // "const load = (...) satisfies PageLoad"
4352
+ insert(load.node.initializer.getStart(), surround('('));
4353
+ insert(load.node.initializer.getEnd(), surround(`) satisfies import('./$types.js').${basename.includes('layout') ? 'Layout' : 'Page'}${basename.includes('server') ? 'Server' : ''}Load`));
4354
+ }
4289
4355
  // add type to entries function if not explicitly typed
4290
4356
  const entries = exports.get('entries');
4291
4357
  if ((entries === null || entries === void 0 ? void 0 : entries.type) === 'function' &&
@@ -4487,7 +4553,8 @@ const internalHelpers = {
4487
4553
  upsertKitFile,
4488
4554
  toVirtualPos,
4489
4555
  toOriginalPos,
4490
- findExports
4556
+ findExports,
4557
+ get_global_types
4491
4558
  };
4492
4559
 
4493
4560
  /**
@@ -4529,12 +4596,13 @@ function is$$PropsDeclaration(node) {
4529
4596
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Props';
4530
4597
  }
4531
4598
  class ExportedNames {
4532
- constructor(str, astOffset, basename, isTsFile, isSvelte5Plus) {
4599
+ constructor(str, astOffset, basename, isTsFile, isSvelte5Plus, isRunes) {
4533
4600
  this.str = str;
4534
4601
  this.astOffset = astOffset;
4535
4602
  this.basename = basename;
4536
4603
  this.isTsFile = isTsFile;
4537
4604
  this.isSvelte5Plus = isSvelte5Plus;
4605
+ this.isRunes = isRunes;
4538
4606
  this.usesAccessors = false;
4539
4607
  /**
4540
4608
  * Uses the `$$Props` type
@@ -4616,10 +4684,10 @@ class ExportedNames {
4616
4684
  if (ts.isNamedExports(exportClause)) {
4617
4685
  for (const ne of exportClause.elements) {
4618
4686
  if (ne.propertyName) {
4619
- this.addExport(ne.propertyName, false, ne.name);
4687
+ this.addExport(ne.propertyName, false, ne.name, undefined, undefined, true);
4620
4688
  }
4621
4689
  else {
4622
- this.addExport(ne.name, false);
4690
+ this.addExport(ne.name, false, undefined, undefined, undefined, true);
4623
4691
  }
4624
4692
  }
4625
4693
  //we can remove entire statement
@@ -4752,7 +4820,11 @@ class ExportedNames {
4752
4820
  ? 'boolean'
4753
4821
  : ts.isIdentifier(element.initializer)
4754
4822
  ? `typeof ${element.initializer.text}`
4755
- : 'unknown';
4823
+ : ts.isObjectLiteralExpression(element.initializer)
4824
+ ? 'Record<string, unknown>'
4825
+ : ts.isArrayLiteralExpression(element.initializer)
4826
+ ? 'unknown[]'
4827
+ : 'unknown';
4756
4828
  props.push(`${name}?: ${type}`);
4757
4829
  }
4758
4830
  else {
@@ -4956,7 +5028,7 @@ class ExportedNames {
4956
5028
  /**
4957
5029
  * Adds export to map
4958
5030
  */
4959
- addExport(name, isLet, target = null, type = null, required = false) {
5031
+ addExport(name, isLet, target = null, type = null, required = false, isNamedExport = false) {
4960
5032
  const existingDeclaration = this.possibleExports.get(name.text);
4961
5033
  if (target) {
4962
5034
  this.exports.set(name.text, {
@@ -4964,7 +5036,8 @@ class ExportedNames {
4964
5036
  type: (type === null || type === void 0 ? void 0 : type.getText()) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.type),
4965
5037
  identifierText: target.text,
4966
5038
  required: required || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.required),
4967
- doc: this.getDoc(target) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc)
5039
+ doc: this.getDoc(target) || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc),
5040
+ isNamedExport
4968
5041
  });
4969
5042
  }
4970
5043
  else {
@@ -4972,7 +5045,8 @@ class ExportedNames {
4972
5045
  isLet: isLet || (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.isLet),
4973
5046
  type: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.type,
4974
5047
  required: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.required,
4975
- doc: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc
5048
+ doc: existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.doc,
5049
+ isNamedExport
4976
5050
  });
4977
5051
  }
4978
5052
  if (existingDeclaration === null || existingDeclaration === void 0 ? void 0 : existingDeclaration.isLet) {
@@ -5083,7 +5157,7 @@ class ExportedNames {
5083
5157
  */
5084
5158
  createExportsStr() {
5085
5159
  const names = Array.from(this.exports.entries());
5086
- const others = names.filter(([, { isLet }]) => !isLet);
5160
+ const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.usesRunes() && isNamedExport));
5087
5161
  const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
5088
5162
  if (this.isSvelte5Plus) {
5089
5163
  let str = '';
@@ -5155,7 +5229,7 @@ class ExportedNames {
5155
5229
  this.isSvelte5Plus && globals.some((global) => runes.includes(global));
5156
5230
  }
5157
5231
  usesRunes() {
5158
- return this.hasRunesGlobals || this.hasPropsRune();
5232
+ return this.hasRunesGlobals || this.hasPropsRune() || this.isRunes;
5159
5233
  }
5160
5234
  }
5161
5235
 
@@ -6115,12 +6189,12 @@ class InterfacesAndTypes {
6115
6189
  }
6116
6190
  }
6117
6191
 
6118
- function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript, isTSFile, basename, isSvelte5Plus) {
6192
+ function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript, isTSFile, basename, isSvelte5Plus, isRunes) {
6119
6193
  const htmlx = str.original;
6120
6194
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6121
6195
  const tsAst = ts.createSourceFile('component.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
6122
6196
  const astOffset = script.content.start;
6123
- const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus);
6197
+ const exportedNames = new ExportedNames(str, astOffset, basename, isTSFile, isSvelte5Plus, isRunes);
6124
6198
  const generics = new Generics(str, astOffset, script);
6125
6199
  const interfacesAndTypes = new InterfacesAndTypes();
6126
6200
  const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
@@ -6516,12 +6590,14 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
6516
6590
  const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), 'render()'));
6517
6591
  const doc = componentDocumentation.getFormatted();
6518
6592
  const className = fileName && classNameFromFilename(fileName, mode !== 'dts');
6593
+ const componentName = className || '$$Component';
6519
6594
  let statement;
6520
6595
  if (mode === 'dts') {
6521
6596
  if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
6522
6597
  statement =
6523
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` +
6524
- `export default ${className || '$$Component'};`;
6598
+ `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` +
6599
+ `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
6600
+ `export default ${componentName};`;
6525
6601
  }
6526
6602
  else if (isSvelte5) {
6527
6603
  // Inline definitions from Svelte shims; else dts files will reference the globals which will be unresolved
@@ -6545,9 +6621,9 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
6545
6621
  declare function $$__sveltets_2_isomorphic_component<
6546
6622
  Props extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>, Exports extends Record<string, any>, Bindings extends string
6547
6623
  >(klass: {props: Props, events: Events, slots: Slots, exports?: Exports, bindings?: Bindings }): $$__sveltets_2_IsomorphicComponent<Props, Events, Slots, Exports, Bindings>;\n`) +
6548
- `${doc}const ${className || '$$Component'} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6549
- surroundWithIgnoreComments(`type ${className || '$$Component'} = InstanceType<typeof ${className || '$$Component'}>;\n`) +
6550
- `export default ${className || '$$Component'};`;
6624
+ `${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6625
+ surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
6626
+ `export default ${componentName};`;
6551
6627
  }
6552
6628
  else if (isTsFile) {
6553
6629
  const svelteComponentClass = noSvelteComponentTyped
@@ -6582,14 +6658,15 @@ declare function $$__sveltets_2_isomorphic_component<
6582
6658
  if (isSvelte5) {
6583
6659
  if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
6584
6660
  statement =
6585
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_fn_component(render());\n` +
6586
- `export default ${className || '$$Component'};`;
6661
+ `\n${doc}const ${componentName} = __sveltets_2_fn_component(render());\n` +
6662
+ `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
6663
+ `export default ${componentName};`;
6587
6664
  }
6588
6665
  else {
6589
6666
  statement =
6590
- `\n${doc}const ${className || '$$Component'} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6591
- surroundWithIgnoreComments(`type ${className || '$$Component'} = InstanceType<typeof ${className || '$$Component'}>;\n`) +
6592
- `export default ${className || '$$Component'};`;
6667
+ `\n${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
6668
+ surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
6669
+ `export default ${componentName};`;
6593
6670
  }
6594
6671
  }
6595
6672
  else {
@@ -6761,6 +6838,7 @@ function processSvelteTemplate(str, parse, options) {
6761
6838
  let uses$$restProps = false;
6762
6839
  let uses$$slots = false;
6763
6840
  let usesAccessors = !!options.accessors;
6841
+ let isRunes = false;
6764
6842
  const componentDocumentation = new ComponentDocumentation();
6765
6843
  //track if we are in a declaration scope
6766
6844
  const isDeclaration = { value: false };
@@ -6784,6 +6862,9 @@ function processSvelteTemplate(str, parse, options) {
6784
6862
  usesAccessors = true;
6785
6863
  }
6786
6864
  break;
6865
+ case 'runes':
6866
+ isRunes = true;
6867
+ break;
6787
6868
  }
6788
6869
  }
6789
6870
  };
@@ -6963,7 +7044,8 @@ function processSvelteTemplate(str, parse, options) {
6963
7044
  uses$$slots,
6964
7045
  componentDocumentation,
6965
7046
  resolvedStores,
6966
- usesAccessors
7047
+ usesAccessors,
7048
+ isRunes
6967
7049
  };
6968
7050
  }
6969
7051
  function svelte2tsx(svelte, options = { parse }) {
@@ -6973,7 +7055,7 @@ function svelte2tsx(svelte, options = { parse }) {
6973
7055
  const basename = path__default.basename(options.filename || '');
6974
7056
  const svelte5Plus = Number(options.version[0]) > 4;
6975
7057
  // process the htmlx as a svelte template
6976
- let { htmlAst, moduleScriptTag, scriptTag, rootSnippets, slots, uses$$props, uses$$slots, uses$$restProps, events, componentDocumentation, resolvedStores, usesAccessors } = processSvelteTemplate(str, options.parse || parse, {
7058
+ let { htmlAst, moduleScriptTag, scriptTag, rootSnippets, slots, uses$$props, uses$$slots, uses$$restProps, events, componentDocumentation, resolvedStores, usesAccessors, isRunes } = processSvelteTemplate(str, options.parse || parse, {
6977
7059
  ...options,
6978
7060
  svelte5Plus
6979
7061
  });
@@ -6998,7 +7080,7 @@ function svelte2tsx(svelte, options = { parse }) {
6998
7080
  : instanceScriptTarget;
6999
7081
  const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart);
7000
7082
  //move the instance script and process the content
7001
- let exportedNames = new ExportedNames(str, 0, basename, options === null || options === void 0 ? void 0 : options.isTsFile, svelte5Plus);
7083
+ let exportedNames = new ExportedNames(str, 0, basename, options === null || options === void 0 ? void 0 : options.isTsFile, svelte5Plus, isRunes);
7002
7084
  let generics = new Generics(str, 0, { attributes: [] });
7003
7085
  let uses$$SlotsInterface = false;
7004
7086
  if (scriptTag) {
@@ -7007,7 +7089,7 @@ function svelte2tsx(svelte, options = { parse }) {
7007
7089
  str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
7008
7090
  }
7009
7091
  const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
7010
- /**hasModuleScripts */ !!moduleScriptTag, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus);
7092
+ /**hasModuleScripts */ !!moduleScriptTag, options === null || options === void 0 ? void 0 : options.isTsFile, basename, svelte5Plus, isRunes);
7011
7093
  uses$$props = uses$$props || res.uses$$props;
7012
7094
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7013
7095
  uses$$slots = uses$$slots || res.uses$$slots;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.7.21",
3
+ "version": "0.7.23",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "David Pershouse",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "svelte": "~4.2.19",
41
41
  "tiny-glob": "^0.2.6",
42
42
  "tslib": "^2.4.0",
43
- "typescript": "^5.5.2"
43
+ "typescript": "^5.6.3"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0",