svelte2tsx 0.5.22 → 0.5.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.
package/index.js CHANGED
@@ -4932,6 +4932,49 @@ function getNamesFromLabeledStatement(node) {
4932
4932
  // svelte won't let you create a variable with $ prefix (reserved for stores)
4933
4933
  .filter((name) => !name.startsWith('$')));
4934
4934
  }
4935
+ /**
4936
+ * move node to top of script so they appear outside our render function
4937
+ */
4938
+ function moveNode(node, str, astOffset, scriptStart, sourceFile) {
4939
+ var _a;
4940
+ const scanner = ts__default['default'].createScanner(sourceFile.languageVersion,
4941
+ /*skipTrivia*/ false, sourceFile.languageVariant);
4942
+ const comments = (_a = ts__default['default'].getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
4943
+ if (!comments.some((comment) => comment.hasTrailingNewLine) &&
4944
+ isNewGroup(sourceFile, node, scanner)) {
4945
+ str.appendRight(node.getStart() + astOffset, '\n');
4946
+ }
4947
+ for (const comment of comments) {
4948
+ const commentEnd = node.pos + comment.end + astOffset;
4949
+ str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
4950
+ if (comment.hasTrailingNewLine) {
4951
+ str.overwrite(commentEnd - 1, commentEnd, str.original[commentEnd - 1] + '\n');
4952
+ }
4953
+ }
4954
+ str.move(node.getStart() + astOffset, node.end + astOffset, scriptStart + 1);
4955
+ //add in a \n
4956
+ const originalEndChar = str.original[node.end + astOffset - 1];
4957
+ str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
4958
+ }
4959
+ /**
4960
+ * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
4961
+ */
4962
+ function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
4963
+ const startPos = topLevelImportDecl.getFullStart();
4964
+ const endPos = topLevelImportDecl.getStart();
4965
+ scanner.setText(sourceFile.text, startPos, endPos - startPos);
4966
+ let numberOfNewLines = 0;
4967
+ while (scanner.getTokenPos() < endPos) {
4968
+ const tokenKind = scanner.scan();
4969
+ if (tokenKind === ts__default['default'].SyntaxKind.NewLineTrivia) {
4970
+ numberOfNewLines++;
4971
+ if (numberOfNewLines >= 2) {
4972
+ return true;
4973
+ }
4974
+ }
4975
+ }
4976
+ return false;
4977
+ }
4935
4978
 
4936
4979
  function is$$EventsDeclaration(node) {
4937
4980
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Events';
@@ -5353,6 +5396,9 @@ class ExportedNames {
5353
5396
  constructor(str, astOffset) {
5354
5397
  this.str = str;
5355
5398
  this.astOffset = astOffset;
5399
+ /**
5400
+ * Uses the $$Props type
5401
+ */
5356
5402
  this.uses$$Props = false;
5357
5403
  this.exports = new Map();
5358
5404
  this.possibleExports = new Map();
@@ -5585,8 +5631,9 @@ class ExportedNames {
5585
5631
  * Creates a string from the collected props
5586
5632
  *
5587
5633
  * @param isTsFile Whether this is a TypeScript file or not.
5634
+ * @param uses$$propsValue whether the file references the $$props variable
5588
5635
  */
5589
- createPropsStr(isTsFile) {
5636
+ createPropsStr(isTsFile, uses$$propsValue) {
5590
5637
  const names = Array.from(this.exports.entries());
5591
5638
  if (this.uses$$Props) {
5592
5639
  const lets = names.filter(([, { isLet }]) => isLet);
@@ -5612,7 +5659,7 @@ class ExportedNames {
5612
5659
  this.createReturnElementsType(others).join(',') +
5613
5660
  '}}');
5614
5661
  }
5615
- if (names.length === 0) {
5662
+ if (names.length === 0 && !uses$$propsValue) {
5616
5663
  // Necessary, because {} roughly equals to any
5617
5664
  return isTsFile
5618
5665
  ? '{} as Record<string, never>'
@@ -6336,6 +6383,7 @@ class Generics {
6336
6383
  this.str = str;
6337
6384
  this.astOffset = astOffset;
6338
6385
  this.definitions = [];
6386
+ this.typeReferences = [];
6339
6387
  this.references = [];
6340
6388
  }
6341
6389
  addIfIsGeneric(node) {
@@ -6345,10 +6393,12 @@ class Generics {
6345
6393
  throw new Error('Invalid $$Generic declaration: Only one type argument allowed');
6346
6394
  }
6347
6395
  if (((_b = node.type.typeArguments) === null || _b === void 0 ? void 0 : _b.length) === 1) {
6348
- this.definitions.push(`${node.name.text} extends ${node.type.typeArguments[0].getText()}`);
6396
+ const typeReference = node.type.typeArguments[0].getText();
6397
+ this.typeReferences.push(typeReference);
6398
+ this.definitions.push(`${node.name.text} extends ${typeReference}`);
6349
6399
  }
6350
6400
  else {
6351
- this.definitions.push(`${node.name.text}`);
6401
+ this.definitions.push(node.name.text);
6352
6402
  }
6353
6403
  this.references.push(node.name.text);
6354
6404
  this.str.remove(this.astOffset + node.getStart(), this.astOffset + node.getEnd());
@@ -6364,6 +6414,9 @@ class Generics {
6364
6414
  ts__default['default'].isIdentifier(node.typeName) &&
6365
6415
  node.typeName.text === '$$Generic');
6366
6416
  }
6417
+ getTypeReferences() {
6418
+ return this.typeReferences;
6419
+ }
6367
6420
  toDefinitionString(addIgnore = false) {
6368
6421
  const surround = addIgnore ? surroundWithIgnoreComments : (str) => str;
6369
6422
  return this.definitions.length ? surround(`<${this.definitions.join(',')}>`) : '';
@@ -6380,44 +6433,7 @@ class Generics {
6380
6433
  * move imports to top of script so they appear outside our render function
6381
6434
  */
6382
6435
  function handleImportDeclaration(node, str, astOffset, scriptStart, sourceFile) {
6383
- var _a;
6384
- const scanner = ts__default['default'].createScanner(sourceFile.languageVersion,
6385
- /*skipTrivia*/ false, sourceFile.languageVariant);
6386
- const comments = (_a = ts__default['default'].getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
6387
- if (!comments.some((comment) => comment.hasTrailingNewLine) &&
6388
- isNewGroup(sourceFile, node, scanner)) {
6389
- str.appendRight(node.getStart() + astOffset, '\n');
6390
- }
6391
- for (const comment of comments) {
6392
- const commentEnd = node.pos + comment.end + astOffset;
6393
- str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
6394
- if (comment.hasTrailingNewLine) {
6395
- str.overwrite(commentEnd - 1, commentEnd, str.original[commentEnd - 1] + '\n');
6396
- }
6397
- }
6398
- str.move(node.getStart() + astOffset, node.end + astOffset, scriptStart + 1);
6399
- //add in a \n
6400
- const originalEndChar = str.original[node.end + astOffset - 1];
6401
- str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
6402
- }
6403
- /**
6404
- * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
6405
- */
6406
- function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
6407
- const startPos = topLevelImportDecl.getFullStart();
6408
- const endPos = topLevelImportDecl.getStart();
6409
- scanner.setText(sourceFile.text, startPos, endPos - startPos);
6410
- let numberOfNewLines = 0;
6411
- while (scanner.getTokenPos() < endPos) {
6412
- const tokenKind = scanner.scan();
6413
- if (tokenKind === ts__default['default'].SyntaxKind.NewLineTrivia) {
6414
- numberOfNewLines++;
6415
- if (numberOfNewLines >= 2) {
6416
- return true;
6417
- }
6418
- }
6419
- }
6420
- return false;
6436
+ return moveNode(node, str, astOffset, scriptStart, sourceFile);
6421
6437
  }
6422
6438
  /**
6423
6439
  * ensure it's in a newline.
@@ -6438,6 +6454,56 @@ function handleFirstInstanceImport(tsAst, astOffset, hasModuleScript, str) {
6438
6454
  str.appendRight(start + astOffset, '\n' + (hasModuleScript ? '\n' : ''));
6439
6455
  }
6440
6456
 
6457
+ function flatten(arr) {
6458
+ return arr.reduce((acc, val) => acc.concat(val), []);
6459
+ }
6460
+
6461
+ class InterfacesAndTypes {
6462
+ constructor() {
6463
+ this.node = null;
6464
+ this.all = [];
6465
+ this.references = new Map();
6466
+ }
6467
+ add(node) {
6468
+ this.all.push(node);
6469
+ }
6470
+ getNodesWithNames(names) {
6471
+ return this.all.filter((node) => names.includes(node.name.text));
6472
+ }
6473
+ // The following could be used to create a informative error message in case
6474
+ // someone has an interface that both references a generic and is used by one:
6475
+ addReference(reference) {
6476
+ if (!this.node) {
6477
+ return;
6478
+ }
6479
+ const references = this.references.get(this.node) || [];
6480
+ references.push(reference);
6481
+ this.references.set(this.node, references);
6482
+ }
6483
+ getNodesThatReferenceType(name) {
6484
+ const nodes = [];
6485
+ for (const [node, references] of this.references) {
6486
+ if (references.some((r) => r.typeName.getText() === name)) {
6487
+ nodes.push(node);
6488
+ }
6489
+ }
6490
+ return nodes;
6491
+ }
6492
+ getNodesThatRecursivelyReferenceType(name) {
6493
+ let types = [name];
6494
+ const nodes = new Set();
6495
+ while (types.length !== 0) {
6496
+ const newTypes = flatten(types.map((type) => this.getNodesThatReferenceType(type))).filter((t) => !nodes.has(t));
6497
+ newTypes.forEach((t) => nodes.add(t));
6498
+ types = newTypes.map((t) => t.name.text);
6499
+ }
6500
+ return [...nodes.values()];
6501
+ }
6502
+ getNodesThatRecursivelyReferenceTypes(names) {
6503
+ return flatten(names.map((name) => this.getNodesThatRecursivelyReferenceType(name)));
6504
+ }
6505
+ }
6506
+
6441
6507
  function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript) {
6442
6508
  const htmlx = str.original;
6443
6509
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
@@ -6445,6 +6511,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6445
6511
  const astOffset = script.content.start;
6446
6512
  const exportedNames = new ExportedNames(str, astOffset);
6447
6513
  const generics = new Generics(str, astOffset);
6514
+ const interfacesAndTypes = new InterfacesAndTypes();
6448
6515
  const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
6449
6516
  let uses$$props = false;
6450
6517
  let uses$$restProps = false;
@@ -6580,6 +6647,11 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6580
6647
  if (ts__namespace.isImportSpecifier(node)) {
6581
6648
  implicitStoreValues.addImportStatement(node);
6582
6649
  }
6650
+ if (ts__namespace.isTypeAliasDeclaration(node) || ts__namespace.isInterfaceDeclaration(node)) {
6651
+ interfacesAndTypes.node = node;
6652
+ interfacesAndTypes.add(node);
6653
+ onLeaveCallbacks.push(() => (interfacesAndTypes.node = null));
6654
+ }
6583
6655
  //handle stores etc
6584
6656
  if (ts__namespace.isIdentifier(node)) {
6585
6657
  handleIdentifier(node, parent);
@@ -6615,12 +6687,18 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6615
6687
  implicitTopLevelNames.modifyCode(rootScope.declared);
6616
6688
  implicitStoreValues.modifyCode(astOffset, str);
6617
6689
  handleFirstInstanceImport(tsAst, astOffset, hasModuleScript, str);
6690
+ // move interfaces and types out of the render function if they are referenced
6691
+ // by a $$Generic, otherwise it will be used before being defined after the transformation
6692
+ const nodesToMove = interfacesAndTypes.getNodesWithNames(generics.getTypeReferences());
6693
+ for (const node of nodesToMove) {
6694
+ moveNode(node, str, astOffset, script.start, tsAst);
6695
+ }
6618
6696
  if (mode === 'dts') {
6619
6697
  // Transform interface declarations to type declarations because indirectly
6620
6698
  // using interfaces inside the return type of a function is forbidden.
6621
6699
  // This is not a problem for intellisense/type inference but it will
6622
6700
  // break dts generation (file will not be generated).
6623
- transformInterfacesToTypes(tsAst, str, astOffset);
6701
+ transformInterfacesToTypes(tsAst, str, astOffset, nodesToMove);
6624
6702
  }
6625
6703
  return {
6626
6704
  exportedNames,
@@ -6632,8 +6710,11 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6632
6710
  generics
6633
6711
  };
6634
6712
  }
6635
- function transformInterfacesToTypes(tsAst, str, astOffset) {
6636
- tsAst.statements.filter(ts__namespace.isInterfaceDeclaration).forEach((node) => {
6713
+ function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
6714
+ tsAst.statements
6715
+ .filter(ts__namespace.isInterfaceDeclaration)
6716
+ .filter((i) => !movedNodes.includes(i))
6717
+ .forEach((node) => {
6637
6718
  var _a;
6638
6719
  str.overwrite(node.getStart() + astOffset, node.getStart() + astOffset + 'interface'.length, 'type');
6639
6720
  if ((_a = node.heritageClauses) === null || _a === void 0 ? void 0 : _a.length) {
@@ -6908,7 +6989,7 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
6908
6989
  })
6909
6990
  .join(', ') +
6910
6991
  '}';
6911
- const returnString = `\nreturn { props: ${exportedNames.createPropsStr(isTsFile)}` +
6992
+ const returnString = `\nreturn { props: ${exportedNames.createPropsStr(isTsFile, uses$$props)}` +
6912
6993
  `, slots: ${slotsAsDef}` +
6913
6994
  `, events: ${events.toDefString()} }}`;
6914
6995
  // wrap template with callback
package/index.mjs CHANGED
@@ -4902,6 +4902,49 @@ function getNamesFromLabeledStatement(node) {
4902
4902
  // svelte won't let you create a variable with $ prefix (reserved for stores)
4903
4903
  .filter((name) => !name.startsWith('$')));
4904
4904
  }
4905
+ /**
4906
+ * move node to top of script so they appear outside our render function
4907
+ */
4908
+ function moveNode(node, str, astOffset, scriptStart, sourceFile) {
4909
+ var _a;
4910
+ const scanner = ts__default.createScanner(sourceFile.languageVersion,
4911
+ /*skipTrivia*/ false, sourceFile.languageVariant);
4912
+ const comments = (_a = ts__default.getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
4913
+ if (!comments.some((comment) => comment.hasTrailingNewLine) &&
4914
+ isNewGroup(sourceFile, node, scanner)) {
4915
+ str.appendRight(node.getStart() + astOffset, '\n');
4916
+ }
4917
+ for (const comment of comments) {
4918
+ const commentEnd = node.pos + comment.end + astOffset;
4919
+ str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
4920
+ if (comment.hasTrailingNewLine) {
4921
+ str.overwrite(commentEnd - 1, commentEnd, str.original[commentEnd - 1] + '\n');
4922
+ }
4923
+ }
4924
+ str.move(node.getStart() + astOffset, node.end + astOffset, scriptStart + 1);
4925
+ //add in a \n
4926
+ const originalEndChar = str.original[node.end + astOffset - 1];
4927
+ str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
4928
+ }
4929
+ /**
4930
+ * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
4931
+ */
4932
+ function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
4933
+ const startPos = topLevelImportDecl.getFullStart();
4934
+ const endPos = topLevelImportDecl.getStart();
4935
+ scanner.setText(sourceFile.text, startPos, endPos - startPos);
4936
+ let numberOfNewLines = 0;
4937
+ while (scanner.getTokenPos() < endPos) {
4938
+ const tokenKind = scanner.scan();
4939
+ if (tokenKind === ts__default.SyntaxKind.NewLineTrivia) {
4940
+ numberOfNewLines++;
4941
+ if (numberOfNewLines >= 2) {
4942
+ return true;
4943
+ }
4944
+ }
4945
+ }
4946
+ return false;
4947
+ }
4905
4948
 
4906
4949
  function is$$EventsDeclaration(node) {
4907
4950
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Events';
@@ -5323,6 +5366,9 @@ class ExportedNames {
5323
5366
  constructor(str, astOffset) {
5324
5367
  this.str = str;
5325
5368
  this.astOffset = astOffset;
5369
+ /**
5370
+ * Uses the $$Props type
5371
+ */
5326
5372
  this.uses$$Props = false;
5327
5373
  this.exports = new Map();
5328
5374
  this.possibleExports = new Map();
@@ -5555,8 +5601,9 @@ class ExportedNames {
5555
5601
  * Creates a string from the collected props
5556
5602
  *
5557
5603
  * @param isTsFile Whether this is a TypeScript file or not.
5604
+ * @param uses$$propsValue whether the file references the $$props variable
5558
5605
  */
5559
- createPropsStr(isTsFile) {
5606
+ createPropsStr(isTsFile, uses$$propsValue) {
5560
5607
  const names = Array.from(this.exports.entries());
5561
5608
  if (this.uses$$Props) {
5562
5609
  const lets = names.filter(([, { isLet }]) => isLet);
@@ -5582,7 +5629,7 @@ class ExportedNames {
5582
5629
  this.createReturnElementsType(others).join(',') +
5583
5630
  '}}');
5584
5631
  }
5585
- if (names.length === 0) {
5632
+ if (names.length === 0 && !uses$$propsValue) {
5586
5633
  // Necessary, because {} roughly equals to any
5587
5634
  return isTsFile
5588
5635
  ? '{} as Record<string, never>'
@@ -6306,6 +6353,7 @@ class Generics {
6306
6353
  this.str = str;
6307
6354
  this.astOffset = astOffset;
6308
6355
  this.definitions = [];
6356
+ this.typeReferences = [];
6309
6357
  this.references = [];
6310
6358
  }
6311
6359
  addIfIsGeneric(node) {
@@ -6315,10 +6363,12 @@ class Generics {
6315
6363
  throw new Error('Invalid $$Generic declaration: Only one type argument allowed');
6316
6364
  }
6317
6365
  if (((_b = node.type.typeArguments) === null || _b === void 0 ? void 0 : _b.length) === 1) {
6318
- this.definitions.push(`${node.name.text} extends ${node.type.typeArguments[0].getText()}`);
6366
+ const typeReference = node.type.typeArguments[0].getText();
6367
+ this.typeReferences.push(typeReference);
6368
+ this.definitions.push(`${node.name.text} extends ${typeReference}`);
6319
6369
  }
6320
6370
  else {
6321
- this.definitions.push(`${node.name.text}`);
6371
+ this.definitions.push(node.name.text);
6322
6372
  }
6323
6373
  this.references.push(node.name.text);
6324
6374
  this.str.remove(this.astOffset + node.getStart(), this.astOffset + node.getEnd());
@@ -6334,6 +6384,9 @@ class Generics {
6334
6384
  ts__default.isIdentifier(node.typeName) &&
6335
6385
  node.typeName.text === '$$Generic');
6336
6386
  }
6387
+ getTypeReferences() {
6388
+ return this.typeReferences;
6389
+ }
6337
6390
  toDefinitionString(addIgnore = false) {
6338
6391
  const surround = addIgnore ? surroundWithIgnoreComments : (str) => str;
6339
6392
  return this.definitions.length ? surround(`<${this.definitions.join(',')}>`) : '';
@@ -6350,44 +6403,7 @@ class Generics {
6350
6403
  * move imports to top of script so they appear outside our render function
6351
6404
  */
6352
6405
  function handleImportDeclaration(node, str, astOffset, scriptStart, sourceFile) {
6353
- var _a;
6354
- const scanner = ts__default.createScanner(sourceFile.languageVersion,
6355
- /*skipTrivia*/ false, sourceFile.languageVariant);
6356
- const comments = (_a = ts__default.getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
6357
- if (!comments.some((comment) => comment.hasTrailingNewLine) &&
6358
- isNewGroup(sourceFile, node, scanner)) {
6359
- str.appendRight(node.getStart() + astOffset, '\n');
6360
- }
6361
- for (const comment of comments) {
6362
- const commentEnd = node.pos + comment.end + astOffset;
6363
- str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
6364
- if (comment.hasTrailingNewLine) {
6365
- str.overwrite(commentEnd - 1, commentEnd, str.original[commentEnd - 1] + '\n');
6366
- }
6367
- }
6368
- str.move(node.getStart() + astOffset, node.end + astOffset, scriptStart + 1);
6369
- //add in a \n
6370
- const originalEndChar = str.original[node.end + astOffset - 1];
6371
- str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
6372
- }
6373
- /**
6374
- * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
6375
- */
6376
- function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
6377
- const startPos = topLevelImportDecl.getFullStart();
6378
- const endPos = topLevelImportDecl.getStart();
6379
- scanner.setText(sourceFile.text, startPos, endPos - startPos);
6380
- let numberOfNewLines = 0;
6381
- while (scanner.getTokenPos() < endPos) {
6382
- const tokenKind = scanner.scan();
6383
- if (tokenKind === ts__default.SyntaxKind.NewLineTrivia) {
6384
- numberOfNewLines++;
6385
- if (numberOfNewLines >= 2) {
6386
- return true;
6387
- }
6388
- }
6389
- }
6390
- return false;
6406
+ return moveNode(node, str, astOffset, scriptStart, sourceFile);
6391
6407
  }
6392
6408
  /**
6393
6409
  * ensure it's in a newline.
@@ -6408,6 +6424,56 @@ function handleFirstInstanceImport(tsAst, astOffset, hasModuleScript, str) {
6408
6424
  str.appendRight(start + astOffset, '\n' + (hasModuleScript ? '\n' : ''));
6409
6425
  }
6410
6426
 
6427
+ function flatten(arr) {
6428
+ return arr.reduce((acc, val) => acc.concat(val), []);
6429
+ }
6430
+
6431
+ class InterfacesAndTypes {
6432
+ constructor() {
6433
+ this.node = null;
6434
+ this.all = [];
6435
+ this.references = new Map();
6436
+ }
6437
+ add(node) {
6438
+ this.all.push(node);
6439
+ }
6440
+ getNodesWithNames(names) {
6441
+ return this.all.filter((node) => names.includes(node.name.text));
6442
+ }
6443
+ // The following could be used to create a informative error message in case
6444
+ // someone has an interface that both references a generic and is used by one:
6445
+ addReference(reference) {
6446
+ if (!this.node) {
6447
+ return;
6448
+ }
6449
+ const references = this.references.get(this.node) || [];
6450
+ references.push(reference);
6451
+ this.references.set(this.node, references);
6452
+ }
6453
+ getNodesThatReferenceType(name) {
6454
+ const nodes = [];
6455
+ for (const [node, references] of this.references) {
6456
+ if (references.some((r) => r.typeName.getText() === name)) {
6457
+ nodes.push(node);
6458
+ }
6459
+ }
6460
+ return nodes;
6461
+ }
6462
+ getNodesThatRecursivelyReferenceType(name) {
6463
+ let types = [name];
6464
+ const nodes = new Set();
6465
+ while (types.length !== 0) {
6466
+ const newTypes = flatten(types.map((type) => this.getNodesThatReferenceType(type))).filter((t) => !nodes.has(t));
6467
+ newTypes.forEach((t) => nodes.add(t));
6468
+ types = newTypes.map((t) => t.name.text);
6469
+ }
6470
+ return [...nodes.values()];
6471
+ }
6472
+ getNodesThatRecursivelyReferenceTypes(names) {
6473
+ return flatten(names.map((name) => this.getNodesThatRecursivelyReferenceType(name)));
6474
+ }
6475
+ }
6476
+
6411
6477
  function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript) {
6412
6478
  const htmlx = str.original;
6413
6479
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
@@ -6415,6 +6481,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6415
6481
  const astOffset = script.content.start;
6416
6482
  const exportedNames = new ExportedNames(str, astOffset);
6417
6483
  const generics = new Generics(str, astOffset);
6484
+ const interfacesAndTypes = new InterfacesAndTypes();
6418
6485
  const implicitTopLevelNames = new ImplicitTopLevelNames(str, astOffset);
6419
6486
  let uses$$props = false;
6420
6487
  let uses$$restProps = false;
@@ -6550,6 +6617,11 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6550
6617
  if (ts.isImportSpecifier(node)) {
6551
6618
  implicitStoreValues.addImportStatement(node);
6552
6619
  }
6620
+ if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) {
6621
+ interfacesAndTypes.node = node;
6622
+ interfacesAndTypes.add(node);
6623
+ onLeaveCallbacks.push(() => (interfacesAndTypes.node = null));
6624
+ }
6553
6625
  //handle stores etc
6554
6626
  if (ts.isIdentifier(node)) {
6555
6627
  handleIdentifier(node, parent);
@@ -6585,12 +6657,18 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6585
6657
  implicitTopLevelNames.modifyCode(rootScope.declared);
6586
6658
  implicitStoreValues.modifyCode(astOffset, str);
6587
6659
  handleFirstInstanceImport(tsAst, astOffset, hasModuleScript, str);
6660
+ // move interfaces and types out of the render function if they are referenced
6661
+ // by a $$Generic, otherwise it will be used before being defined after the transformation
6662
+ const nodesToMove = interfacesAndTypes.getNodesWithNames(generics.getTypeReferences());
6663
+ for (const node of nodesToMove) {
6664
+ moveNode(node, str, astOffset, script.start, tsAst);
6665
+ }
6588
6666
  if (mode === 'dts') {
6589
6667
  // Transform interface declarations to type declarations because indirectly
6590
6668
  // using interfaces inside the return type of a function is forbidden.
6591
6669
  // This is not a problem for intellisense/type inference but it will
6592
6670
  // break dts generation (file will not be generated).
6593
- transformInterfacesToTypes(tsAst, str, astOffset);
6671
+ transformInterfacesToTypes(tsAst, str, astOffset, nodesToMove);
6594
6672
  }
6595
6673
  return {
6596
6674
  exportedNames,
@@ -6602,8 +6680,11 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6602
6680
  generics
6603
6681
  };
6604
6682
  }
6605
- function transformInterfacesToTypes(tsAst, str, astOffset) {
6606
- tsAst.statements.filter(ts.isInterfaceDeclaration).forEach((node) => {
6683
+ function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
6684
+ tsAst.statements
6685
+ .filter(ts.isInterfaceDeclaration)
6686
+ .filter((i) => !movedNodes.includes(i))
6687
+ .forEach((node) => {
6607
6688
  var _a;
6608
6689
  str.overwrite(node.getStart() + astOffset, node.getStart() + astOffset + 'interface'.length, 'type');
6609
6690
  if ((_a = node.heritageClauses) === null || _a === void 0 ? void 0 : _a.length) {
@@ -6878,7 +6959,7 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
6878
6959
  })
6879
6960
  .join(', ') +
6880
6961
  '}';
6881
- const returnString = `\nreturn { props: ${exportedNames.createPropsStr(isTsFile)}` +
6962
+ const returnString = `\nreturn { props: ${exportedNames.createPropsStr(isTsFile, uses$$props)}` +
6882
6963
  `, slots: ${slotsAsDef}` +
6883
6964
  `, events: ${events.toDefString()} }}`;
6884
6965
  // wrap template with callback
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.5.22",
3
+ "version": "0.5.23",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "David Pershouse",
6
6
  "license": "MIT",
@@ -538,6 +538,12 @@ export interface HTMLAttributes<T extends EventTarget> extends AriaAttributes, D
538
538
  * Elements with the contenteditable attribute support innerHTML and textContent bindings.
539
539
  */
540
540
  'bind:textContent'?: string | undefined | null;
541
+
542
+ // SvelteKit
543
+ 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
544
+ 'data-sveltekit-preload-code'?: true | '' | 'eager' | 'viewport' | 'hover' | 'tap' | 'off' | undefined | null;
545
+ 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
546
+ 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
541
547
  }
542
548
 
543
549
  export type HTMLAttributeAnchorTarget =
@@ -558,12 +564,6 @@ export interface HTMLAnchorAttributes extends HTMLAttributes<HTMLAnchorElement>
558
564
  type?: string | undefined | null;
559
565
  referrerpolicy?: ReferrerPolicy | undefined | null;
560
566
 
561
- // SvelteKit
562
- 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
563
- 'data-sveltekit-preload-code'?: true | '' | 'eager' | 'viewport' | 'hover' | 'tap' | 'off' | undefined | null;
564
- 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
565
- 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
566
-
567
567
  // Sapper
568
568
  'sapper:noscroll'?: true | undefined | null;
569
569
  'sapper:prefetch'?: true | undefined | null;
package/svelte-jsx.d.ts CHANGED
@@ -839,6 +839,11 @@ declare namespace svelte.JSX {
839
839
  results?: number | undefined | null;
840
840
  security?: string | undefined | null;
841
841
  unselectable?: boolean | undefined | null;
842
+
843
+ 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
844
+ 'data-sveltekit-preload-code'?: true | '' | 'eager' | 'viewport' | 'hover' | 'tap' | 'off' | undefined | null;
845
+ 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
846
+ 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
842
847
  }
843
848
 
844
849
  // this list is "complete" in that it contains every SVG attribute
@@ -1176,13 +1181,6 @@ declare namespace svelte.JSX {
1176
1181
  sapperPrefetch?: true | undefined | null;
1177
1182
  }
1178
1183
 
1179
- interface SvelteKitAnchorProps {
1180
- 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
1181
- 'data-sveltekit-preload-code'?: true | '' | 'eager' | 'viewport' | 'hover' | 'tap' | 'off' | undefined | null;
1182
- 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
1183
- 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
1184
- }
1185
-
1186
1184
  interface SvelteMediaTimeRange {
1187
1185
  start: number;
1188
1186
  end: number;
@@ -1221,7 +1219,7 @@ declare namespace svelte.JSX {
1221
1219
 
1222
1220
  interface IntrinsicElements {
1223
1221
  // HTML
1224
- a: HTMLProps<HTMLAnchorElement> & SapperAnchorProps & SvelteKitAnchorProps;
1222
+ a: HTMLProps<HTMLAnchorElement> & SapperAnchorProps;
1225
1223
  abbr: HTMLProps<HTMLElement>;
1226
1224
  address: HTMLProps<HTMLElement>;
1227
1225
  area: HTMLProps<HTMLAreaElement>;
@@ -1398,7 +1396,7 @@ declare namespace svelte.JSX {
1398
1396
  sveltefragment: { slot?: string; };
1399
1397
  svelteoptions: { [name: string]: any };
1400
1398
  sveltehead: { [name: string]: any };
1401
- svelteelement: { 'this': string | undefined | null; } & HTMLProps<any> & SVGProps<any> & SapperAnchorProps & SvelteKitAnchorProps;
1399
+ svelteelement: { 'this': string | undefined | null; } & HTMLProps<any> & SVGProps<any> & SapperAnchorProps;
1402
1400
  // Needed due to backwards compatibility type which hits these
1403
1401
  'svelte:window': HTMLProps<Window> & SvelteWindowProps;
1404
1402
  'svelte:body': HTMLProps<HTMLElement>;