svelte2tsx 0.7.39 → 0.7.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +120 -64
  2. package/index.mjs +120 -64
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -2829,6 +2829,22 @@ const supportsBindThis = [
2829
2829
  */
2830
2830
  function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus) {
2831
2831
  const isGetSetBinding = attr.expression.type === 'SequenceExpression';
2832
+ const [get, set] = isGetSetBinding ? attr.expression.expressions : [];
2833
+ // bind this
2834
+ if (attr.name === 'this' && supportsBindThis.includes(parent.type)) {
2835
+ // bind:this is effectively only works bottom up - the variable is updated by the element, not
2836
+ // the other way round. So we check if the instance is assignable to the variable.
2837
+ // Note: If the component unmounts (it's inside an if block, or svelte:component this={null},
2838
+ // the value becomes null, but we don't add it to the clause because it would introduce
2839
+ // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2840
+ if (isGetSetBinding) {
2841
+ element.appendToStartEnd(['(', [set.start, getEnd(set)], `)(${element.name});`]);
2842
+ }
2843
+ else {
2844
+ appendOneWayBinding(attr, ` = ${element.name}`, element);
2845
+ }
2846
+ return;
2847
+ }
2832
2848
  if (!isGetSetBinding) {
2833
2849
  // bind group on input
2834
2850
  if (element instanceof Element && attr.name == 'group' && parent.name == 'input') {
@@ -2836,16 +2852,6 @@ function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus)
2836
2852
  appendOneWayBinding(attr, ' = __sveltets_2_any(null)', element);
2837
2853
  return;
2838
2854
  }
2839
- // bind this
2840
- if (attr.name === 'this' && supportsBindThis.includes(parent.type)) {
2841
- // bind:this is effectively only works bottom up - the variable is updated by the element, not
2842
- // the other way round. So we check if the instance is assignable to the variable.
2843
- // Note: If the component unmounts (it's inside an if block, or svelte:component this={null},
2844
- // the value becomes null, but we don't add it to the clause because it would introduce
2845
- // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2846
- appendOneWayBinding(attr, ` = ${element.name}`, element);
2847
- return;
2848
- }
2849
2855
  // one way binding
2850
2856
  if (oneWayBindingAttributes.has(attr.name) && element instanceof Element) {
2851
2857
  appendOneWayBinding(attr, `= ${element.name}.${attr.name}`, element);
@@ -2881,7 +2887,6 @@ function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus)
2881
2887
  str.original.lastIndexOf('=', attr.expression.start)
2882
2888
  ]
2883
2889
  ];
2884
- const [get, set] = isGetSetBinding ? attr.expression.expressions : [];
2885
2890
  const value = isShorthand
2886
2891
  ? preserveBind && element instanceof Element
2887
2892
  ? [rangeWithTrailingPropertyAccess(str.original, attr.expression)]
@@ -3111,18 +3116,18 @@ function handleElse(str, elseBlock, parent) {
3111
3116
  }
3112
3117
 
3113
3118
  /**
3114
- * {#key expr}content{/key} ---> expr; content
3119
+ * {#key expr}content{/key} ---> expr; {content}
3115
3120
  */
3116
3121
  function handleKey(str, keyBlock) {
3117
- // {#key expr} -> expr;
3122
+ // {#key expr} -> expr;{
3118
3123
  str.overwrite(keyBlock.start, keyBlock.expression.start, '', { contentOnly: true });
3119
3124
  const expressionEnd = withTrailingPropertyAccess(str.original, keyBlock.expression.end);
3120
3125
  const end = str.original.indexOf('}', expressionEnd);
3121
- str.overwrite(expressionEnd, end + 1, '; ');
3122
- // {/key} ->
3126
+ str.overwrite(expressionEnd, end + 1, '; {');
3127
+ // {/key} -> }
3123
3128
  const endKey = str.original.lastIndexOf('{', keyBlock.end - 1);
3124
3129
  if (!isImplicitlyClosedBlock(endKey, keyBlock)) {
3125
- str.overwrite(endKey, keyBlock.end, '', { contentOnly: true });
3130
+ str.overwrite(endKey, keyBlock.end, '}', { contentOnly: true });
3126
3131
  }
3127
3132
  }
3128
3133
 
@@ -4866,13 +4871,6 @@ function handleAttachTag(tag, element) {
4866
4871
  }
4867
4872
  }
4868
4873
 
4869
- function stripDoctype(str) {
4870
- const regex = /<!doctype(.+?)>(\n)?/i;
4871
- const result = regex.exec(str.original);
4872
- if (result) {
4873
- str.remove(result.index, result.index + result[0].length);
4874
- }
4875
- }
4876
4874
  /**
4877
4875
  * Walks the HTMLx part of the Svelte component
4878
4876
  * and converts it to JSX
@@ -4880,7 +4878,6 @@ function stripDoctype(str) {
4880
4878
  function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
4881
4879
  options.typingsNamespace = options.typingsNamespace || 'svelteHTML';
4882
4880
  const preserveAttributeCase = options.namespace === 'foreign';
4883
- stripDoctype(str);
4884
4881
  const rootSnippets = [];
4885
4882
  let element;
4886
4883
  const pendingSnippetHoistCheck = new Set();
@@ -4960,11 +4957,13 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
4960
4957
  });
4961
4958
  };
4962
4959
  const eventHandler = new EventHandler();
4960
+ const path = [];
4963
4961
  walk(ast, {
4964
4962
  enter: (estreeTypedNode, estreeTypedParent, prop) => {
4965
4963
  var _a;
4966
4964
  const node = estreeTypedNode;
4967
4965
  const parent = estreeTypedParent;
4966
+ path.push(node);
4968
4967
  if (prop == 'params' &&
4969
4968
  (parent.type == 'FunctionDeclaration' || parent.type == 'ArrowFunctionExpression')) {
4970
4969
  isDeclaration.value = true;
@@ -5086,7 +5085,10 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5086
5085
  else if (node.type === 'Slot') {
5087
5086
  slotHandler.handleSlot(node, templateScope);
5088
5087
  }
5089
- if (node.name !== '!DOCTYPE') {
5088
+ if (node.name === '!DOCTYPE') {
5089
+ str.remove(node.start, node.end);
5090
+ }
5091
+ else {
5090
5092
  if (element) {
5091
5093
  element.child = new Element(str, node, options.typingsNamespace, element);
5092
5094
  element = element.child;
@@ -5152,6 +5154,10 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5152
5154
  handleScopeAndResolveForSlotInner(node.error, node.expression, node.catch);
5153
5155
  }
5154
5156
  break;
5157
+ case 'AwaitExpression':
5158
+ isRunes || (isRunes = path.every(({ type }) => type !== 'ArrowFunctionExpression' &&
5159
+ type !== 'FunctionExpression' &&
5160
+ type !== 'FunctionDeclaration'));
5155
5161
  }
5156
5162
  }
5157
5163
  catch (e) {
@@ -5162,6 +5168,7 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5162
5168
  leave: (estreeTypedNode, estreeTypedParent, prop) => {
5163
5169
  const node = estreeTypedNode;
5164
5170
  const parent = estreeTypedParent;
5171
+ path.pop();
5165
5172
  if (prop == 'params' &&
5166
5173
  (parent.type == 'FunctionDeclaration' || parent.type == 'ArrowFunctionExpression')) {
5167
5174
  isDeclaration.value = false;
@@ -5680,7 +5687,7 @@ function addComponentExport(params) {
5680
5687
  addSimpleComponentExport(params);
5681
5688
  }
5682
5689
  }
5683
- function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, isTsFile, str, generics, usesSlots, isSvelte5, noSvelteComponentTyped }) {
5690
+ function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, generics, usesSlots, isSvelte5, noSvelteComponentTyped, hasTopLevelAwait }) {
5684
5691
  const genericsDef = generics.toDefinitionString();
5685
5692
  const genericsRef = generics.toReferencesString();
5686
5693
  const doc = componentDocumentation.getFormatted();
@@ -5688,32 +5695,38 @@ function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, com
5688
5695
  function returnType(forPart) {
5689
5696
  return `ReturnType<__sveltets_Render${genericsRef}['${forPart}']>`;
5690
5697
  }
5698
+ const renderCall = hasTopLevelAwait
5699
+ ? `(await ${internalHelpers.renderName}${genericsRef}())`
5700
+ : `${internalHelpers.renderName}${genericsRef}()`;
5691
5701
  // TODO once Svelte 4 compatibility is dropped, we can simplify this, because since TS 4.7 it is possible to use generics
5692
5702
  // like this: `typeof render<T>` - which wasn't possibly before, hence the class + methods workaround.
5693
5703
  let statement = `
5694
5704
  class __sveltets_Render${genericsDef} {
5695
5705
  props() {
5696
- return ${props(true, canHaveAnyProp, exportedNames, `${internalHelpers.renderName}${genericsRef}()`)}.props;
5706
+ return ${props(true, canHaveAnyProp, exportedNames, renderCall)}.props;
5697
5707
  }
5698
5708
  events() {
5699
- return ${_events(events.hasStrictEvents() || exportedNames.usesRunes(), `${internalHelpers.renderName}${genericsRef}()`)}.events;
5709
+ return ${_events(events.hasStrictEvents() || exportedNames.isRunesMode(), renderCall)}.events;
5700
5710
  }
5701
5711
  slots() {
5702
- return ${internalHelpers.renderName}${genericsRef}().slots;
5712
+ return ${renderCall}.slots;
5703
5713
  }
5704
5714
  `;
5705
5715
  // For Svelte 5+ we assume TS > 4.7
5706
- if (isSvelte5 && !isTsFile && exportedNames.usesRunes()) {
5716
+ if (isSvelte5 && exportedNames.isRunesMode()) {
5717
+ const renderType = hasTopLevelAwait
5718
+ ? `Awaited<ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>>`
5719
+ : `ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>`;
5707
5720
  statement = `
5708
5721
  class __sveltets_Render${genericsDef} {
5709
- props(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['props'] { return null as any; }
5710
- events(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['events'] { return null as any; }
5711
- slots(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['slots'] { return null as any; }
5722
+ props(): ${renderType}['props'] { return null as any; }
5723
+ events(): ${renderType}['events'] { return null as any; }
5724
+ slots(): ${renderType}['slots'] { return null as any; }
5712
5725
  `;
5713
5726
  }
5714
5727
  statement += isSvelte5
5715
5728
  ? ` bindings() { return ${exportedNames.createBindingsStr()}; }
5716
- exports() { return ${exportedNames.hasExports() ? `${internalHelpers.renderName}${genericsRef}().exports` : '{}'}; }
5729
+ ${hasTopLevelAwait ? 'async ' : ''}exports() { return ${exportedNames.hasExports() ? `${renderCall}.exports` : '{}'}; }
5717
5730
  }\n`
5718
5731
  : '}\n';
5719
5732
  const svelteComponentClass = noSvelteComponentTyped
@@ -5726,7 +5739,7 @@ class __sveltets_Render${genericsDef} {
5726
5739
  // Don't add props/events/slots type exports in dts mode for now, maybe someone asks for it to be back,
5727
5740
  // but it's safer to not do it for now to have more flexibility in the future.
5728
5741
  let eventsSlotsType = [];
5729
- if (events.hasEvents() || !exportedNames.usesRunes()) {
5742
+ if (events.hasEvents() || !exportedNames.isRunesMode()) {
5730
5743
  eventsSlotsType.push(`$$events?: ${returnType('events')}`);
5731
5744
  }
5732
5745
  if (usesSlots) {
@@ -5771,16 +5784,23 @@ class __sveltets_Render${genericsDef} {
5771
5784
  }
5772
5785
  str.append(statement);
5773
5786
  }
5774
- function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, usesSlots, noSvelteComponentTyped, isSvelte5 }) {
5775
- const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), `${internalHelpers.renderName}()`));
5787
+ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, usesSlots, noSvelteComponentTyped, isSvelte5, hasTopLevelAwait }) {
5788
+ const renderCall = hasTopLevelAwait
5789
+ ? `$${internalHelpers.renderName}`
5790
+ : `${internalHelpers.renderName}()`;
5791
+ const awaitDeclaration = hasTopLevelAwait
5792
+ ? // tsconfig could disallow top-level await, so we need to wrap it in ignore
5793
+ surroundWithIgnoreComments(`const $${internalHelpers.renderName} = await ${internalHelpers.renderName}();`) + '\n'
5794
+ : '';
5795
+ const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), renderCall));
5776
5796
  const doc = componentDocumentation.getFormatted();
5777
5797
  const className = fileName && classNameFromFilename(fileName, mode !== 'dts');
5778
5798
  const componentName = className || '$$Component';
5779
5799
  let statement;
5780
5800
  if (mode === 'dts') {
5781
- if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
5801
+ if (isSvelte5 && exportedNames.isRunesMode() && !usesSlots && !events.hasEvents()) {
5782
5802
  statement =
5783
- `\n${doc}const ${componentName} = __sveltets_2_fn_component(${internalHelpers.renderName}());\n` +
5803
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_fn_component(${renderCall});\n` +
5784
5804
  `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
5785
5805
  `export default ${componentName};`;
5786
5806
  }
@@ -5806,7 +5826,7 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
5806
5826
  declare function $$__sveltets_2_isomorphic_component<
5807
5827
  Props extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>, Exports extends Record<string, any>, Bindings extends string
5808
5828
  >(klass: {props: Props, events: Events, slots: Slots, exports?: Exports, bindings?: Bindings }): $$__sveltets_2_IsomorphicComponent<Props, Events, Slots, Exports, Bindings>;\n`) +
5809
- `${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5829
+ `${awaitDeclaration}${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5810
5830
  surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
5811
5831
  `export default ${componentName};`;
5812
5832
  }
@@ -5841,9 +5861,9 @@ declare function $$__sveltets_2_isomorphic_component<
5841
5861
  }
5842
5862
  else {
5843
5863
  if (isSvelte5) {
5844
- if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
5864
+ if (exportedNames.isRunesMode() && !usesSlots && !events.hasEvents()) {
5845
5865
  statement =
5846
- `\n${doc}const ${componentName} = __sveltets_2_fn_component(${internalHelpers.renderName}());\n` +
5866
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_fn_component(${renderCall});\n` +
5847
5867
  // Surround the type with ignore comments so it is filtered out from go-to-definition etc,
5848
5868
  // which for some editors can cause duplicates
5849
5869
  surroundWithIgnoreComments(`type ${componentName} = ReturnType<typeof ${componentName}>;\n`) +
@@ -5851,7 +5871,7 @@ declare function $$__sveltets_2_isomorphic_component<
5851
5871
  }
5852
5872
  else {
5853
5873
  statement =
5854
- `\n${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5874
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5855
5875
  surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
5856
5876
  `export default ${componentName};`;
5857
5877
  }
@@ -5898,7 +5918,7 @@ function _events(strictEvents, renderStr) {
5898
5918
  return strictEvents ? renderStr : `__sveltets_2_with_any_event(${renderStr})`;
5899
5919
  }
5900
5920
  function props(isTsFile, canHaveAnyProp, exportedNames, renderStr) {
5901
- if (exportedNames.usesRunes()) {
5921
+ if (exportedNames.isRunesMode()) {
5902
5922
  return renderStr;
5903
5923
  }
5904
5924
  else if (isTsFile) {
@@ -5943,7 +5963,7 @@ function classNameFromFilename(filename, appendSuffix) {
5943
5963
  }
5944
5964
  }
5945
5965
 
5946
- function createRenderFunction({ str, scriptTag, scriptDestination, slots, events, exportedNames, uses$$props, uses$$restProps, uses$$slots, uses$$SlotsInterface, generics, isTsFile, mode }) {
5966
+ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events, exportedNames, uses$$props, uses$$restProps, uses$$slots, uses$$SlotsInterface, generics, hasTopLevelAwait, isTsFile, mode }) {
5947
5967
  const htmlx = str.original;
5948
5968
  let propsDecl = '';
5949
5969
  if (uses$$props) {
@@ -5977,12 +5997,12 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
5977
5997
  start++;
5978
5998
  end--;
5979
5999
  }
5980
- str.overwrite(scriptTag.start + 1, start - 1, `function ${internalHelpers.renderName}`);
6000
+ str.overwrite(scriptTag.start + 1, start - 1, `${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}`);
5981
6001
  str.overwrite(start - 1, start, isTsFile ? '<' : `<${IGNORE_START_COMMENT}`); // if the generics are unused, only this char is colored opaque
5982
6002
  str.overwrite(end, scriptTagEnd, `>${isTsFile ? '' : IGNORE_END_COMMENT}() {${propsDecl}\n`);
5983
6003
  }
5984
6004
  else {
5985
- str.overwrite(scriptTag.start + 1, scriptTagEnd, `function ${internalHelpers.renderName}${generics.toDefinitionString(true)}() {${propsDecl}\n`);
6005
+ str.overwrite(scriptTag.start + 1, scriptTagEnd, `${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}${generics.toDefinitionString(true)}() {${propsDecl}\n`);
5986
6006
  }
5987
6007
  const scriptEndTagStart = htmlx.lastIndexOf('<', scriptTag.end - 1);
5988
6008
  // wrap template with callback
@@ -5991,7 +6011,7 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
5991
6011
  });
5992
6012
  }
5993
6013
  else {
5994
- str.prependRight(scriptDestination, `;function ${internalHelpers.renderName}() {` +
6014
+ str.prependRight(scriptDestination, `;${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}() {` +
5995
6015
  `${propsDecl}${slotsDeclaration}\nasync () => {`);
5996
6016
  }
5997
6017
  const slotsAsDef = uses$$SlotsInterface
@@ -6626,12 +6646,16 @@ class ExportedNames {
6626
6646
  ? element.propertyName.text
6627
6647
  : element.name.text;
6628
6648
  if (isKitRouteFile) {
6649
+ // TODO once we know we can assume SvelteKit 2.16+, simplify this to always using LayoutProps/PageProps
6629
6650
  if (name === 'data') {
6630
6651
  props.push(`data: import('./$types.js').${isKitLayoutFile ? 'LayoutData' : 'PageData'}`);
6631
6652
  }
6632
6653
  if (name === 'form' && !isKitLayoutFile) {
6633
6654
  props.push(`form: import('./$types.js').ActionData`);
6634
6655
  }
6656
+ if (name === 'params') {
6657
+ props.push(`params: import('./$types.js').${isKitLayoutFile ? 'LayoutProps' : 'PageProps'}['params']`);
6658
+ }
6635
6659
  }
6636
6660
  else if (element.initializer) {
6637
6661
  const initializer = ts.isCallExpression(element.initializer) &&
@@ -6804,7 +6828,7 @@ class ExportedNames {
6804
6828
  this.getters.add(node.text);
6805
6829
  }
6806
6830
  createClassGetters(generics = '') {
6807
- if (this.usesRunes()) {
6831
+ if (this.isRunesMode()) {
6808
6832
  // In runes mode, exports are no longer part of props
6809
6833
  return Array.from(this.getters)
6810
6834
  .map((name) => `\n get ${name}() { return ${internalHelpers.renderName}${generics}().exports.${name} }`)
@@ -6920,7 +6944,7 @@ class ExportedNames {
6920
6944
  */
6921
6945
  createPropsStr(uses$$propsOr$$restProps) {
6922
6946
  const names = Array.from(this.exports.entries());
6923
- if (this.usesRunes()) {
6947
+ if (this.isRunesMode()) {
6924
6948
  if (this.$props.type) {
6925
6949
  return '{} as any as ' + this.$props.type;
6926
6950
  }
@@ -6968,14 +6992,14 @@ class ExportedNames {
6968
6992
  return `{${returnElements.join(' , ')}} as {${returnElementsType.join(', ')}}`;
6969
6993
  }
6970
6994
  hasNoProps() {
6971
- if (this.usesRunes()) {
6995
+ if (this.isRunesMode()) {
6972
6996
  return !this.$props.type && !this.$props.comment;
6973
6997
  }
6974
6998
  const names = Array.from(this.exports.entries());
6975
6999
  return names.length === 0;
6976
7000
  }
6977
7001
  createBindingsStr() {
6978
- if (this.usesRunes()) {
7002
+ if (this.isRunesMode()) {
6979
7003
  // will be just the empty strings for zero bindings, which is impossible to create a binding for, so it works out fine
6980
7004
  return `__sveltets_$$bindings('${this.$props.bindings.join("', '")}')`;
6981
7005
  }
@@ -6990,17 +7014,17 @@ class ExportedNames {
6990
7014
  */
6991
7015
  createExportsStr() {
6992
7016
  const names = Array.from(this.exports.entries());
6993
- const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.usesRunes() && isNamedExport));
6994
- const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
7017
+ const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.isRunesMode() && isNamedExport));
7018
+ const needsAccessors = this.usesAccessors && names.length > 0 && !this.isRunesMode(); // runes mode doesn't support accessors
6995
7019
  if (this.isSvelte5Plus) {
6996
7020
  let str = '';
6997
- if (others.length > 0 || this.usesRunes() || needsAccessors) {
7021
+ if (others.length > 0 || this.isRunesMode() || needsAccessors) {
6998
7022
  const exports = needsAccessors ? names : others;
6999
7023
  if (others.length > 0 || needsAccessors) {
7000
7024
  if (this.isTsFile) {
7001
7025
  str +=
7002
7026
  // Reference imports that have a type, else they are marked as unused if nothing in the component references them
7003
- `, exports: {${this.createReturnElements(this.usesRunes() ? others : [], false, true)}} as any as { ` +
7027
+ `, exports: {${this.createReturnElements(this.isRunesMode() ? others : [], false, true)}} as any as { ` +
7004
7028
  this.createReturnElementsType(exports, undefined, true).join(',') +
7005
7029
  ' }';
7006
7030
  }
@@ -7043,7 +7067,7 @@ class ExportedNames {
7043
7067
  });
7044
7068
  }
7045
7069
  createOptionalPropsArray() {
7046
- if (this.usesRunes()) {
7070
+ if (this.isRunesMode()) {
7047
7071
  return [];
7048
7072
  }
7049
7073
  else {
@@ -7067,7 +7091,13 @@ class ExportedNames {
7067
7091
  this.hasRunesGlobals =
7068
7092
  this.isSvelte5Plus && globals.some((global) => runes.includes(global));
7069
7093
  }
7070
- usesRunes() {
7094
+ enterRunesMode() {
7095
+ this.isRunes = true;
7096
+ }
7097
+ /**
7098
+ * True if uses runes or top level await or await in template expressions
7099
+ */
7100
+ isRunesMode() {
7071
7101
  return this.hasRunesGlobals || this.hasPropsRune() || this.isRunes;
7072
7102
  }
7073
7103
  }
@@ -7222,8 +7252,9 @@ class Generics {
7222
7252
  * were used as stores are appended with `let $xx = __sveltets_2_store_get(xx)` to create the store variables.
7223
7253
  */
7224
7254
  class ImplicitStoreValues {
7225
- constructor(storesResolvedInTemplate = [], renderFunctionStart, storeFromImportsWrapper = (input) => input) {
7255
+ constructor(storesResolvedInTemplate = [], renderFunctionStart, isSvelte5Plus, storeFromImportsWrapper = (input) => input) {
7226
7256
  this.renderFunctionStart = renderFunctionStart;
7257
+ this.isSvelte5Plus = isSvelte5Plus;
7227
7258
  this.storeFromImportsWrapper = storeFromImportsWrapper;
7228
7259
  this.accessedStores = new Set();
7229
7260
  this.variableDeclarations = [];
@@ -7296,7 +7327,9 @@ class ImplicitStoreValues {
7296
7327
  }
7297
7328
  attachStoreValueDeclarationOfImportsToRenderFn(str) {
7298
7329
  const storeNames = this.importStatements
7299
- .filter(({ name }) => name && this.accessedStores.has(name.getText()))
7330
+ .filter((declaration) => declaration.name &&
7331
+ (!this.isSvelte5Plus || !this.isSvelteStoreDerivedImport(declaration)) &&
7332
+ this.accessedStores.has(declaration.name.getText()))
7300
7333
  .map(({ name }) => name.getText());
7301
7334
  if (!storeNames.length) {
7302
7335
  return;
@@ -7304,6 +7337,17 @@ class ImplicitStoreValues {
7304
7337
  const storeDeclarations = this.storeFromImportsWrapper(surroundWithIgnoreComments(this.createStoreDeclarations(storeNames)));
7305
7338
  str.appendRight(this.renderFunctionStart, storeDeclarations);
7306
7339
  }
7340
+ isSvelteStoreDerivedImport(declaration) {
7341
+ // named import of 'derived' from 'svelte/store'
7342
+ if (!ts.isImportSpecifier(declaration) || declaration.name.text !== 'derived') {
7343
+ return false;
7344
+ }
7345
+ const importDeclaration = declaration.parent.parent.parent;
7346
+ return (ts.isImportDeclaration(importDeclaration) &&
7347
+ importDeclaration.moduleSpecifier &&
7348
+ ts.isStringLiteral(importDeclaration.moduleSpecifier) &&
7349
+ importDeclaration.moduleSpecifier.text === 'svelte/store');
7350
+ }
7307
7351
  createStoreDeclarations(storeNames) {
7308
7352
  let declarations = '';
7309
7353
  for (let i = 0; i < storeNames.length; i++) {
@@ -7531,6 +7575,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7531
7575
  let uses$$restProps = false;
7532
7576
  let uses$$slots = false;
7533
7577
  let uses$$SlotsInterface = false;
7578
+ let hasTopLevelAwait = false;
7534
7579
  //track if we are in a declaration scope
7535
7580
  let isDeclaration = false;
7536
7581
  //track the variable declaration node
@@ -7719,6 +7764,10 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7719
7764
  }
7720
7765
  implicitTopLevelNames.handleReactiveStatement(node, binaryExpression);
7721
7766
  }
7767
+ // Check for top-level await expressions
7768
+ if (isSvelte5Plus && ts.isAwaitExpression(node) && scope === rootScope) {
7769
+ hasTopLevelAwait = true;
7770
+ }
7722
7771
  // Defensively call function (checking for undefined) because it got added only recently (TS 4.0)
7723
7772
  // and therefore might break people using older TS versions
7724
7773
  // Don't transform in ts mode because <type>value type assertions are valid in this case
@@ -7769,7 +7818,8 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7769
7818
  uses$$restProps,
7770
7819
  uses$$slots,
7771
7820
  uses$$SlotsInterface,
7772
- generics
7821
+ generics,
7822
+ hasTopLevelAwait
7773
7823
  };
7774
7824
  }
7775
7825
  function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
@@ -7902,11 +7952,12 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7902
7952
  const renderFunctionStart = scriptTag
7903
7953
  ? str.original.lastIndexOf('>', scriptTag.content.start) + 1
7904
7954
  : instanceScriptTarget;
7905
- const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart);
7955
+ const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart, svelte5Plus);
7906
7956
  //move the instance script and process the content
7907
7957
  let exportedNames = new ExportedNames(str, 0, basename, isTsFile, svelte5Plus, isRunes);
7908
7958
  let generics = new Generics(str, 0, { attributes: [] });
7909
7959
  let uses$$SlotsInterface = false;
7960
+ let hasTopLevelAwait = false;
7910
7961
  if (scriptTag) {
7911
7962
  //ensure it is between the module script and the rest of the template (the variables need to be declared before the jsx template)
7912
7963
  if (scriptTag.start != instanceScriptTarget) {
@@ -7916,11 +7967,14 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7916
7967
  uses$$props = uses$$props || res.uses$$props;
7917
7968
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7918
7969
  uses$$slots = uses$$slots || res.uses$$slots;
7919
- ({ exportedNames, events, generics, uses$$SlotsInterface } = res);
7970
+ ({ exportedNames, events, generics, uses$$SlotsInterface, hasTopLevelAwait } = res);
7920
7971
  }
7921
7972
  exportedNames.usesAccessors = usesAccessors;
7922
7973
  if (svelte5Plus) {
7923
7974
  exportedNames.checkGlobalsForRunes(implicitStoreValues.getGlobals());
7975
+ if (hasTopLevelAwait) {
7976
+ exportedNames.enterRunesMode();
7977
+ }
7924
7978
  }
7925
7979
  //wrap the script tag and template content in a function returning the slot and exports
7926
7980
  createRenderFunction({
@@ -7935,13 +7989,14 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7935
7989
  uses$$slots,
7936
7990
  uses$$SlotsInterface,
7937
7991
  generics,
7992
+ hasTopLevelAwait,
7938
7993
  svelte5Plus,
7939
7994
  isTsFile,
7940
7995
  mode: options.mode
7941
7996
  });
7942
7997
  // we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items
7943
7998
  if (moduleScriptTag) {
7944
- processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`), moduleAst);
7999
+ processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, svelte5Plus, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`), moduleAst);
7945
8000
  if (!scriptTag) {
7946
8001
  moduleAst.tsAst.forEachChild((node) => exportedNames.hoistableInterfaces.analyzeModuleScriptNode(node));
7947
8002
  }
@@ -7989,6 +8044,7 @@ function svelte2tsx(svelte, options = { parse: compiler.parse }) {
7989
8044
  mode: options.mode,
7990
8045
  generics,
7991
8046
  isSvelte5: svelte5Plus,
8047
+ hasTopLevelAwait,
7992
8048
  noSvelteComponentTyped: options.noSvelteComponentTyped
7993
8049
  });
7994
8050
  if (options.mode === 'dts') {
package/index.mjs CHANGED
@@ -2809,6 +2809,22 @@ const supportsBindThis = [
2809
2809
  */
2810
2810
  function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus) {
2811
2811
  const isGetSetBinding = attr.expression.type === 'SequenceExpression';
2812
+ const [get, set] = isGetSetBinding ? attr.expression.expressions : [];
2813
+ // bind this
2814
+ if (attr.name === 'this' && supportsBindThis.includes(parent.type)) {
2815
+ // bind:this is effectively only works bottom up - the variable is updated by the element, not
2816
+ // the other way round. So we check if the instance is assignable to the variable.
2817
+ // Note: If the component unmounts (it's inside an if block, or svelte:component this={null},
2818
+ // the value becomes null, but we don't add it to the clause because it would introduce
2819
+ // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2820
+ if (isGetSetBinding) {
2821
+ element.appendToStartEnd(['(', [set.start, getEnd(set)], `)(${element.name});`]);
2822
+ }
2823
+ else {
2824
+ appendOneWayBinding(attr, ` = ${element.name}`, element);
2825
+ }
2826
+ return;
2827
+ }
2812
2828
  if (!isGetSetBinding) {
2813
2829
  // bind group on input
2814
2830
  if (element instanceof Element && attr.name == 'group' && parent.name == 'input') {
@@ -2816,16 +2832,6 @@ function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus)
2816
2832
  appendOneWayBinding(attr, ' = __sveltets_2_any(null)', element);
2817
2833
  return;
2818
2834
  }
2819
- // bind this
2820
- if (attr.name === 'this' && supportsBindThis.includes(parent.type)) {
2821
- // bind:this is effectively only works bottom up - the variable is updated by the element, not
2822
- // the other way round. So we check if the instance is assignable to the variable.
2823
- // Note: If the component unmounts (it's inside an if block, or svelte:component this={null},
2824
- // the value becomes null, but we don't add it to the clause because it would introduce
2825
- // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2826
- appendOneWayBinding(attr, ` = ${element.name}`, element);
2827
- return;
2828
- }
2829
2835
  // one way binding
2830
2836
  if (oneWayBindingAttributes.has(attr.name) && element instanceof Element) {
2831
2837
  appendOneWayBinding(attr, `= ${element.name}.${attr.name}`, element);
@@ -2861,7 +2867,6 @@ function handleBinding(str, attr, parent, element, preserveBind, isSvelte5Plus)
2861
2867
  str.original.lastIndexOf('=', attr.expression.start)
2862
2868
  ]
2863
2869
  ];
2864
- const [get, set] = isGetSetBinding ? attr.expression.expressions : [];
2865
2870
  const value = isShorthand
2866
2871
  ? preserveBind && element instanceof Element
2867
2872
  ? [rangeWithTrailingPropertyAccess(str.original, attr.expression)]
@@ -3091,18 +3096,18 @@ function handleElse(str, elseBlock, parent) {
3091
3096
  }
3092
3097
 
3093
3098
  /**
3094
- * {#key expr}content{/key} ---> expr; content
3099
+ * {#key expr}content{/key} ---> expr; {content}
3095
3100
  */
3096
3101
  function handleKey(str, keyBlock) {
3097
- // {#key expr} -> expr;
3102
+ // {#key expr} -> expr;{
3098
3103
  str.overwrite(keyBlock.start, keyBlock.expression.start, '', { contentOnly: true });
3099
3104
  const expressionEnd = withTrailingPropertyAccess(str.original, keyBlock.expression.end);
3100
3105
  const end = str.original.indexOf('}', expressionEnd);
3101
- str.overwrite(expressionEnd, end + 1, '; ');
3102
- // {/key} ->
3106
+ str.overwrite(expressionEnd, end + 1, '; {');
3107
+ // {/key} -> }
3103
3108
  const endKey = str.original.lastIndexOf('{', keyBlock.end - 1);
3104
3109
  if (!isImplicitlyClosedBlock(endKey, keyBlock)) {
3105
- str.overwrite(endKey, keyBlock.end, '', { contentOnly: true });
3110
+ str.overwrite(endKey, keyBlock.end, '}', { contentOnly: true });
3106
3111
  }
3107
3112
  }
3108
3113
 
@@ -4846,13 +4851,6 @@ function handleAttachTag(tag, element) {
4846
4851
  }
4847
4852
  }
4848
4853
 
4849
- function stripDoctype(str) {
4850
- const regex = /<!doctype(.+?)>(\n)?/i;
4851
- const result = regex.exec(str.original);
4852
- if (result) {
4853
- str.remove(result.index, result.index + result[0].length);
4854
- }
4855
- }
4856
4854
  /**
4857
4855
  * Walks the HTMLx part of the Svelte component
4858
4856
  * and converts it to JSX
@@ -4860,7 +4858,6 @@ function stripDoctype(str) {
4860
4858
  function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
4861
4859
  options.typingsNamespace = options.typingsNamespace || 'svelteHTML';
4862
4860
  const preserveAttributeCase = options.namespace === 'foreign';
4863
- stripDoctype(str);
4864
4861
  const rootSnippets = [];
4865
4862
  let element;
4866
4863
  const pendingSnippetHoistCheck = new Set();
@@ -4940,11 +4937,13 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
4940
4937
  });
4941
4938
  };
4942
4939
  const eventHandler = new EventHandler();
4940
+ const path = [];
4943
4941
  walk(ast, {
4944
4942
  enter: (estreeTypedNode, estreeTypedParent, prop) => {
4945
4943
  var _a;
4946
4944
  const node = estreeTypedNode;
4947
4945
  const parent = estreeTypedParent;
4946
+ path.push(node);
4948
4947
  if (prop == 'params' &&
4949
4948
  (parent.type == 'FunctionDeclaration' || parent.type == 'ArrowFunctionExpression')) {
4950
4949
  isDeclaration.value = true;
@@ -5066,7 +5065,10 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5066
5065
  else if (node.type === 'Slot') {
5067
5066
  slotHandler.handleSlot(node, templateScope);
5068
5067
  }
5069
- if (node.name !== '!DOCTYPE') {
5068
+ if (node.name === '!DOCTYPE') {
5069
+ str.remove(node.start, node.end);
5070
+ }
5071
+ else {
5070
5072
  if (element) {
5071
5073
  element.child = new Element(str, node, options.typingsNamespace, element);
5072
5074
  element = element.child;
@@ -5132,6 +5134,10 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5132
5134
  handleScopeAndResolveForSlotInner(node.error, node.expression, node.catch);
5133
5135
  }
5134
5136
  break;
5137
+ case 'AwaitExpression':
5138
+ isRunes || (isRunes = path.every(({ type }) => type !== 'ArrowFunctionExpression' &&
5139
+ type !== 'FunctionExpression' &&
5140
+ type !== 'FunctionDeclaration'));
5135
5141
  }
5136
5142
  }
5137
5143
  catch (e) {
@@ -5142,6 +5148,7 @@ function convertHtmlxToJsx(str, ast, tags, options = { svelte5Plus: false }) {
5142
5148
  leave: (estreeTypedNode, estreeTypedParent, prop) => {
5143
5149
  const node = estreeTypedNode;
5144
5150
  const parent = estreeTypedParent;
5151
+ path.pop();
5145
5152
  if (prop == 'params' &&
5146
5153
  (parent.type == 'FunctionDeclaration' || parent.type == 'ArrowFunctionExpression')) {
5147
5154
  isDeclaration.value = false;
@@ -5660,7 +5667,7 @@ function addComponentExport(params) {
5660
5667
  addSimpleComponentExport(params);
5661
5668
  }
5662
5669
  }
5663
- function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, isTsFile, str, generics, usesSlots, isSvelte5, noSvelteComponentTyped }) {
5670
+ function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, generics, usesSlots, isSvelte5, noSvelteComponentTyped, hasTopLevelAwait }) {
5664
5671
  const genericsDef = generics.toDefinitionString();
5665
5672
  const genericsRef = generics.toReferencesString();
5666
5673
  const doc = componentDocumentation.getFormatted();
@@ -5668,32 +5675,38 @@ function addGenericsComponentExport({ events, canHaveAnyProp, exportedNames, com
5668
5675
  function returnType(forPart) {
5669
5676
  return `ReturnType<__sveltets_Render${genericsRef}['${forPart}']>`;
5670
5677
  }
5678
+ const renderCall = hasTopLevelAwait
5679
+ ? `(await ${internalHelpers.renderName}${genericsRef}())`
5680
+ : `${internalHelpers.renderName}${genericsRef}()`;
5671
5681
  // TODO once Svelte 4 compatibility is dropped, we can simplify this, because since TS 4.7 it is possible to use generics
5672
5682
  // like this: `typeof render<T>` - which wasn't possibly before, hence the class + methods workaround.
5673
5683
  let statement = `
5674
5684
  class __sveltets_Render${genericsDef} {
5675
5685
  props() {
5676
- return ${props(true, canHaveAnyProp, exportedNames, `${internalHelpers.renderName}${genericsRef}()`)}.props;
5686
+ return ${props(true, canHaveAnyProp, exportedNames, renderCall)}.props;
5677
5687
  }
5678
5688
  events() {
5679
- return ${_events(events.hasStrictEvents() || exportedNames.usesRunes(), `${internalHelpers.renderName}${genericsRef}()`)}.events;
5689
+ return ${_events(events.hasStrictEvents() || exportedNames.isRunesMode(), renderCall)}.events;
5680
5690
  }
5681
5691
  slots() {
5682
- return ${internalHelpers.renderName}${genericsRef}().slots;
5692
+ return ${renderCall}.slots;
5683
5693
  }
5684
5694
  `;
5685
5695
  // For Svelte 5+ we assume TS > 4.7
5686
- if (isSvelte5 && !isTsFile && exportedNames.usesRunes()) {
5696
+ if (isSvelte5 && exportedNames.isRunesMode()) {
5697
+ const renderType = hasTopLevelAwait
5698
+ ? `Awaited<ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>>`
5699
+ : `ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>`;
5687
5700
  statement = `
5688
5701
  class __sveltets_Render${genericsDef} {
5689
- props(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['props'] { return null as any; }
5690
- events(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['events'] { return null as any; }
5691
- slots(): ReturnType<typeof ${internalHelpers.renderName}${genericsRef}>['slots'] { return null as any; }
5702
+ props(): ${renderType}['props'] { return null as any; }
5703
+ events(): ${renderType}['events'] { return null as any; }
5704
+ slots(): ${renderType}['slots'] { return null as any; }
5692
5705
  `;
5693
5706
  }
5694
5707
  statement += isSvelte5
5695
5708
  ? ` bindings() { return ${exportedNames.createBindingsStr()}; }
5696
- exports() { return ${exportedNames.hasExports() ? `${internalHelpers.renderName}${genericsRef}().exports` : '{}'}; }
5709
+ ${hasTopLevelAwait ? 'async ' : ''}exports() { return ${exportedNames.hasExports() ? `${renderCall}.exports` : '{}'}; }
5697
5710
  }\n`
5698
5711
  : '}\n';
5699
5712
  const svelteComponentClass = noSvelteComponentTyped
@@ -5706,7 +5719,7 @@ class __sveltets_Render${genericsDef} {
5706
5719
  // Don't add props/events/slots type exports in dts mode for now, maybe someone asks for it to be back,
5707
5720
  // but it's safer to not do it for now to have more flexibility in the future.
5708
5721
  let eventsSlotsType = [];
5709
- if (events.hasEvents() || !exportedNames.usesRunes()) {
5722
+ if (events.hasEvents() || !exportedNames.isRunesMode()) {
5710
5723
  eventsSlotsType.push(`$$events?: ${returnType('events')}`);
5711
5724
  }
5712
5725
  if (usesSlots) {
@@ -5751,16 +5764,23 @@ class __sveltets_Render${genericsDef} {
5751
5764
  }
5752
5765
  str.append(statement);
5753
5766
  }
5754
- function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, usesSlots, noSvelteComponentTyped, isSvelte5 }) {
5755
- const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), `${internalHelpers.renderName}()`));
5767
+ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNames, componentDocumentation, fileName, mode, usesAccessors, str, usesSlots, noSvelteComponentTyped, isSvelte5, hasTopLevelAwait }) {
5768
+ const renderCall = hasTopLevelAwait
5769
+ ? `$${internalHelpers.renderName}`
5770
+ : `${internalHelpers.renderName}()`;
5771
+ const awaitDeclaration = hasTopLevelAwait
5772
+ ? // tsconfig could disallow top-level await, so we need to wrap it in ignore
5773
+ surroundWithIgnoreComments(`const $${internalHelpers.renderName} = await ${internalHelpers.renderName}();`) + '\n'
5774
+ : '';
5775
+ const propDef = props(isTsFile, canHaveAnyProp, exportedNames, _events(events.hasStrictEvents(), renderCall));
5756
5776
  const doc = componentDocumentation.getFormatted();
5757
5777
  const className = fileName && classNameFromFilename(fileName, mode !== 'dts');
5758
5778
  const componentName = className || '$$Component';
5759
5779
  let statement;
5760
5780
  if (mode === 'dts') {
5761
- if (isSvelte5 && exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
5781
+ if (isSvelte5 && exportedNames.isRunesMode() && !usesSlots && !events.hasEvents()) {
5762
5782
  statement =
5763
- `\n${doc}const ${componentName} = __sveltets_2_fn_component(${internalHelpers.renderName}());\n` +
5783
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_fn_component(${renderCall});\n` +
5764
5784
  `type ${componentName} = ReturnType<typeof ${componentName}>;\n` +
5765
5785
  `export default ${componentName};`;
5766
5786
  }
@@ -5786,7 +5806,7 @@ function addSimpleComponentExport({ events, isTsFile, canHaveAnyProp, exportedNa
5786
5806
  declare function $$__sveltets_2_isomorphic_component<
5787
5807
  Props extends Record<string, any>, Events extends Record<string, any>, Slots extends Record<string, any>, Exports extends Record<string, any>, Bindings extends string
5788
5808
  >(klass: {props: Props, events: Events, slots: Slots, exports?: Exports, bindings?: Bindings }): $$__sveltets_2_IsomorphicComponent<Props, Events, Slots, Exports, Bindings>;\n`) +
5789
- `${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5809
+ `${awaitDeclaration}${doc}const ${componentName} = $$__sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5790
5810
  surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
5791
5811
  `export default ${componentName};`;
5792
5812
  }
@@ -5821,9 +5841,9 @@ declare function $$__sveltets_2_isomorphic_component<
5821
5841
  }
5822
5842
  else {
5823
5843
  if (isSvelte5) {
5824
- if (exportedNames.usesRunes() && !usesSlots && !events.hasEvents()) {
5844
+ if (exportedNames.isRunesMode() && !usesSlots && !events.hasEvents()) {
5825
5845
  statement =
5826
- `\n${doc}const ${componentName} = __sveltets_2_fn_component(${internalHelpers.renderName}());\n` +
5846
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_fn_component(${renderCall});\n` +
5827
5847
  // Surround the type with ignore comments so it is filtered out from go-to-definition etc,
5828
5848
  // which for some editors can cause duplicates
5829
5849
  surroundWithIgnoreComments(`type ${componentName} = ReturnType<typeof ${componentName}>;\n`) +
@@ -5831,7 +5851,7 @@ declare function $$__sveltets_2_isomorphic_component<
5831
5851
  }
5832
5852
  else {
5833
5853
  statement =
5834
- `\n${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5854
+ `\n${awaitDeclaration}${doc}const ${componentName} = __sveltets_2_isomorphic_component${usesSlots ? '_slots' : ''}(${propDef});\n` +
5835
5855
  surroundWithIgnoreComments(`type ${componentName} = InstanceType<typeof ${componentName}>;\n`) +
5836
5856
  `export default ${componentName};`;
5837
5857
  }
@@ -5878,7 +5898,7 @@ function _events(strictEvents, renderStr) {
5878
5898
  return strictEvents ? renderStr : `__sveltets_2_with_any_event(${renderStr})`;
5879
5899
  }
5880
5900
  function props(isTsFile, canHaveAnyProp, exportedNames, renderStr) {
5881
- if (exportedNames.usesRunes()) {
5901
+ if (exportedNames.isRunesMode()) {
5882
5902
  return renderStr;
5883
5903
  }
5884
5904
  else if (isTsFile) {
@@ -5923,7 +5943,7 @@ function classNameFromFilename(filename, appendSuffix) {
5923
5943
  }
5924
5944
  }
5925
5945
 
5926
- function createRenderFunction({ str, scriptTag, scriptDestination, slots, events, exportedNames, uses$$props, uses$$restProps, uses$$slots, uses$$SlotsInterface, generics, isTsFile, mode }) {
5946
+ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events, exportedNames, uses$$props, uses$$restProps, uses$$slots, uses$$SlotsInterface, generics, hasTopLevelAwait, isTsFile, mode }) {
5927
5947
  const htmlx = str.original;
5928
5948
  let propsDecl = '';
5929
5949
  if (uses$$props) {
@@ -5957,12 +5977,12 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
5957
5977
  start++;
5958
5978
  end--;
5959
5979
  }
5960
- str.overwrite(scriptTag.start + 1, start - 1, `function ${internalHelpers.renderName}`);
5980
+ str.overwrite(scriptTag.start + 1, start - 1, `${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}`);
5961
5981
  str.overwrite(start - 1, start, isTsFile ? '<' : `<${IGNORE_START_COMMENT}`); // if the generics are unused, only this char is colored opaque
5962
5982
  str.overwrite(end, scriptTagEnd, `>${isTsFile ? '' : IGNORE_END_COMMENT}() {${propsDecl}\n`);
5963
5983
  }
5964
5984
  else {
5965
- str.overwrite(scriptTag.start + 1, scriptTagEnd, `function ${internalHelpers.renderName}${generics.toDefinitionString(true)}() {${propsDecl}\n`);
5985
+ str.overwrite(scriptTag.start + 1, scriptTagEnd, `${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}${generics.toDefinitionString(true)}() {${propsDecl}\n`);
5966
5986
  }
5967
5987
  const scriptEndTagStart = htmlx.lastIndexOf('<', scriptTag.end - 1);
5968
5988
  // wrap template with callback
@@ -5971,7 +5991,7 @@ function createRenderFunction({ str, scriptTag, scriptDestination, slots, events
5971
5991
  });
5972
5992
  }
5973
5993
  else {
5974
- str.prependRight(scriptDestination, `;function ${internalHelpers.renderName}() {` +
5994
+ str.prependRight(scriptDestination, `;${hasTopLevelAwait ? 'async ' : ''}function ${internalHelpers.renderName}() {` +
5975
5995
  `${propsDecl}${slotsDeclaration}\nasync () => {`);
5976
5996
  }
5977
5997
  const slotsAsDef = uses$$SlotsInterface
@@ -6606,12 +6626,16 @@ class ExportedNames {
6606
6626
  ? element.propertyName.text
6607
6627
  : element.name.text;
6608
6628
  if (isKitRouteFile) {
6629
+ // TODO once we know we can assume SvelteKit 2.16+, simplify this to always using LayoutProps/PageProps
6609
6630
  if (name === 'data') {
6610
6631
  props.push(`data: import('./$types.js').${isKitLayoutFile ? 'LayoutData' : 'PageData'}`);
6611
6632
  }
6612
6633
  if (name === 'form' && !isKitLayoutFile) {
6613
6634
  props.push(`form: import('./$types.js').ActionData`);
6614
6635
  }
6636
+ if (name === 'params') {
6637
+ props.push(`params: import('./$types.js').${isKitLayoutFile ? 'LayoutProps' : 'PageProps'}['params']`);
6638
+ }
6615
6639
  }
6616
6640
  else if (element.initializer) {
6617
6641
  const initializer = ts.isCallExpression(element.initializer) &&
@@ -6784,7 +6808,7 @@ class ExportedNames {
6784
6808
  this.getters.add(node.text);
6785
6809
  }
6786
6810
  createClassGetters(generics = '') {
6787
- if (this.usesRunes()) {
6811
+ if (this.isRunesMode()) {
6788
6812
  // In runes mode, exports are no longer part of props
6789
6813
  return Array.from(this.getters)
6790
6814
  .map((name) => `\n get ${name}() { return ${internalHelpers.renderName}${generics}().exports.${name} }`)
@@ -6900,7 +6924,7 @@ class ExportedNames {
6900
6924
  */
6901
6925
  createPropsStr(uses$$propsOr$$restProps) {
6902
6926
  const names = Array.from(this.exports.entries());
6903
- if (this.usesRunes()) {
6927
+ if (this.isRunesMode()) {
6904
6928
  if (this.$props.type) {
6905
6929
  return '{} as any as ' + this.$props.type;
6906
6930
  }
@@ -6948,14 +6972,14 @@ class ExportedNames {
6948
6972
  return `{${returnElements.join(' , ')}} as {${returnElementsType.join(', ')}}`;
6949
6973
  }
6950
6974
  hasNoProps() {
6951
- if (this.usesRunes()) {
6975
+ if (this.isRunesMode()) {
6952
6976
  return !this.$props.type && !this.$props.comment;
6953
6977
  }
6954
6978
  const names = Array.from(this.exports.entries());
6955
6979
  return names.length === 0;
6956
6980
  }
6957
6981
  createBindingsStr() {
6958
- if (this.usesRunes()) {
6982
+ if (this.isRunesMode()) {
6959
6983
  // will be just the empty strings for zero bindings, which is impossible to create a binding for, so it works out fine
6960
6984
  return `__sveltets_$$bindings('${this.$props.bindings.join("', '")}')`;
6961
6985
  }
@@ -6970,17 +6994,17 @@ class ExportedNames {
6970
6994
  */
6971
6995
  createExportsStr() {
6972
6996
  const names = Array.from(this.exports.entries());
6973
- const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.usesRunes() && isNamedExport));
6974
- const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
6997
+ const others = names.filter(([, { isLet, isNamedExport }]) => !isLet || (this.isRunesMode() && isNamedExport));
6998
+ const needsAccessors = this.usesAccessors && names.length > 0 && !this.isRunesMode(); // runes mode doesn't support accessors
6975
6999
  if (this.isSvelte5Plus) {
6976
7000
  let str = '';
6977
- if (others.length > 0 || this.usesRunes() || needsAccessors) {
7001
+ if (others.length > 0 || this.isRunesMode() || needsAccessors) {
6978
7002
  const exports = needsAccessors ? names : others;
6979
7003
  if (others.length > 0 || needsAccessors) {
6980
7004
  if (this.isTsFile) {
6981
7005
  str +=
6982
7006
  // Reference imports that have a type, else they are marked as unused if nothing in the component references them
6983
- `, exports: {${this.createReturnElements(this.usesRunes() ? others : [], false, true)}} as any as { ` +
7007
+ `, exports: {${this.createReturnElements(this.isRunesMode() ? others : [], false, true)}} as any as { ` +
6984
7008
  this.createReturnElementsType(exports, undefined, true).join(',') +
6985
7009
  ' }';
6986
7010
  }
@@ -7023,7 +7047,7 @@ class ExportedNames {
7023
7047
  });
7024
7048
  }
7025
7049
  createOptionalPropsArray() {
7026
- if (this.usesRunes()) {
7050
+ if (this.isRunesMode()) {
7027
7051
  return [];
7028
7052
  }
7029
7053
  else {
@@ -7047,7 +7071,13 @@ class ExportedNames {
7047
7071
  this.hasRunesGlobals =
7048
7072
  this.isSvelte5Plus && globals.some((global) => runes.includes(global));
7049
7073
  }
7050
- usesRunes() {
7074
+ enterRunesMode() {
7075
+ this.isRunes = true;
7076
+ }
7077
+ /**
7078
+ * True if uses runes or top level await or await in template expressions
7079
+ */
7080
+ isRunesMode() {
7051
7081
  return this.hasRunesGlobals || this.hasPropsRune() || this.isRunes;
7052
7082
  }
7053
7083
  }
@@ -7202,8 +7232,9 @@ class Generics {
7202
7232
  * were used as stores are appended with `let $xx = __sveltets_2_store_get(xx)` to create the store variables.
7203
7233
  */
7204
7234
  class ImplicitStoreValues {
7205
- constructor(storesResolvedInTemplate = [], renderFunctionStart, storeFromImportsWrapper = (input) => input) {
7235
+ constructor(storesResolvedInTemplate = [], renderFunctionStart, isSvelte5Plus, storeFromImportsWrapper = (input) => input) {
7206
7236
  this.renderFunctionStart = renderFunctionStart;
7237
+ this.isSvelte5Plus = isSvelte5Plus;
7207
7238
  this.storeFromImportsWrapper = storeFromImportsWrapper;
7208
7239
  this.accessedStores = new Set();
7209
7240
  this.variableDeclarations = [];
@@ -7276,7 +7307,9 @@ class ImplicitStoreValues {
7276
7307
  }
7277
7308
  attachStoreValueDeclarationOfImportsToRenderFn(str) {
7278
7309
  const storeNames = this.importStatements
7279
- .filter(({ name }) => name && this.accessedStores.has(name.getText()))
7310
+ .filter((declaration) => declaration.name &&
7311
+ (!this.isSvelte5Plus || !this.isSvelteStoreDerivedImport(declaration)) &&
7312
+ this.accessedStores.has(declaration.name.getText()))
7280
7313
  .map(({ name }) => name.getText());
7281
7314
  if (!storeNames.length) {
7282
7315
  return;
@@ -7284,6 +7317,17 @@ class ImplicitStoreValues {
7284
7317
  const storeDeclarations = this.storeFromImportsWrapper(surroundWithIgnoreComments(this.createStoreDeclarations(storeNames)));
7285
7318
  str.appendRight(this.renderFunctionStart, storeDeclarations);
7286
7319
  }
7320
+ isSvelteStoreDerivedImport(declaration) {
7321
+ // named import of 'derived' from 'svelte/store'
7322
+ if (!ts.isImportSpecifier(declaration) || declaration.name.text !== 'derived') {
7323
+ return false;
7324
+ }
7325
+ const importDeclaration = declaration.parent.parent.parent;
7326
+ return (ts.isImportDeclaration(importDeclaration) &&
7327
+ importDeclaration.moduleSpecifier &&
7328
+ ts.isStringLiteral(importDeclaration.moduleSpecifier) &&
7329
+ importDeclaration.moduleSpecifier.text === 'svelte/store');
7330
+ }
7287
7331
  createStoreDeclarations(storeNames) {
7288
7332
  let declarations = '';
7289
7333
  for (let i = 0; i < storeNames.length; i++) {
@@ -7511,6 +7555,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7511
7555
  let uses$$restProps = false;
7512
7556
  let uses$$slots = false;
7513
7557
  let uses$$SlotsInterface = false;
7558
+ let hasTopLevelAwait = false;
7514
7559
  //track if we are in a declaration scope
7515
7560
  let isDeclaration = false;
7516
7561
  //track the variable declaration node
@@ -7699,6 +7744,10 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7699
7744
  }
7700
7745
  implicitTopLevelNames.handleReactiveStatement(node, binaryExpression);
7701
7746
  }
7747
+ // Check for top-level await expressions
7748
+ if (isSvelte5Plus && ts.isAwaitExpression(node) && scope === rootScope) {
7749
+ hasTopLevelAwait = true;
7750
+ }
7702
7751
  // Defensively call function (checking for undefined) because it got added only recently (TS 4.0)
7703
7752
  // and therefore might break people using older TS versions
7704
7753
  // Don't transform in ts mode because <type>value type assertions are valid in this case
@@ -7749,7 +7798,8 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
7749
7798
  uses$$restProps,
7750
7799
  uses$$slots,
7751
7800
  uses$$SlotsInterface,
7752
- generics
7801
+ generics,
7802
+ hasTopLevelAwait
7753
7803
  };
7754
7804
  }
7755
7805
  function transformInterfacesToTypes(tsAst, str, astOffset, movedNodes) {
@@ -7882,11 +7932,12 @@ function svelte2tsx(svelte, options = { parse }) {
7882
7932
  const renderFunctionStart = scriptTag
7883
7933
  ? str.original.lastIndexOf('>', scriptTag.content.start) + 1
7884
7934
  : instanceScriptTarget;
7885
- const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart);
7935
+ const implicitStoreValues = new ImplicitStoreValues(resolvedStores, renderFunctionStart, svelte5Plus);
7886
7936
  //move the instance script and process the content
7887
7937
  let exportedNames = new ExportedNames(str, 0, basename, isTsFile, svelte5Plus, isRunes);
7888
7938
  let generics = new Generics(str, 0, { attributes: [] });
7889
7939
  let uses$$SlotsInterface = false;
7940
+ let hasTopLevelAwait = false;
7890
7941
  if (scriptTag) {
7891
7942
  //ensure it is between the module script and the rest of the template (the variables need to be declared before the jsx template)
7892
7943
  if (scriptTag.start != instanceScriptTarget) {
@@ -7896,11 +7947,14 @@ function svelte2tsx(svelte, options = { parse }) {
7896
7947
  uses$$props = uses$$props || res.uses$$props;
7897
7948
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7898
7949
  uses$$slots = uses$$slots || res.uses$$slots;
7899
- ({ exportedNames, events, generics, uses$$SlotsInterface } = res);
7950
+ ({ exportedNames, events, generics, uses$$SlotsInterface, hasTopLevelAwait } = res);
7900
7951
  }
7901
7952
  exportedNames.usesAccessors = usesAccessors;
7902
7953
  if (svelte5Plus) {
7903
7954
  exportedNames.checkGlobalsForRunes(implicitStoreValues.getGlobals());
7955
+ if (hasTopLevelAwait) {
7956
+ exportedNames.enterRunesMode();
7957
+ }
7904
7958
  }
7905
7959
  //wrap the script tag and template content in a function returning the slot and exports
7906
7960
  createRenderFunction({
@@ -7915,13 +7969,14 @@ function svelte2tsx(svelte, options = { parse }) {
7915
7969
  uses$$slots,
7916
7970
  uses$$SlotsInterface,
7917
7971
  generics,
7972
+ hasTopLevelAwait,
7918
7973
  svelte5Plus,
7919
7974
  isTsFile,
7920
7975
  mode: options.mode
7921
7976
  });
7922
7977
  // we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items
7923
7978
  if (moduleScriptTag) {
7924
- processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`), moduleAst);
7979
+ processModuleScriptTag(str, moduleScriptTag, new ImplicitStoreValues(implicitStoreValues.getAccessedStores(), renderFunctionStart, svelte5Plus, scriptTag || options.mode === 'ts' ? undefined : (input) => `</>;${input}<>`), moduleAst);
7925
7980
  if (!scriptTag) {
7926
7981
  moduleAst.tsAst.forEachChild((node) => exportedNames.hoistableInterfaces.analyzeModuleScriptNode(node));
7927
7982
  }
@@ -7969,6 +8024,7 @@ function svelte2tsx(svelte, options = { parse }) {
7969
8024
  mode: options.mode,
7970
8025
  generics,
7971
8026
  isSvelte5: svelte5Plus,
8027
+ hasTopLevelAwait,
7972
8028
  noSvelteComponentTyped: options.noSvelteComponentTyped
7973
8029
  });
7974
8030
  if (options.mode === 'dts') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.7.39",
3
+ "version": "0.7.41",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "The Svelte Community",
6
6
  "license": "MIT",