svelte2tsx 0.7.12 → 0.7.14

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
@@ -1692,11 +1692,13 @@ transformations) {
1692
1692
  }
1693
1693
  let removeStart = start;
1694
1694
  const sortedMoves = [...moves].sort((t1, t2) => t1[0] - t2[0]);
1695
+ // Remove everything between the transformations up until the end position
1695
1696
  for (const transformation of sortedMoves) {
1696
1697
  if (removeStart < transformation[0]) {
1697
1698
  if (deletePos !== moves.length &&
1698
1699
  removeStart > deleteDest &&
1699
- !(removeStart < end && transformation[0] >= end)) {
1700
+ removeStart < end &&
1701
+ transformation[0] < end) {
1700
1702
  str.move(removeStart, transformation[0], end);
1701
1703
  }
1702
1704
  if (transformation[0] < end) {
@@ -1835,6 +1837,8 @@ var svgAttributes = 'accent-height accumulate additive alignment-baseline allowR
1835
1837
 
1836
1838
  const IGNORE_START_COMMENT = '/*Ωignore_startΩ*/';
1837
1839
  const IGNORE_END_COMMENT = '/*Ωignore_endΩ*/';
1840
+ /** to tell tooling to ignore the character at this position; can for example be used to ignore everything starting at this position */
1841
+ const IGNORE_POSITION_COMMENT = '/*Ωignore_positionΩ*/';
1838
1842
  /**
1839
1843
  * Surrounds given string with a start/end comment which marks it
1840
1844
  * to be ignored by tooling.
@@ -2160,6 +2164,7 @@ class InlineComponent {
2160
2164
  this.startEndTransformation = [];
2161
2165
  this.propsTransformation = [];
2162
2166
  this.eventsTransformation = [];
2167
+ this.snippetPropsTransformation = [];
2163
2168
  this.endTransformation = [];
2164
2169
  if (parent) {
2165
2170
  parent.child = this;
@@ -2247,6 +2252,10 @@ class InlineComponent {
2247
2252
  this.slotLetsTransformation = this.slotLetsTransformation || [['default'], []];
2248
2253
  this.slotLetsTransformation[1].push(...transformation, ',');
2249
2254
  }
2255
+ addImplicitSnippetProp(name, transforms) {
2256
+ this.addProp([name], transforms);
2257
+ this.snippetPropsTransformation.push(this.str.original.slice(name[0], name[1]));
2258
+ }
2250
2259
  /**
2251
2260
  * Add something right after the start tag end.
2252
2261
  */
@@ -2254,6 +2263,7 @@ class InlineComponent {
2254
2263
  this.startEndTransformation.push(...value);
2255
2264
  }
2256
2265
  performTransformation() {
2266
+ var _a;
2257
2267
  const namedSlotLetTransformation = [];
2258
2268
  const defaultSlotLetTransformation = [];
2259
2269
  if (this.slotLetsTransformation) {
@@ -2270,6 +2280,10 @@ class InlineComponent {
2270
2280
  }
2271
2281
  this.endTransformation.push('}');
2272
2282
  }
2283
+ const snippetPropVariables = (_a = this.snippetPropsTransformation) === null || _a === void 0 ? void 0 : _a.join(', ');
2284
+ const snippetPropVariablesDeclaration = snippetPropVariables
2285
+ ? surroundWithIgnoreComments(`const {${snippetPropVariables}} = ${this.name}.$$prop_def;`)
2286
+ : '';
2273
2287
  if (this.isSelfclosing) {
2274
2288
  this.endTransformation.push('}');
2275
2289
  transform(this.str, this.startTagStart, this.startTagEnd, this.startTagEnd, [
@@ -2282,6 +2296,7 @@ class InlineComponent {
2282
2296
  ...this.startEndTransformation,
2283
2297
  ...this.eventsTransformation,
2284
2298
  ...defaultSlotLetTransformation,
2299
+ snippetPropVariablesDeclaration,
2285
2300
  ...this.endTransformation
2286
2301
  ]);
2287
2302
  }
@@ -2301,6 +2316,7 @@ class InlineComponent {
2301
2316
  ...this.propsTransformation,
2302
2317
  ...this.startEndTransformation,
2303
2318
  ...this.eventsTransformation,
2319
+ snippetPropVariablesDeclaration,
2304
2320
  ...defaultSlotLetTransformation
2305
2321
  ]);
2306
2322
  transform(this.str, endStart, this.node.end, this.node.end, this.endTransformation);
@@ -3080,9 +3096,9 @@ function handleTransitionDirective(str, attr, element) {
3080
3096
  * ```
3081
3097
  * --> if standalone:
3082
3098
  * ```ts
3083
- * const foo = (bar) => {
3099
+ * const foo = (bar) => { async () => {
3084
3100
  * ..
3085
- * }
3101
+ * };return return __sveltets_2_any(0)};
3086
3102
  * ```
3087
3103
  * --> if slot prop:
3088
3104
  * ```ts
@@ -3092,22 +3108,32 @@ function handleTransitionDirective(str, attr, element) {
3092
3108
  * ```
3093
3109
  */
3094
3110
  function handleSnippet(str, snippetBlock, component) {
3095
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3111
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
3096
3112
  const isImplicitProp = component !== undefined;
3097
3113
  const endSnippet = str.original.lastIndexOf('{', snippetBlock.end - 1);
3098
- // Return something to silence the "snippet type not assignable to return type void" error
3099
- str.overwrite(endSnippet, snippetBlock.end, `};return __sveltets_2_any(0)}${isImplicitProp ? '' : ';'}`, {
3114
+ const afterSnippet = isImplicitProp
3115
+ ? `};return __sveltets_2_any(0)}`
3116
+ : `};return __sveltets_2_any(0)};`;
3117
+ str.overwrite(endSnippet, snippetBlock.end, afterSnippet, {
3100
3118
  contentOnly: true
3101
3119
  });
3102
3120
  const lastParameter = (_a = snippetBlock.parameters) === null || _a === void 0 ? void 0 : _a.at(-1);
3103
3121
  const startEnd = str.original.indexOf('}', (_d = (_c = (_b = lastParameter === null || lastParameter === void 0 ? void 0 : lastParameter.typeAnnotation) === null || _b === void 0 ? void 0 : _b.end) !== null && _c !== void 0 ? _c : lastParameter === null || lastParameter === void 0 ? void 0 : lastParameter.end) !== null && _d !== void 0 ? _d : snippetBlock.expression.end) + 1;
3122
+ let parameters;
3123
+ if ((_e = snippetBlock.parameters) === null || _e === void 0 ? void 0 : _e.length) {
3124
+ const firstParameter = snippetBlock.parameters[0];
3125
+ const start = (_h = (_g = (_f = firstParameter === null || firstParameter === void 0 ? void 0 : firstParameter.leadingComments) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.start) !== null && _h !== void 0 ? _h : firstParameter.start;
3126
+ const end = (_k = (_j = lastParameter.typeAnnotation) === null || _j === void 0 ? void 0 : _j.end) !== null && _k !== void 0 ? _k : lastParameter.end;
3127
+ parameters = [start, end];
3128
+ }
3129
+ // inner async function for potential #await blocks
3130
+ const afterParameters = ` => { async ()${IGNORE_POSITION_COMMENT} => {`;
3104
3131
  if (isImplicitProp) {
3105
3132
  str.overwrite(snippetBlock.start, snippetBlock.expression.start, '', { contentOnly: true });
3106
3133
  const transforms = ['('];
3107
- if ((_e = snippetBlock.parameters) === null || _e === void 0 ? void 0 : _e.length) {
3108
- const start = snippetBlock.parameters[0].start;
3109
- const end = (_g = (_f = lastParameter.typeAnnotation) === null || _f === void 0 ? void 0 : _f.end) !== null && _g !== void 0 ? _g : lastParameter.end;
3110
- transforms.push([start, end]);
3134
+ if (parameters) {
3135
+ transforms.push(parameters);
3136
+ const [start, end] = parameters;
3111
3137
  str.overwrite(snippetBlock.expression.end, start, '', {
3112
3138
  contentOnly: true
3113
3139
  });
@@ -3116,47 +3142,22 @@ function handleSnippet(str, snippetBlock, component) {
3116
3142
  else {
3117
3143
  str.overwrite(snippetBlock.expression.end, startEnd, '', { contentOnly: true });
3118
3144
  }
3119
- transforms.push(') => {async () => {'); // inner async function for potential #await blocks
3145
+ transforms.push(')' + afterParameters);
3120
3146
  transforms.push([startEnd, snippetBlock.end]);
3121
- component.addProp([[snippetBlock.expression.start, snippetBlock.expression.end]], transforms);
3147
+ component.addImplicitSnippetProp([snippetBlock.expression.start, snippetBlock.expression.end], transforms);
3122
3148
  }
3123
3149
  else {
3124
- let generic = '';
3125
- if ((_h = snippetBlock.parameters) === null || _h === void 0 ? void 0 : _h.length) {
3126
- generic = `<[${snippetBlock.parameters
3127
- .map((p) => {
3128
- var _a, _b;
3129
- let typeAnnotation = p.typeAnnotation;
3130
- if (!typeAnnotation && p.type === 'AssignmentPattern') {
3131
- typeAnnotation = (_a = p.left) === null || _a === void 0 ? void 0 : _a.typeAnnotation;
3132
- if (!typeAnnotation) {
3133
- typeAnnotation = (_b = p.right) === null || _b === void 0 ? void 0 : _b.typeAnnotation;
3134
- }
3135
- }
3136
- // fall back to `any` to silence "implicit any" errors; JSDoc people can't add types to snippets
3137
- let type = 'any';
3138
- if (typeAnnotation === null || typeAnnotation === void 0 ? void 0 : typeAnnotation.typeAnnotation) {
3139
- type = str.original.slice(typeAnnotation.typeAnnotation.start, typeAnnotation.typeAnnotation.end);
3140
- }
3141
- if (p.optional || p.type === 'AssignmentPattern') {
3142
- type += '?';
3143
- }
3144
- return type;
3145
- })
3146
- .join(', ')}]>`;
3147
- }
3148
- const typeAnnotation = surroundWithIgnoreComments(`: import('svelte').Snippet${generic}`);
3149
3150
  const transforms = [
3150
- 'var ',
3151
+ 'const ',
3151
3152
  [snippetBlock.expression.start, snippetBlock.expression.end],
3152
- typeAnnotation + ' = ('
3153
+ IGNORE_POSITION_COMMENT,
3154
+ ' = ('
3153
3155
  ];
3154
- if ((_j = snippetBlock.parameters) === null || _j === void 0 ? void 0 : _j.length) {
3155
- const start = snippetBlock.parameters[0].start;
3156
- const end = (_l = (_k = lastParameter.typeAnnotation) === null || _k === void 0 ? void 0 : _k.end) !== null && _l !== void 0 ? _l : lastParameter.end;
3157
- transforms.push([start, end]);
3156
+ if (parameters) {
3157
+ transforms.push(parameters);
3158
3158
  }
3159
- transforms.push(') => {async () => {'); // inner async function for potential #await blocks
3159
+ transforms.push(')', surroundWithIgnoreComments(`: ReturnType<import('svelte').Snippet>`), // shows up nicely preserved on hover, other alternatives don't
3160
+ afterParameters);
3160
3161
  transform(str, snippetBlock.start, startEnd, startEnd, transforms);
3161
3162
  }
3162
3163
  }
@@ -3180,7 +3181,9 @@ function handleImplicitChildren(componentNode, component) {
3180
3181
  continue;
3181
3182
  }
3182
3183
  }
3183
- if (child.type === 'Comment' || (child.type === 'Text' && child.data.trim() === '')) {
3184
+ if (child.type === 'Comment' ||
3185
+ child.type === 'Slot' ||
3186
+ (child.type === 'Text' && child.data.trim() === '')) {
3184
3187
  continue;
3185
3188
  }
3186
3189
  if (child.type !== 'SnippetBlock') {
@@ -3194,6 +3197,30 @@ function handleImplicitChildren(componentNode, component) {
3194
3197
  // it's enough to fake a children prop, we don't need to actually move the content inside (which would also reset control flow)
3195
3198
  component.addProp(['children'], ['() => { return __sveltets_2_any(0); }']);
3196
3199
  }
3200
+ function hoistSnippetBlock(str, blockOrEl) {
3201
+ var _a;
3202
+ if (blockOrEl.type === 'InlineComponent') {
3203
+ // implicit props, handled in InlineComponent
3204
+ return;
3205
+ }
3206
+ let targetPosition;
3207
+ for (const node of (_a = blockOrEl.children) !== null && _a !== void 0 ? _a : []) {
3208
+ if (node.type !== 'SnippetBlock') {
3209
+ if (targetPosition === undefined && (node.type !== 'Text' || node.data.trim() !== '')) {
3210
+ targetPosition = node.type === 'Text' ? node.end : node.start;
3211
+ }
3212
+ continue;
3213
+ }
3214
+ // already first
3215
+ if (targetPosition === undefined) {
3216
+ continue;
3217
+ }
3218
+ if (node.start === targetPosition) {
3219
+ continue;
3220
+ }
3221
+ str.move(node.start, node.end, targetPosition);
3222
+ }
3223
+ }
3197
3224
 
3198
3225
  /**
3199
3226
  * `{@render foo(x)}` --> `;foo(x);`
@@ -3223,6 +3250,7 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3223
3250
  stripDoctype(str);
3224
3251
  const rootSnippets = [];
3225
3252
  let element;
3253
+ const pendingSnippetHoistCheck = new Set();
3226
3254
  walk(ast, {
3227
3255
  enter: (estreeTypedNode, estreeTypedParent, prop, index) => {
3228
3256
  const node = estreeTypedNode;
@@ -3250,6 +3278,9 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3250
3278
  // root snippet -> move to instance script
3251
3279
  rootSnippets.push([node.start, node.end]);
3252
3280
  }
3281
+ else {
3282
+ pendingSnippetHoistCheck.add(parent);
3283
+ }
3253
3284
  break;
3254
3285
  case 'MustacheTag':
3255
3286
  handleMustacheTag(str, node, parent);
@@ -3381,6 +3412,9 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3381
3412
  }
3382
3413
  }
3383
3414
  });
3415
+ for (const node of pendingSnippetHoistCheck) {
3416
+ hoistSnippetBlock(str, node);
3417
+ }
3384
3418
  return rootSnippets;
3385
3419
  }
3386
3420
 
@@ -4948,22 +4982,31 @@ class ExportedNames {
4948
4982
  const names = Array.from(this.exports.entries());
4949
4983
  const others = names.filter(([, { isLet }]) => !isLet);
4950
4984
  const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
4951
- if (this.isSvelte5Plus && (others.length > 0 || this.usesRunes() || needsAccessors)) {
4985
+ if (this.isSvelte5Plus) {
4952
4986
  let str = '';
4953
- if (others.length > 0 || needsAccessors) {
4954
- if (this.isTsFile) {
4955
- str +=
4956
- ', exports: {} as any as { ' +
4957
- this.createReturnElementsType(needsAccessors ? names : others, undefined, true).join(',') +
4958
- ' }';
4987
+ if (others.length > 0 || this.usesRunes() || needsAccessors) {
4988
+ if (others.length > 0 || needsAccessors) {
4989
+ if (this.isTsFile) {
4990
+ str +=
4991
+ ', exports: {} as any as { ' +
4992
+ this.createReturnElementsType(needsAccessors ? names : others, undefined, true).join(',') +
4993
+ ' }';
4994
+ }
4995
+ else {
4996
+ str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
4997
+ }
4959
4998
  }
4960
4999
  else {
4961
- str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
5000
+ // Always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types.
5001
+ // Don't cast to `Record<string, never>` because that will break the union type we use elsewhere
5002
+ str += ', exports: {}';
4962
5003
  }
4963
- }
4964
- if (this.usesRunes()) {
4965
5004
  str += `, bindings: ${this.createBindingsStr()}`;
4966
5005
  }
5006
+ else {
5007
+ // always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types
5008
+ str += `, exports: {}, bindings: ${this.createBindingsStr()}`;
5009
+ }
4967
5010
  return str;
4968
5011
  }
4969
5012
  return '';
@@ -6921,7 +6964,30 @@ async function emitDts(config) {
6921
6964
  const { options, filenames } = loadTsconfig(config, svelteMap);
6922
6965
  const host = await createTsCompilerHost(options, svelteMap);
6923
6966
  const program = ts.createProgram(filenames, options, host);
6924
- program.emit();
6967
+ const result = program.emit();
6968
+ const likely_failed_files = result.diagnostics.filter((diagnostic) => {
6969
+ // List of errors which hint at a failed d.ts generation
6970
+ // https://github.com/microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json
6971
+ return diagnostic.code === 2527 || (diagnostic.code >= 4000 && diagnostic.code <= 4108);
6972
+ });
6973
+ if (likely_failed_files.length > 0) {
6974
+ const failed_by_file = new Map();
6975
+ likely_failed_files.forEach((diagnostic) => {
6976
+ var _a;
6977
+ const file = (_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.fileName;
6978
+ if (file) {
6979
+ const errors = failed_by_file.get(file) || [];
6980
+ errors.push(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
6981
+ failed_by_file.set(file, errors);
6982
+ }
6983
+ });
6984
+ console.warn('d.ts type declaration files for the following files were likely not generated due to the following errors:');
6985
+ console.warn([...failed_by_file.entries()]
6986
+ .map(([file, errors]) => {
6987
+ return `${file}\n${errors.map((error) => ` - ${error}`).join('\n')}`;
6988
+ })
6989
+ .join('\n'));
6990
+ }
6925
6991
  }
6926
6992
  function loadTsconfig(config, svelteMap) {
6927
6993
  var _a;
@@ -7031,16 +7097,16 @@ async function createTsCompilerHost(options, svelteMap) {
7031
7097
  fileName = pathPrefix ? path__namespace.join(pathPrefix, fileName) : fileName;
7032
7098
  if (fileName.endsWith('d.ts.map')) {
7033
7099
  data = data.replace(/"sources":\["(.+?)"\]/, (_, sourcePath) => {
7034
- // Due to our hack of treating .svelte files as .ts files, we need to adjust the extension
7035
- if (sourcePath.endsWith('.svelte.ts')) {
7036
- sourcePath = sourcePath.slice(0, -3);
7037
- }
7038
7100
  // The inverse of the pathPrefix adjustment
7039
7101
  sourcePath =
7040
7102
  pathPrefix && sourcePath.includes(pathPrefix)
7041
7103
  ? sourcePath.slice(0, sourcePath.indexOf(pathPrefix)) +
7042
7104
  sourcePath.slice(sourcePath.indexOf(pathPrefix) + pathPrefix.length + 1)
7043
7105
  : sourcePath;
7106
+ // Due to our hack of treating .svelte files as .ts files, we need to adjust the extension
7107
+ if (svelteMap.get(path__namespace.join(options.rootDir, toRealSvelteFilepath(sourcePath)))) {
7108
+ sourcePath = toRealSvelteFilepath(sourcePath);
7109
+ }
7044
7110
  return `"sources":["${sourcePath}"]`;
7045
7111
  });
7046
7112
  }
@@ -7109,10 +7175,13 @@ async function createSvelteMap(config) {
7109
7175
  version,
7110
7176
  noSvelteComponentTyped: noSvelteComponentTyped
7111
7177
  }).code;
7112
- svelteFiles.set(path, transformed);
7178
+ svelteFiles.set(path.replace(/\\/g, '/'), transformed);
7113
7179
  return isTsFile;
7114
7180
  }
7115
- return { add, get: (key) => svelteFiles.get(key) };
7181
+ return {
7182
+ add,
7183
+ get: (key) => svelteFiles.get(key.replace(/\\/g, '/'))
7184
+ };
7116
7185
  }
7117
7186
  function isSvelteFilepath(filePath) {
7118
7187
  return filePath.endsWith('.svelte');
package/index.mjs CHANGED
@@ -1672,11 +1672,13 @@ transformations) {
1672
1672
  }
1673
1673
  let removeStart = start;
1674
1674
  const sortedMoves = [...moves].sort((t1, t2) => t1[0] - t2[0]);
1675
+ // Remove everything between the transformations up until the end position
1675
1676
  for (const transformation of sortedMoves) {
1676
1677
  if (removeStart < transformation[0]) {
1677
1678
  if (deletePos !== moves.length &&
1678
1679
  removeStart > deleteDest &&
1679
- !(removeStart < end && transformation[0] >= end)) {
1680
+ removeStart < end &&
1681
+ transformation[0] < end) {
1680
1682
  str.move(removeStart, transformation[0], end);
1681
1683
  }
1682
1684
  if (transformation[0] < end) {
@@ -1815,6 +1817,8 @@ var svgAttributes = 'accent-height accumulate additive alignment-baseline allowR
1815
1817
 
1816
1818
  const IGNORE_START_COMMENT = '/*Ωignore_startΩ*/';
1817
1819
  const IGNORE_END_COMMENT = '/*Ωignore_endΩ*/';
1820
+ /** to tell tooling to ignore the character at this position; can for example be used to ignore everything starting at this position */
1821
+ const IGNORE_POSITION_COMMENT = '/*Ωignore_positionΩ*/';
1818
1822
  /**
1819
1823
  * Surrounds given string with a start/end comment which marks it
1820
1824
  * to be ignored by tooling.
@@ -2140,6 +2144,7 @@ class InlineComponent {
2140
2144
  this.startEndTransformation = [];
2141
2145
  this.propsTransformation = [];
2142
2146
  this.eventsTransformation = [];
2147
+ this.snippetPropsTransformation = [];
2143
2148
  this.endTransformation = [];
2144
2149
  if (parent) {
2145
2150
  parent.child = this;
@@ -2227,6 +2232,10 @@ class InlineComponent {
2227
2232
  this.slotLetsTransformation = this.slotLetsTransformation || [['default'], []];
2228
2233
  this.slotLetsTransformation[1].push(...transformation, ',');
2229
2234
  }
2235
+ addImplicitSnippetProp(name, transforms) {
2236
+ this.addProp([name], transforms);
2237
+ this.snippetPropsTransformation.push(this.str.original.slice(name[0], name[1]));
2238
+ }
2230
2239
  /**
2231
2240
  * Add something right after the start tag end.
2232
2241
  */
@@ -2234,6 +2243,7 @@ class InlineComponent {
2234
2243
  this.startEndTransformation.push(...value);
2235
2244
  }
2236
2245
  performTransformation() {
2246
+ var _a;
2237
2247
  const namedSlotLetTransformation = [];
2238
2248
  const defaultSlotLetTransformation = [];
2239
2249
  if (this.slotLetsTransformation) {
@@ -2250,6 +2260,10 @@ class InlineComponent {
2250
2260
  }
2251
2261
  this.endTransformation.push('}');
2252
2262
  }
2263
+ const snippetPropVariables = (_a = this.snippetPropsTransformation) === null || _a === void 0 ? void 0 : _a.join(', ');
2264
+ const snippetPropVariablesDeclaration = snippetPropVariables
2265
+ ? surroundWithIgnoreComments(`const {${snippetPropVariables}} = ${this.name}.$$prop_def;`)
2266
+ : '';
2253
2267
  if (this.isSelfclosing) {
2254
2268
  this.endTransformation.push('}');
2255
2269
  transform(this.str, this.startTagStart, this.startTagEnd, this.startTagEnd, [
@@ -2262,6 +2276,7 @@ class InlineComponent {
2262
2276
  ...this.startEndTransformation,
2263
2277
  ...this.eventsTransformation,
2264
2278
  ...defaultSlotLetTransformation,
2279
+ snippetPropVariablesDeclaration,
2265
2280
  ...this.endTransformation
2266
2281
  ]);
2267
2282
  }
@@ -2281,6 +2296,7 @@ class InlineComponent {
2281
2296
  ...this.propsTransformation,
2282
2297
  ...this.startEndTransformation,
2283
2298
  ...this.eventsTransformation,
2299
+ snippetPropVariablesDeclaration,
2284
2300
  ...defaultSlotLetTransformation
2285
2301
  ]);
2286
2302
  transform(this.str, endStart, this.node.end, this.node.end, this.endTransformation);
@@ -3060,9 +3076,9 @@ function handleTransitionDirective(str, attr, element) {
3060
3076
  * ```
3061
3077
  * --> if standalone:
3062
3078
  * ```ts
3063
- * const foo = (bar) => {
3079
+ * const foo = (bar) => { async () => {
3064
3080
  * ..
3065
- * }
3081
+ * };return return __sveltets_2_any(0)};
3066
3082
  * ```
3067
3083
  * --> if slot prop:
3068
3084
  * ```ts
@@ -3072,22 +3088,32 @@ function handleTransitionDirective(str, attr, element) {
3072
3088
  * ```
3073
3089
  */
3074
3090
  function handleSnippet(str, snippetBlock, component) {
3075
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3091
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
3076
3092
  const isImplicitProp = component !== undefined;
3077
3093
  const endSnippet = str.original.lastIndexOf('{', snippetBlock.end - 1);
3078
- // Return something to silence the "snippet type not assignable to return type void" error
3079
- str.overwrite(endSnippet, snippetBlock.end, `};return __sveltets_2_any(0)}${isImplicitProp ? '' : ';'}`, {
3094
+ const afterSnippet = isImplicitProp
3095
+ ? `};return __sveltets_2_any(0)}`
3096
+ : `};return __sveltets_2_any(0)};`;
3097
+ str.overwrite(endSnippet, snippetBlock.end, afterSnippet, {
3080
3098
  contentOnly: true
3081
3099
  });
3082
3100
  const lastParameter = (_a = snippetBlock.parameters) === null || _a === void 0 ? void 0 : _a.at(-1);
3083
3101
  const startEnd = str.original.indexOf('}', (_d = (_c = (_b = lastParameter === null || lastParameter === void 0 ? void 0 : lastParameter.typeAnnotation) === null || _b === void 0 ? void 0 : _b.end) !== null && _c !== void 0 ? _c : lastParameter === null || lastParameter === void 0 ? void 0 : lastParameter.end) !== null && _d !== void 0 ? _d : snippetBlock.expression.end) + 1;
3102
+ let parameters;
3103
+ if ((_e = snippetBlock.parameters) === null || _e === void 0 ? void 0 : _e.length) {
3104
+ const firstParameter = snippetBlock.parameters[0];
3105
+ const start = (_h = (_g = (_f = firstParameter === null || firstParameter === void 0 ? void 0 : firstParameter.leadingComments) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.start) !== null && _h !== void 0 ? _h : firstParameter.start;
3106
+ const end = (_k = (_j = lastParameter.typeAnnotation) === null || _j === void 0 ? void 0 : _j.end) !== null && _k !== void 0 ? _k : lastParameter.end;
3107
+ parameters = [start, end];
3108
+ }
3109
+ // inner async function for potential #await blocks
3110
+ const afterParameters = ` => { async ()${IGNORE_POSITION_COMMENT} => {`;
3084
3111
  if (isImplicitProp) {
3085
3112
  str.overwrite(snippetBlock.start, snippetBlock.expression.start, '', { contentOnly: true });
3086
3113
  const transforms = ['('];
3087
- if ((_e = snippetBlock.parameters) === null || _e === void 0 ? void 0 : _e.length) {
3088
- const start = snippetBlock.parameters[0].start;
3089
- const end = (_g = (_f = lastParameter.typeAnnotation) === null || _f === void 0 ? void 0 : _f.end) !== null && _g !== void 0 ? _g : lastParameter.end;
3090
- transforms.push([start, end]);
3114
+ if (parameters) {
3115
+ transforms.push(parameters);
3116
+ const [start, end] = parameters;
3091
3117
  str.overwrite(snippetBlock.expression.end, start, '', {
3092
3118
  contentOnly: true
3093
3119
  });
@@ -3096,47 +3122,22 @@ function handleSnippet(str, snippetBlock, component) {
3096
3122
  else {
3097
3123
  str.overwrite(snippetBlock.expression.end, startEnd, '', { contentOnly: true });
3098
3124
  }
3099
- transforms.push(') => {async () => {'); // inner async function for potential #await blocks
3125
+ transforms.push(')' + afterParameters);
3100
3126
  transforms.push([startEnd, snippetBlock.end]);
3101
- component.addProp([[snippetBlock.expression.start, snippetBlock.expression.end]], transforms);
3127
+ component.addImplicitSnippetProp([snippetBlock.expression.start, snippetBlock.expression.end], transforms);
3102
3128
  }
3103
3129
  else {
3104
- let generic = '';
3105
- if ((_h = snippetBlock.parameters) === null || _h === void 0 ? void 0 : _h.length) {
3106
- generic = `<[${snippetBlock.parameters
3107
- .map((p) => {
3108
- var _a, _b;
3109
- let typeAnnotation = p.typeAnnotation;
3110
- if (!typeAnnotation && p.type === 'AssignmentPattern') {
3111
- typeAnnotation = (_a = p.left) === null || _a === void 0 ? void 0 : _a.typeAnnotation;
3112
- if (!typeAnnotation) {
3113
- typeAnnotation = (_b = p.right) === null || _b === void 0 ? void 0 : _b.typeAnnotation;
3114
- }
3115
- }
3116
- // fall back to `any` to silence "implicit any" errors; JSDoc people can't add types to snippets
3117
- let type = 'any';
3118
- if (typeAnnotation === null || typeAnnotation === void 0 ? void 0 : typeAnnotation.typeAnnotation) {
3119
- type = str.original.slice(typeAnnotation.typeAnnotation.start, typeAnnotation.typeAnnotation.end);
3120
- }
3121
- if (p.optional || p.type === 'AssignmentPattern') {
3122
- type += '?';
3123
- }
3124
- return type;
3125
- })
3126
- .join(', ')}]>`;
3127
- }
3128
- const typeAnnotation = surroundWithIgnoreComments(`: import('svelte').Snippet${generic}`);
3129
3130
  const transforms = [
3130
- 'var ',
3131
+ 'const ',
3131
3132
  [snippetBlock.expression.start, snippetBlock.expression.end],
3132
- typeAnnotation + ' = ('
3133
+ IGNORE_POSITION_COMMENT,
3134
+ ' = ('
3133
3135
  ];
3134
- if ((_j = snippetBlock.parameters) === null || _j === void 0 ? void 0 : _j.length) {
3135
- const start = snippetBlock.parameters[0].start;
3136
- const end = (_l = (_k = lastParameter.typeAnnotation) === null || _k === void 0 ? void 0 : _k.end) !== null && _l !== void 0 ? _l : lastParameter.end;
3137
- transforms.push([start, end]);
3136
+ if (parameters) {
3137
+ transforms.push(parameters);
3138
3138
  }
3139
- transforms.push(') => {async () => {'); // inner async function for potential #await blocks
3139
+ transforms.push(')', surroundWithIgnoreComments(`: ReturnType<import('svelte').Snippet>`), // shows up nicely preserved on hover, other alternatives don't
3140
+ afterParameters);
3140
3141
  transform(str, snippetBlock.start, startEnd, startEnd, transforms);
3141
3142
  }
3142
3143
  }
@@ -3160,7 +3161,9 @@ function handleImplicitChildren(componentNode, component) {
3160
3161
  continue;
3161
3162
  }
3162
3163
  }
3163
- if (child.type === 'Comment' || (child.type === 'Text' && child.data.trim() === '')) {
3164
+ if (child.type === 'Comment' ||
3165
+ child.type === 'Slot' ||
3166
+ (child.type === 'Text' && child.data.trim() === '')) {
3164
3167
  continue;
3165
3168
  }
3166
3169
  if (child.type !== 'SnippetBlock') {
@@ -3174,6 +3177,30 @@ function handleImplicitChildren(componentNode, component) {
3174
3177
  // it's enough to fake a children prop, we don't need to actually move the content inside (which would also reset control flow)
3175
3178
  component.addProp(['children'], ['() => { return __sveltets_2_any(0); }']);
3176
3179
  }
3180
+ function hoistSnippetBlock(str, blockOrEl) {
3181
+ var _a;
3182
+ if (blockOrEl.type === 'InlineComponent') {
3183
+ // implicit props, handled in InlineComponent
3184
+ return;
3185
+ }
3186
+ let targetPosition;
3187
+ for (const node of (_a = blockOrEl.children) !== null && _a !== void 0 ? _a : []) {
3188
+ if (node.type !== 'SnippetBlock') {
3189
+ if (targetPosition === undefined && (node.type !== 'Text' || node.data.trim() !== '')) {
3190
+ targetPosition = node.type === 'Text' ? node.end : node.start;
3191
+ }
3192
+ continue;
3193
+ }
3194
+ // already first
3195
+ if (targetPosition === undefined) {
3196
+ continue;
3197
+ }
3198
+ if (node.start === targetPosition) {
3199
+ continue;
3200
+ }
3201
+ str.move(node.start, node.end, targetPosition);
3202
+ }
3203
+ }
3177
3204
 
3178
3205
  /**
3179
3206
  * `{@render foo(x)}` --> `;foo(x);`
@@ -3203,6 +3230,7 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3203
3230
  stripDoctype(str);
3204
3231
  const rootSnippets = [];
3205
3232
  let element;
3233
+ const pendingSnippetHoistCheck = new Set();
3206
3234
  walk(ast, {
3207
3235
  enter: (estreeTypedNode, estreeTypedParent, prop, index) => {
3208
3236
  const node = estreeTypedNode;
@@ -3230,6 +3258,9 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3230
3258
  // root snippet -> move to instance script
3231
3259
  rootSnippets.push([node.start, node.end]);
3232
3260
  }
3261
+ else {
3262
+ pendingSnippetHoistCheck.add(parent);
3263
+ }
3233
3264
  break;
3234
3265
  case 'MustacheTag':
3235
3266
  handleMustacheTag(str, node, parent);
@@ -3361,6 +3392,9 @@ function convertHtmlxToJsx(str, ast, onWalk = null, onLeave = null, options = {
3361
3392
  }
3362
3393
  }
3363
3394
  });
3395
+ for (const node of pendingSnippetHoistCheck) {
3396
+ hoistSnippetBlock(str, node);
3397
+ }
3364
3398
  return rootSnippets;
3365
3399
  }
3366
3400
 
@@ -4928,22 +4962,31 @@ class ExportedNames {
4928
4962
  const names = Array.from(this.exports.entries());
4929
4963
  const others = names.filter(([, { isLet }]) => !isLet);
4930
4964
  const needsAccessors = this.usesAccessors && names.length > 0 && !this.usesRunes(); // runes mode doesn't support accessors
4931
- if (this.isSvelte5Plus && (others.length > 0 || this.usesRunes() || needsAccessors)) {
4965
+ if (this.isSvelte5Plus) {
4932
4966
  let str = '';
4933
- if (others.length > 0 || needsAccessors) {
4934
- if (this.isTsFile) {
4935
- str +=
4936
- ', exports: {} as any as { ' +
4937
- this.createReturnElementsType(needsAccessors ? names : others, undefined, true).join(',') +
4938
- ' }';
4967
+ if (others.length > 0 || this.usesRunes() || needsAccessors) {
4968
+ if (others.length > 0 || needsAccessors) {
4969
+ if (this.isTsFile) {
4970
+ str +=
4971
+ ', exports: {} as any as { ' +
4972
+ this.createReturnElementsType(needsAccessors ? names : others, undefined, true).join(',') +
4973
+ ' }';
4974
+ }
4975
+ else {
4976
+ str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
4977
+ }
4939
4978
  }
4940
4979
  else {
4941
- str += `, exports: /** @type {{${this.createReturnElementsType(needsAccessors ? names : others, false, true)}}} */ ({})`;
4980
+ // Always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types.
4981
+ // Don't cast to `Record<string, never>` because that will break the union type we use elsewhere
4982
+ str += ', exports: {}';
4942
4983
  }
4943
- }
4944
- if (this.usesRunes()) {
4945
4984
  str += `, bindings: ${this.createBindingsStr()}`;
4946
4985
  }
4986
+ else {
4987
+ // always add that, in TS5.5+ the type for Exports is infered to never when this is not present, which breaks types
4988
+ str += `, exports: {}, bindings: ${this.createBindingsStr()}`;
4989
+ }
4947
4990
  return str;
4948
4991
  }
4949
4992
  return '';
@@ -6901,7 +6944,30 @@ async function emitDts(config) {
6901
6944
  const { options, filenames } = loadTsconfig(config, svelteMap);
6902
6945
  const host = await createTsCompilerHost(options, svelteMap);
6903
6946
  const program = ts.createProgram(filenames, options, host);
6904
- program.emit();
6947
+ const result = program.emit();
6948
+ const likely_failed_files = result.diagnostics.filter((diagnostic) => {
6949
+ // List of errors which hint at a failed d.ts generation
6950
+ // https://github.com/microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json
6951
+ return diagnostic.code === 2527 || (diagnostic.code >= 4000 && diagnostic.code <= 4108);
6952
+ });
6953
+ if (likely_failed_files.length > 0) {
6954
+ const failed_by_file = new Map();
6955
+ likely_failed_files.forEach((diagnostic) => {
6956
+ var _a;
6957
+ const file = (_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.fileName;
6958
+ if (file) {
6959
+ const errors = failed_by_file.get(file) || [];
6960
+ errors.push(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
6961
+ failed_by_file.set(file, errors);
6962
+ }
6963
+ });
6964
+ console.warn('d.ts type declaration files for the following files were likely not generated due to the following errors:');
6965
+ console.warn([...failed_by_file.entries()]
6966
+ .map(([file, errors]) => {
6967
+ return `${file}\n${errors.map((error) => ` - ${error}`).join('\n')}`;
6968
+ })
6969
+ .join('\n'));
6970
+ }
6905
6971
  }
6906
6972
  function loadTsconfig(config, svelteMap) {
6907
6973
  var _a;
@@ -7011,16 +7077,16 @@ async function createTsCompilerHost(options, svelteMap) {
7011
7077
  fileName = pathPrefix ? path.join(pathPrefix, fileName) : fileName;
7012
7078
  if (fileName.endsWith('d.ts.map')) {
7013
7079
  data = data.replace(/"sources":\["(.+?)"\]/, (_, sourcePath) => {
7014
- // Due to our hack of treating .svelte files as .ts files, we need to adjust the extension
7015
- if (sourcePath.endsWith('.svelte.ts')) {
7016
- sourcePath = sourcePath.slice(0, -3);
7017
- }
7018
7080
  // The inverse of the pathPrefix adjustment
7019
7081
  sourcePath =
7020
7082
  pathPrefix && sourcePath.includes(pathPrefix)
7021
7083
  ? sourcePath.slice(0, sourcePath.indexOf(pathPrefix)) +
7022
7084
  sourcePath.slice(sourcePath.indexOf(pathPrefix) + pathPrefix.length + 1)
7023
7085
  : sourcePath;
7086
+ // Due to our hack of treating .svelte files as .ts files, we need to adjust the extension
7087
+ if (svelteMap.get(path.join(options.rootDir, toRealSvelteFilepath(sourcePath)))) {
7088
+ sourcePath = toRealSvelteFilepath(sourcePath);
7089
+ }
7024
7090
  return `"sources":["${sourcePath}"]`;
7025
7091
  });
7026
7092
  }
@@ -7089,10 +7155,13 @@ async function createSvelteMap(config) {
7089
7155
  version,
7090
7156
  noSvelteComponentTyped: noSvelteComponentTyped
7091
7157
  }).code;
7092
- svelteFiles.set(path, transformed);
7158
+ svelteFiles.set(path.replace(/\\/g, '/'), transformed);
7093
7159
  return isTsFile;
7094
7160
  }
7095
- return { add, get: (key) => svelteFiles.get(key) };
7161
+ return {
7162
+ add,
7163
+ get: (key) => svelteFiles.get(key.replace(/\\/g, '/'))
7164
+ };
7096
7165
  }
7097
7166
  function isSvelteFilepath(filePath) {
7098
7167
  return filePath.endsWith('.svelte');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.7.12",
3
+ "version": "0.7.14",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "David Pershouse",
6
6
  "license": "MIT",
@@ -145,10 +145,6 @@ declare function __sveltets_2_cssProp(prop: Record<string, any>): {};
145
145
 
146
146
  // @ts-ignore Svelte v3/v4 don't have this
147
147
  declare function __sveltets_2_ensureSnippet(val: ReturnType<import('svelte').Snippet> | undefined | null): any;
148
- // @ts-ignore Svelte v3/v4 don't have this
149
- declare function __sveltets_2_snippet(): import('svelte').Snippet;
150
- // @ts-ignore Svelte v3/v4 don't have this
151
- declare function __sveltets_2_snippet<T>(t: T): import('svelte').Snippet<[T]>;
152
148
 
153
149
  /** @internal PRIVATE API, DO NOT USE */
154
150
  type __sveltets_2_SvelteAnimationReturnType = {