svelte2tsx 0.5.9 → 0.5.12

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
@@ -2096,7 +2096,7 @@ const oneWayBindingAttributes$1 = new Map(['clientWidth', 'clientHeight', 'offse
2096
2096
  * List of all binding names that are transformed to sth like `binding = variable`.
2097
2097
  * This applies to readonly bindings and the this binding.
2098
2098
  */
2099
- const assignmentBindings = new Set([...oneWayBindingAttributes$1.keys(), 'this']);
2099
+ new Set([...oneWayBindingAttributes$1.keys(), 'this']);
2100
2100
  /**
2101
2101
  * Transform bind:xxx into something that conforms to JSX
2102
2102
  */
@@ -2440,22 +2440,42 @@ function handleEventHandler$1(htmlx, str, attr, parent) {
2440
2440
  */
2441
2441
  function handleIf$1(htmlx, str, ifBlock, ifScope) {
2442
2442
  const endIf = htmlx.lastIndexOf('{', ifBlock.end - 1);
2443
+ const constTags = extractConstTags(ifBlock.children);
2444
+ const ifConditionEnd = htmlx.indexOf('}', ifBlock.expression.end) + 1;
2445
+ const hasConstTags = !!constTags.length;
2446
+ const endIIFE = createEndIIFE(hasConstTags);
2447
+ const startIIFE = createStartIIFE(hasConstTags);
2448
+ if (hasConstTags) {
2449
+ // {@const hi = exp} <div>{hi}> -> {(() => { const hi = exp; return <> <div>{hi}<div></> })}
2450
+ constTags.forEach((constTag) => {
2451
+ constTag(ifConditionEnd, str);
2452
+ });
2453
+ str.appendRight(ifConditionEnd, 'return <>');
2454
+ if (ifBlock.else) {
2455
+ // {:else} -> </>})()}</> : <>
2456
+ const elseWord = htmlx.lastIndexOf(':else', ifBlock.else.start);
2457
+ const elseStart = htmlx.lastIndexOf('{', elseWord);
2458
+ str.appendLeft(elseStart, endIIFE);
2459
+ }
2460
+ }
2443
2461
  if (ifBlock.elseif) {
2444
2462
  // {:else if expr} -> : (expr) ? <>
2463
+ // {:else if expr}{@const ...} -> : (expr) ? <>{(() => {const ...; return <>
2445
2464
  const elseIfStart = htmlx.lastIndexOf('{', ifBlock.expression.start);
2446
- const elseIfConditionEnd = htmlx.indexOf('}', ifBlock.expression.end) + 1;
2447
- str.overwrite(elseIfStart, ifBlock.expression.start, '</> : (', { contentOnly: true });
2448
- str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), elseIfConditionEnd, ') ? <>');
2465
+ str.overwrite(elseIfStart, ifBlock.expression.start, '</> : (', {
2466
+ contentOnly: true
2467
+ });
2468
+ str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), ifConditionEnd, ') ? <>' + startIIFE);
2449
2469
  ifScope.addElseIf(ifBlock.expression, str);
2450
2470
  if (!ifBlock.else) {
2451
- str.appendLeft(endIf, '</> : <>');
2471
+ str.appendLeft(endIf, endIIFE + '</> : <>');
2452
2472
  }
2453
2473
  return;
2454
2474
  }
2455
2475
  // {#if expr} -> {(expr) ? <>
2476
+ // {#if expr}{@const ...} -> {(expr) ? <>{(() => {const ...; return <>
2456
2477
  str.overwrite(ifBlock.start, ifBlock.expression.start, '{(', { contentOnly: true });
2457
- const end = htmlx.indexOf('}', ifBlock.expression.end);
2458
- str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), end + 1, ') ? <>', { contentOnly: true });
2478
+ str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), ifConditionEnd, ') ? <>' + startIIFE, { contentOnly: true });
2459
2479
  ifScope.addNestedIf(ifBlock.expression, str);
2460
2480
  if (ifBlock.else) {
2461
2481
  // {/if} -> </> }
@@ -2463,11 +2483,21 @@ function handleIf$1(htmlx, str, ifBlock, ifScope) {
2463
2483
  }
2464
2484
  else {
2465
2485
  // {/if} -> </> : <></>}
2466
- str.overwrite(endIf, ifBlock.end, '</> : <></>}', { contentOnly: true });
2486
+ // {@const ...} -> </>})()}</> : <></>}
2487
+ str.overwrite(endIf, ifBlock.end, endIIFE + '</> : <></>}', {
2488
+ contentOnly: true
2489
+ });
2467
2490
  }
2468
2491
  }
2492
+ function createStartIIFE(hasConstTags) {
2493
+ return hasConstTags ? '{(() => {' : '';
2494
+ }
2495
+ function createEndIIFE(hasConstTags) {
2496
+ return hasConstTags ? '</>})()}' : '';
2497
+ }
2469
2498
  /**
2470
2499
  * {:else} ---> </> : <>
2500
+ * {:else} {@const ...} -> </> : <>{(() => { const ...; return<>
2471
2501
  */
2472
2502
  function handleElse$1(htmlx, str, elseBlock, parent, ifScope) {
2473
2503
  var _a, _b;
@@ -2478,8 +2508,18 @@ function handleElse$1(htmlx, str, elseBlock, parent, ifScope) {
2478
2508
  const elseEnd = htmlx.lastIndexOf('}', elseBlock.start);
2479
2509
  const elseword = htmlx.lastIndexOf(':else', elseEnd);
2480
2510
  const elseStart = htmlx.lastIndexOf('{', elseword);
2481
- str.overwrite(elseStart, elseEnd + 1, '</> : <>');
2511
+ const constTags = extractConstTags(elseBlock.children);
2512
+ const hasConstTags = !!constTags.length;
2513
+ str.overwrite(elseStart, elseEnd + 1, '</> : <>' + createStartIIFE(hasConstTags));
2482
2514
  ifScope.addElse();
2515
+ if (!hasConstTags) {
2516
+ return;
2517
+ }
2518
+ constTags.forEach((constTag) => {
2519
+ constTag(elseEnd + 1, str);
2520
+ });
2521
+ str.appendRight(elseEnd + 1, 'return <>');
2522
+ str.appendLeft(elseBlock.end, createEndIIFE(true));
2483
2523
  }
2484
2524
 
2485
2525
  var IfType;
@@ -3455,8 +3495,8 @@ class Element {
3455
3495
  // remove the colon: svelte:xxx -> sveltexxx
3456
3496
  const nodeName = `svelte${this.node.name.substring(7)}`;
3457
3497
  this._name = '$$_' + nodeName + this.computeDepth();
3458
- this.startTransformation.push(`{ ${createElement}("${nodeName}", {`);
3459
- this.addNameConstDeclaration = () => (this.startTransformation[0] = `{ const ${this._name} = ${createElement}("${nodeName}", {`);
3498
+ this.startTransformation.push(`{ ${createElement}("${this.node.name}", {`);
3499
+ this.addNameConstDeclaration = () => (this.startTransformation[0] = `{ const ${this._name} = ${createElement}("${this.node.name}", {`);
3460
3500
  break;
3461
3501
  }
3462
3502
  case 'svelte:element': {
@@ -3925,7 +3965,7 @@ function handleAttribute(str, attr, parent, preserveCase, element) {
3925
3965
  return;
3926
3966
  }
3927
3967
  if (attr.value.length == 0) {
3928
- // attr=""
3968
+ // shouldn't happen
3929
3969
  addAttribute(attributeName, ['""']);
3930
3970
  return;
3931
3971
  }
@@ -3933,6 +3973,11 @@ function handleAttribute(str, attr, parent, preserveCase, element) {
3933
3973
  if (attr.value.length == 1) {
3934
3974
  const attrVal = attr.value[0];
3935
3975
  if (attrVal.type == 'Text') {
3976
+ // Handle the attr="" special case with a transformation that allows mapping of the position
3977
+ if (attrVal.start === attrVal.end) {
3978
+ addAttribute(attributeName, [[attrVal.start - 1, attrVal.end + 1]]);
3979
+ return;
3980
+ }
3936
3981
  const hasBrackets = str.original.lastIndexOf('}', attrVal.end) === attrVal.end - 1 ||
3937
3982
  str.original.lastIndexOf('}"', attrVal.end) === attrVal.end - 1 ||
3938
3983
  str.original.lastIndexOf("}'", attrVal.end) === attrVal.end - 1;
@@ -4813,22 +4858,6 @@ function getNamesFromLabeledStatement(node) {
4813
4858
  // svelte won't let you create a variable with $ prefix (reserved for stores)
4814
4859
  .filter((name) => !name.startsWith('$')));
4815
4860
  }
4816
- function isSafeToPrefixWithSemicolon(node) {
4817
- let parent = node.parent;
4818
- while (parent && !ts__default['default'].isExpressionStatement(parent)) {
4819
- parent = parent.parent;
4820
- }
4821
- if (!parent) {
4822
- return false;
4823
- }
4824
- return (parent.getStart() === node.getStart() &&
4825
- !(parent.parent &&
4826
- (ts__default['default'].isIfStatement(parent.parent) ||
4827
- ts__default['default'].isForStatement(parent.parent) ||
4828
- ts__default['default'].isForInStatement(parent.parent) ||
4829
- ts__default['default'].isForOfStatement(parent.parent) ||
4830
- ts__default['default'].isWhileStatement(parent.parent))));
4831
- }
4832
4861
 
4833
4862
  function is$$EventsDeclaration(node) {
4834
4863
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Events';
@@ -5933,72 +5962,12 @@ function getSingleSlotDef(componentNode, slotName) {
5933
5962
  return `__sveltets_1_instanceOf(${componentType}).$$slot_def['${slotName}']`;
5934
5963
  }
5935
5964
 
5936
- function handleStore(node, parent, str) {
5937
- const storename = node.name.slice(1);
5938
- //handle assign to
5939
- if (parent.type == 'AssignmentExpression' && parent.left == node && parent.operator == '=') {
5940
- const dollar = str.original.indexOf('$', node.start);
5941
- str.remove(dollar, dollar + 1);
5942
- str.overwrite(node.end, str.original.indexOf('=', node.end) + 1, '.set(');
5943
- str.appendLeft(parent.end, ')');
5944
- return;
5945
- }
5946
- // handle Assignment operators ($store +=, -=, *=, /=, %=, **=, etc.)
5947
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
5948
- const operators = ['+=', '-=', '*=', '/=', '%=', '**=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
5949
- if (parent.type == 'AssignmentExpression' &&
5950
- parent.left == node &&
5951
- operators.includes(parent.operator)) {
5952
- const storename = node.name.slice(1); // drop the $
5953
- const operator = parent.operator.substring(0, parent.operator.length - 1); // drop the = sign
5954
- str.overwrite(parent.start, str.original.indexOf('=', node.end) + 1, `${storename}.set( $${storename} ${operator}`);
5955
- str.appendLeft(parent.end, ')');
5956
- return;
5957
- }
5958
- // handle $store++, $store--, ++$store, --$store
5959
- if (parent.type == 'UpdateExpression') {
5960
- let simpleOperator;
5961
- if (parent.operator === '++') {
5962
- simpleOperator = '+';
5963
- }
5964
- if (parent.operator === '--') {
5965
- simpleOperator = '-';
5966
- }
5967
- if (simpleOperator) {
5968
- const storename = node.name.slice(1); // drop the $
5969
- str.overwrite(parent.start, parent.end, `(${storename}.set( $${storename} ${simpleOperator} 1), $${storename})`);
5970
- }
5971
- else {
5972
- console.warn(`Warning - unrecognized UpdateExpression operator ${parent.operator}!
5973
- This is an edge case unaccounted for in svelte2tsx, please file an issue:
5974
- https://github.com/sveltejs/language-tools/issues/new/choose
5975
- `, str.original.slice(parent.start, parent.end));
5976
- }
5977
- return;
5978
- }
5979
- const dollar = str.original.indexOf('$', node.start);
5980
- // handle bindings which are transformed to assignments. These need special treatment because
5981
- // `(__sveltets_1_store_get(foo), foo$) = something` is syntactically invalid
5982
- // Therefore remove the outer commas. Note: This relies on the binding expression wrapping
5983
- // this statement with __sveltets_1_empty
5984
- if (parent.type === 'Binding' && assignmentBindings.has(parent.name)) {
5985
- str.overwrite(dollar, dollar + 1, '__sveltets_1_store_get(', { contentOnly: true });
5986
- str.prependLeft(node.end, `), $${storename}`);
5987
- return;
5988
- }
5989
- // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
5990
- // - in order to get ts errors if store is not assignable to SvelteStore
5991
- // - use $store variable defined above to get ts flow control
5992
- str.overwrite(dollar, dollar + 1, '(__sveltets_1_store_get(', { contentOnly: true });
5993
- str.prependLeft(node.end, `), $${storename})`);
5994
- }
5995
5965
  const reservedNames = new Set(['$$props', '$$restProps', '$$slots']);
5996
5966
  class Stores {
5997
- constructor(scope, str, isDeclaration) {
5967
+ constructor(scope, isDeclaration) {
5998
5968
  this.scope = scope;
5999
- this.str = str;
6000
5969
  this.isDeclaration = isDeclaration;
6001
- this.pendingStoreResolutions = [];
5970
+ this.possibleStores = [];
6002
5971
  }
6003
5972
  handleDirective(node, str) {
6004
5973
  if (this.notAStore(node.name) || this.isDeclaration.value) {
@@ -6006,7 +5975,7 @@ class Stores {
6006
5975
  }
6007
5976
  const start = str.original.indexOf('$', node.start);
6008
5977
  const end = start + node.name.length;
6009
- this.pendingStoreResolutions.push({
5978
+ this.possibleStores.push({
6010
5979
  node: { type: 'Identifier', start, end, name: node.name },
6011
5980
  parent: { start: 0, end: 0, type: '' },
6012
5981
  scope: this.scope.current
@@ -6030,18 +5999,17 @@ class Stores {
6030
5999
  if (isObjectKey(parent, prop)) {
6031
6000
  return;
6032
6001
  }
6033
- this.pendingStoreResolutions.push({ node, parent, scope: this.scope.current });
6002
+ this.possibleStores.push({ node, parent, scope: this.scope.current });
6034
6003
  }
6035
6004
  }
6036
- resolveStores() {
6037
- const unresolvedStores = this.pendingStoreResolutions.filter(({ node, scope }) => {
6005
+ getStoreNames() {
6006
+ const stores = this.possibleStores.filter(({ node, scope }) => {
6038
6007
  const name = node.name;
6039
6008
  // if variable starting with '$' was manually declared by the user,
6040
6009
  // this isn't a store access.
6041
6010
  return !scope.hasDefined(name);
6042
6011
  });
6043
- unresolvedStores.forEach(({ node, parent }) => handleStore(node, parent, this.str));
6044
- return unresolvedStores.map(({ node }) => node.name.slice(1));
6012
+ return stores.map(({ node }) => node.name.slice(1));
6045
6013
  }
6046
6014
  notAStore(name) {
6047
6015
  return name[0] !== '$' || reservedNames.has(name);
@@ -6332,9 +6300,15 @@ class Generics {
6332
6300
  /**
6333
6301
  * move imports to top of script so they appear outside our render function
6334
6302
  */
6335
- function handleImportDeclaration(node, str, astOffset, scriptStart) {
6303
+ function handleImportDeclaration(node, str, astOffset, scriptStart, sourceFile) {
6336
6304
  var _a;
6305
+ const scanner = ts__default['default'].createScanner(sourceFile.languageVersion,
6306
+ /*skipTrivia*/ false, sourceFile.languageVariant);
6337
6307
  const comments = (_a = ts__default['default'].getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
6308
+ if (!comments.some((comment) => comment.hasTrailingNewLine) &&
6309
+ isNewGroup(sourceFile, node, scanner)) {
6310
+ str.appendRight(node.getStart() + astOffset, '\n');
6311
+ }
6338
6312
  for (const comment of comments) {
6339
6313
  const commentEnd = node.pos + comment.end + astOffset;
6340
6314
  str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
@@ -6347,8 +6321,27 @@ function handleImportDeclaration(node, str, astOffset, scriptStart) {
6347
6321
  const originalEndChar = str.original[node.end + astOffset - 1];
6348
6322
  str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
6349
6323
  }
6324
+ /**
6325
+ * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
6326
+ */
6327
+ function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
6328
+ const startPos = topLevelImportDecl.getFullStart();
6329
+ const endPos = topLevelImportDecl.getStart();
6330
+ scanner.setText(sourceFile.text, startPos, endPos - startPos);
6331
+ let numberOfNewLines = 0;
6332
+ while (scanner.getTokenPos() < endPos) {
6333
+ const tokenKind = scanner.scan();
6334
+ if (tokenKind === ts__default['default'].SyntaxKind.NewLineTrivia) {
6335
+ numberOfNewLines++;
6336
+ if (numberOfNewLines >= 2) {
6337
+ return true;
6338
+ }
6339
+ }
6340
+ }
6341
+ return false;
6342
+ }
6350
6343
 
6351
- function processInstanceScriptContent(str, script, events, implicitStoreValues, mode) {
6344
+ function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript) {
6352
6345
  const htmlx = str.original;
6353
6346
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6354
6347
  const tsAst = ts__namespace.createSourceFile('component.ts.svelte', scriptContent, ts__namespace.ScriptTarget.Latest, true, ts__namespace.ScriptKind.TS);
@@ -6369,95 +6362,8 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6369
6362
  const rootScope = scope;
6370
6363
  const pushScope = () => (scope = new Scope(scope));
6371
6364
  const popScope = () => (scope = scope.parent);
6372
- const handleStore = (ident, parent) => {
6373
- // ignore "typeof $store"
6374
- if (parent && parent.kind === ts__namespace.SyntaxKind.TypeQuery) {
6375
- return;
6376
- }
6377
- // ignore break
6378
- if (parent && parent.kind === ts__namespace.SyntaxKind.BreakStatement) {
6379
- return;
6380
- }
6381
- const storename = ident.getText().slice(1); // drop the $
6382
- // handle assign to
6383
- if (parent &&
6384
- ts__namespace.isBinaryExpression(parent) &&
6385
- parent.operatorToken.kind == ts__namespace.SyntaxKind.EqualsToken &&
6386
- parent.left == ident) {
6387
- //remove $
6388
- const dollar = str.original.indexOf('$', ident.getStart() + astOffset);
6389
- str.remove(dollar, dollar + 1);
6390
- // replace = with .set(
6391
- str.overwrite(ident.end + astOffset, parent.operatorToken.end + astOffset, '.set(');
6392
- // append )
6393
- str.appendLeft(parent.end + astOffset, ')');
6394
- return;
6395
- }
6396
- // handle Assignment operators ($store +=, -=, *=, /=, %=, **=, etc.)
6397
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
6398
- const operators = {
6399
- [ts__namespace.SyntaxKind.PlusEqualsToken]: '+',
6400
- [ts__namespace.SyntaxKind.MinusEqualsToken]: '-',
6401
- [ts__namespace.SyntaxKind.AsteriskEqualsToken]: '*',
6402
- [ts__namespace.SyntaxKind.SlashEqualsToken]: '/',
6403
- [ts__namespace.SyntaxKind.PercentEqualsToken]: '%',
6404
- [ts__namespace.SyntaxKind.AsteriskAsteriskEqualsToken]: '**',
6405
- [ts__namespace.SyntaxKind.LessThanLessThanEqualsToken]: '<<',
6406
- [ts__namespace.SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>',
6407
- [ts__namespace.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>',
6408
- [ts__namespace.SyntaxKind.AmpersandEqualsToken]: '&',
6409
- [ts__namespace.SyntaxKind.CaretEqualsToken]: '^',
6410
- [ts__namespace.SyntaxKind.BarEqualsToken]: '|'
6411
- };
6412
- if (ts__namespace.isBinaryExpression(parent) &&
6413
- parent.left == ident &&
6414
- Object.keys(operators).find((x) => x === String(parent.operatorToken.kind))) {
6415
- const operator = operators[parent.operatorToken.kind];
6416
- str.overwrite(parent.getStart() + astOffset, str.original.indexOf('=', ident.end + astOffset) + 1, `${storename}.set( $${storename} ${operator}`);
6417
- str.appendLeft(parent.end + astOffset, ')');
6418
- return;
6419
- }
6420
- // handle $store++, $store--, ++$store, --$store
6421
- if ((ts__namespace.isPrefixUnaryExpression(parent) || ts__namespace.isPostfixUnaryExpression(parent)) &&
6422
- ![
6423
- ts__namespace.SyntaxKind.ExclamationToken,
6424
- ts__namespace.SyntaxKind.PlusToken,
6425
- ts__namespace.SyntaxKind.MinusToken,
6426
- ts__namespace.SyntaxKind.TildeToken // ~$store
6427
- ].includes(parent.operator) /* `!$store` etc does not need processing */) {
6428
- let simpleOperator;
6429
- if (parent.operator === ts__namespace.SyntaxKind.PlusPlusToken) {
6430
- simpleOperator = '+';
6431
- }
6432
- if (parent.operator === ts__namespace.SyntaxKind.MinusMinusToken) {
6433
- simpleOperator = '-';
6434
- }
6435
- if (simpleOperator) {
6436
- str.overwrite(parent.getStart() + astOffset, parent.end + astOffset, `(${storename}.set( $${storename} ${simpleOperator} 1), $${storename})`);
6437
- return;
6438
- }
6439
- else {
6440
- console.warn(`Warning - unrecognized UnaryExpression operator ${parent.operator}!
6441
- This is an edge case unaccounted for in svelte2tsx, please file an issue:
6442
- https://github.com/sveltejs/language-tools/issues/new/choose
6443
- `, parent.getText());
6444
- }
6445
- }
6446
- // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
6447
- // - in order to get ts errors if store is not assignable to SvelteStore
6448
- // - use $store variable defined above to get ts flow control
6449
- const dollar = str.original.indexOf('$', ident.getStart() + astOffset);
6450
- const getPrefix = isSafeToPrefixWithSemicolon(ident)
6451
- ? ';'
6452
- : ts__namespace.isShorthandPropertyAssignment(parent)
6453
- ? // { $store } --> { $store: __sveltets_1_store_get(..)}
6454
- ident.text + ': '
6455
- : '';
6456
- str.overwrite(dollar, dollar + 1, getPrefix + '(__sveltets_1_store_get(');
6457
- str.prependLeft(ident.end + astOffset, `), $${storename})`);
6458
- };
6459
6365
  const resolveStore = (pending) => {
6460
- let { node, parent, scope } = pending;
6366
+ let { node, scope } = pending;
6461
6367
  const name = node.text;
6462
6368
  while (scope) {
6463
6369
  if (scope.declared.has(name)) {
@@ -6466,8 +6372,6 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6466
6372
  }
6467
6373
  scope = scope.parent;
6468
6374
  }
6469
- //We haven't been resolved, we must be a store read/write, handle it.
6470
- handleStore(node, parent);
6471
6375
  const storename = node.getText().slice(1);
6472
6376
  implicitStoreValues.addStoreAcess(storename);
6473
6377
  };
@@ -6544,7 +6448,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6544
6448
  exportedNames.handleExportDeclaration(node);
6545
6449
  }
6546
6450
  if (ts__namespace.isImportDeclaration(node)) {
6547
- handleImportDeclaration(node, str, astOffset, script.start);
6451
+ handleImportDeclaration(node, str, astOffset, script.start, tsAst);
6548
6452
  // Check if import is the event dispatcher
6549
6453
  events.checkIfImportIsEventDispatcher(node);
6550
6454
  }
@@ -6617,7 +6521,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6617
6521
  .filter(ts__namespace.isImportDeclaration)
6618
6522
  .sort((a, b) => a.end - b.end)[0];
6619
6523
  if (firstImport) {
6620
- str.appendRight(firstImport.getStart() + astOffset, '\n');
6524
+ // ensure it's in a newline.
6525
+ // if file has module script ensure an empty line to separate imports
6526
+ str.appendRight(firstImport.getStart() + astOffset, '\n' + (hasModuleScript ? '\n' : ''));
6621
6527
  }
6622
6528
  if (mode === 'dts') {
6623
6529
  // Transform interface declarations to type declarations because indirectly
@@ -6941,7 +6847,7 @@ function processSvelteTemplate(str, options) {
6941
6847
  //track $store variables since we are only supposed to give top level scopes special treatment, and users can declare $blah variables at higher scopes
6942
6848
  //which prevents us just changing all instances of Identity that start with $
6943
6849
  const scopeStack = new ScopeStack();
6944
- const stores = new Stores(scopeStack, str, isDeclaration);
6850
+ const stores = new Stores(scopeStack, isDeclaration);
6945
6851
  const scripts = new Scripts(htmlxAst);
6946
6852
  const handleSvelteOptions = (node) => {
6947
6853
  for (let i = 0; i < node.attributes.length; i++) {
@@ -7128,7 +7034,7 @@ function processSvelteTemplate(str, options) {
7128
7034
  const { scriptTag, moduleScriptTag } = scripts.getTopLevelScriptTags();
7129
7035
  scripts.blankOtherScriptTags(str);
7130
7036
  //resolve stores
7131
- const resolvedStores = stores.resolveStores();
7037
+ const resolvedStores = stores.getStoreNames();
7132
7038
  return {
7133
7039
  htmlAst: htmlxAst,
7134
7040
  moduleScriptTag,
@@ -7178,7 +7084,8 @@ function svelte2tsx(svelte, options = {}) {
7178
7084
  if (scriptTag.start != instanceScriptTarget) {
7179
7085
  str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
7180
7086
  }
7181
- const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode);
7087
+ const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
7088
+ /**hasModuleScripts */ !!moduleScriptTag);
7182
7089
  uses$$props = uses$$props || res.uses$$props;
7183
7090
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7184
7091
  uses$$slots = uses$$slots || res.uses$$slots;
package/index.mjs CHANGED
@@ -2066,7 +2066,7 @@ const oneWayBindingAttributes$1 = new Map(['clientWidth', 'clientHeight', 'offse
2066
2066
  * List of all binding names that are transformed to sth like `binding = variable`.
2067
2067
  * This applies to readonly bindings and the this binding.
2068
2068
  */
2069
- const assignmentBindings = new Set([...oneWayBindingAttributes$1.keys(), 'this']);
2069
+ new Set([...oneWayBindingAttributes$1.keys(), 'this']);
2070
2070
  /**
2071
2071
  * Transform bind:xxx into something that conforms to JSX
2072
2072
  */
@@ -2410,22 +2410,42 @@ function handleEventHandler$1(htmlx, str, attr, parent) {
2410
2410
  */
2411
2411
  function handleIf$1(htmlx, str, ifBlock, ifScope) {
2412
2412
  const endIf = htmlx.lastIndexOf('{', ifBlock.end - 1);
2413
+ const constTags = extractConstTags(ifBlock.children);
2414
+ const ifConditionEnd = htmlx.indexOf('}', ifBlock.expression.end) + 1;
2415
+ const hasConstTags = !!constTags.length;
2416
+ const endIIFE = createEndIIFE(hasConstTags);
2417
+ const startIIFE = createStartIIFE(hasConstTags);
2418
+ if (hasConstTags) {
2419
+ // {@const hi = exp} <div>{hi}> -> {(() => { const hi = exp; return <> <div>{hi}<div></> })}
2420
+ constTags.forEach((constTag) => {
2421
+ constTag(ifConditionEnd, str);
2422
+ });
2423
+ str.appendRight(ifConditionEnd, 'return <>');
2424
+ if (ifBlock.else) {
2425
+ // {:else} -> </>})()}</> : <>
2426
+ const elseWord = htmlx.lastIndexOf(':else', ifBlock.else.start);
2427
+ const elseStart = htmlx.lastIndexOf('{', elseWord);
2428
+ str.appendLeft(elseStart, endIIFE);
2429
+ }
2430
+ }
2413
2431
  if (ifBlock.elseif) {
2414
2432
  // {:else if expr} -> : (expr) ? <>
2433
+ // {:else if expr}{@const ...} -> : (expr) ? <>{(() => {const ...; return <>
2415
2434
  const elseIfStart = htmlx.lastIndexOf('{', ifBlock.expression.start);
2416
- const elseIfConditionEnd = htmlx.indexOf('}', ifBlock.expression.end) + 1;
2417
- str.overwrite(elseIfStart, ifBlock.expression.start, '</> : (', { contentOnly: true });
2418
- str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), elseIfConditionEnd, ') ? <>');
2435
+ str.overwrite(elseIfStart, ifBlock.expression.start, '</> : (', {
2436
+ contentOnly: true
2437
+ });
2438
+ str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), ifConditionEnd, ') ? <>' + startIIFE);
2419
2439
  ifScope.addElseIf(ifBlock.expression, str);
2420
2440
  if (!ifBlock.else) {
2421
- str.appendLeft(endIf, '</> : <>');
2441
+ str.appendLeft(endIf, endIIFE + '</> : <>');
2422
2442
  }
2423
2443
  return;
2424
2444
  }
2425
2445
  // {#if expr} -> {(expr) ? <>
2446
+ // {#if expr}{@const ...} -> {(expr) ? <>{(() => {const ...; return <>
2426
2447
  str.overwrite(ifBlock.start, ifBlock.expression.start, '{(', { contentOnly: true });
2427
- const end = htmlx.indexOf('}', ifBlock.expression.end);
2428
- str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), end + 1, ') ? <>', { contentOnly: true });
2448
+ str.overwrite(withTrailingPropertyAccess$1(str.original, ifBlock.expression.end), ifConditionEnd, ') ? <>' + startIIFE, { contentOnly: true });
2429
2449
  ifScope.addNestedIf(ifBlock.expression, str);
2430
2450
  if (ifBlock.else) {
2431
2451
  // {/if} -> </> }
@@ -2433,11 +2453,21 @@ function handleIf$1(htmlx, str, ifBlock, ifScope) {
2433
2453
  }
2434
2454
  else {
2435
2455
  // {/if} -> </> : <></>}
2436
- str.overwrite(endIf, ifBlock.end, '</> : <></>}', { contentOnly: true });
2456
+ // {@const ...} -> </>})()}</> : <></>}
2457
+ str.overwrite(endIf, ifBlock.end, endIIFE + '</> : <></>}', {
2458
+ contentOnly: true
2459
+ });
2437
2460
  }
2438
2461
  }
2462
+ function createStartIIFE(hasConstTags) {
2463
+ return hasConstTags ? '{(() => {' : '';
2464
+ }
2465
+ function createEndIIFE(hasConstTags) {
2466
+ return hasConstTags ? '</>})()}' : '';
2467
+ }
2439
2468
  /**
2440
2469
  * {:else} ---> </> : <>
2470
+ * {:else} {@const ...} -> </> : <>{(() => { const ...; return<>
2441
2471
  */
2442
2472
  function handleElse$1(htmlx, str, elseBlock, parent, ifScope) {
2443
2473
  var _a, _b;
@@ -2448,8 +2478,18 @@ function handleElse$1(htmlx, str, elseBlock, parent, ifScope) {
2448
2478
  const elseEnd = htmlx.lastIndexOf('}', elseBlock.start);
2449
2479
  const elseword = htmlx.lastIndexOf(':else', elseEnd);
2450
2480
  const elseStart = htmlx.lastIndexOf('{', elseword);
2451
- str.overwrite(elseStart, elseEnd + 1, '</> : <>');
2481
+ const constTags = extractConstTags(elseBlock.children);
2482
+ const hasConstTags = !!constTags.length;
2483
+ str.overwrite(elseStart, elseEnd + 1, '</> : <>' + createStartIIFE(hasConstTags));
2452
2484
  ifScope.addElse();
2485
+ if (!hasConstTags) {
2486
+ return;
2487
+ }
2488
+ constTags.forEach((constTag) => {
2489
+ constTag(elseEnd + 1, str);
2490
+ });
2491
+ str.appendRight(elseEnd + 1, 'return <>');
2492
+ str.appendLeft(elseBlock.end, createEndIIFE(true));
2453
2493
  }
2454
2494
 
2455
2495
  var IfType;
@@ -3425,8 +3465,8 @@ class Element {
3425
3465
  // remove the colon: svelte:xxx -> sveltexxx
3426
3466
  const nodeName = `svelte${this.node.name.substring(7)}`;
3427
3467
  this._name = '$$_' + nodeName + this.computeDepth();
3428
- this.startTransformation.push(`{ ${createElement}("${nodeName}", {`);
3429
- this.addNameConstDeclaration = () => (this.startTransformation[0] = `{ const ${this._name} = ${createElement}("${nodeName}", {`);
3468
+ this.startTransformation.push(`{ ${createElement}("${this.node.name}", {`);
3469
+ this.addNameConstDeclaration = () => (this.startTransformation[0] = `{ const ${this._name} = ${createElement}("${this.node.name}", {`);
3430
3470
  break;
3431
3471
  }
3432
3472
  case 'svelte:element': {
@@ -3895,7 +3935,7 @@ function handleAttribute(str, attr, parent, preserveCase, element) {
3895
3935
  return;
3896
3936
  }
3897
3937
  if (attr.value.length == 0) {
3898
- // attr=""
3938
+ // shouldn't happen
3899
3939
  addAttribute(attributeName, ['""']);
3900
3940
  return;
3901
3941
  }
@@ -3903,6 +3943,11 @@ function handleAttribute(str, attr, parent, preserveCase, element) {
3903
3943
  if (attr.value.length == 1) {
3904
3944
  const attrVal = attr.value[0];
3905
3945
  if (attrVal.type == 'Text') {
3946
+ // Handle the attr="" special case with a transformation that allows mapping of the position
3947
+ if (attrVal.start === attrVal.end) {
3948
+ addAttribute(attributeName, [[attrVal.start - 1, attrVal.end + 1]]);
3949
+ return;
3950
+ }
3906
3951
  const hasBrackets = str.original.lastIndexOf('}', attrVal.end) === attrVal.end - 1 ||
3907
3952
  str.original.lastIndexOf('}"', attrVal.end) === attrVal.end - 1 ||
3908
3953
  str.original.lastIndexOf("}'", attrVal.end) === attrVal.end - 1;
@@ -4783,22 +4828,6 @@ function getNamesFromLabeledStatement(node) {
4783
4828
  // svelte won't let you create a variable with $ prefix (reserved for stores)
4784
4829
  .filter((name) => !name.startsWith('$')));
4785
4830
  }
4786
- function isSafeToPrefixWithSemicolon(node) {
4787
- let parent = node.parent;
4788
- while (parent && !ts__default.isExpressionStatement(parent)) {
4789
- parent = parent.parent;
4790
- }
4791
- if (!parent) {
4792
- return false;
4793
- }
4794
- return (parent.getStart() === node.getStart() &&
4795
- !(parent.parent &&
4796
- (ts__default.isIfStatement(parent.parent) ||
4797
- ts__default.isForStatement(parent.parent) ||
4798
- ts__default.isForInStatement(parent.parent) ||
4799
- ts__default.isForOfStatement(parent.parent) ||
4800
- ts__default.isWhileStatement(parent.parent))));
4801
- }
4802
4831
 
4803
4832
  function is$$EventsDeclaration(node) {
4804
4833
  return isInterfaceOrTypeDeclaration(node) && node.name.text === '$$Events';
@@ -5903,72 +5932,12 @@ function getSingleSlotDef(componentNode, slotName) {
5903
5932
  return `__sveltets_1_instanceOf(${componentType}).$$slot_def['${slotName}']`;
5904
5933
  }
5905
5934
 
5906
- function handleStore(node, parent, str) {
5907
- const storename = node.name.slice(1);
5908
- //handle assign to
5909
- if (parent.type == 'AssignmentExpression' && parent.left == node && parent.operator == '=') {
5910
- const dollar = str.original.indexOf('$', node.start);
5911
- str.remove(dollar, dollar + 1);
5912
- str.overwrite(node.end, str.original.indexOf('=', node.end) + 1, '.set(');
5913
- str.appendLeft(parent.end, ')');
5914
- return;
5915
- }
5916
- // handle Assignment operators ($store +=, -=, *=, /=, %=, **=, etc.)
5917
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
5918
- const operators = ['+=', '-=', '*=', '/=', '%=', '**=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
5919
- if (parent.type == 'AssignmentExpression' &&
5920
- parent.left == node &&
5921
- operators.includes(parent.operator)) {
5922
- const storename = node.name.slice(1); // drop the $
5923
- const operator = parent.operator.substring(0, parent.operator.length - 1); // drop the = sign
5924
- str.overwrite(parent.start, str.original.indexOf('=', node.end) + 1, `${storename}.set( $${storename} ${operator}`);
5925
- str.appendLeft(parent.end, ')');
5926
- return;
5927
- }
5928
- // handle $store++, $store--, ++$store, --$store
5929
- if (parent.type == 'UpdateExpression') {
5930
- let simpleOperator;
5931
- if (parent.operator === '++') {
5932
- simpleOperator = '+';
5933
- }
5934
- if (parent.operator === '--') {
5935
- simpleOperator = '-';
5936
- }
5937
- if (simpleOperator) {
5938
- const storename = node.name.slice(1); // drop the $
5939
- str.overwrite(parent.start, parent.end, `(${storename}.set( $${storename} ${simpleOperator} 1), $${storename})`);
5940
- }
5941
- else {
5942
- console.warn(`Warning - unrecognized UpdateExpression operator ${parent.operator}!
5943
- This is an edge case unaccounted for in svelte2tsx, please file an issue:
5944
- https://github.com/sveltejs/language-tools/issues/new/choose
5945
- `, str.original.slice(parent.start, parent.end));
5946
- }
5947
- return;
5948
- }
5949
- const dollar = str.original.indexOf('$', node.start);
5950
- // handle bindings which are transformed to assignments. These need special treatment because
5951
- // `(__sveltets_1_store_get(foo), foo$) = something` is syntactically invalid
5952
- // Therefore remove the outer commas. Note: This relies on the binding expression wrapping
5953
- // this statement with __sveltets_1_empty
5954
- if (parent.type === 'Binding' && assignmentBindings.has(parent.name)) {
5955
- str.overwrite(dollar, dollar + 1, '__sveltets_1_store_get(', { contentOnly: true });
5956
- str.prependLeft(node.end, `), $${storename}`);
5957
- return;
5958
- }
5959
- // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
5960
- // - in order to get ts errors if store is not assignable to SvelteStore
5961
- // - use $store variable defined above to get ts flow control
5962
- str.overwrite(dollar, dollar + 1, '(__sveltets_1_store_get(', { contentOnly: true });
5963
- str.prependLeft(node.end, `), $${storename})`);
5964
- }
5965
5935
  const reservedNames = new Set(['$$props', '$$restProps', '$$slots']);
5966
5936
  class Stores {
5967
- constructor(scope, str, isDeclaration) {
5937
+ constructor(scope, isDeclaration) {
5968
5938
  this.scope = scope;
5969
- this.str = str;
5970
5939
  this.isDeclaration = isDeclaration;
5971
- this.pendingStoreResolutions = [];
5940
+ this.possibleStores = [];
5972
5941
  }
5973
5942
  handleDirective(node, str) {
5974
5943
  if (this.notAStore(node.name) || this.isDeclaration.value) {
@@ -5976,7 +5945,7 @@ class Stores {
5976
5945
  }
5977
5946
  const start = str.original.indexOf('$', node.start);
5978
5947
  const end = start + node.name.length;
5979
- this.pendingStoreResolutions.push({
5948
+ this.possibleStores.push({
5980
5949
  node: { type: 'Identifier', start, end, name: node.name },
5981
5950
  parent: { start: 0, end: 0, type: '' },
5982
5951
  scope: this.scope.current
@@ -6000,18 +5969,17 @@ class Stores {
6000
5969
  if (isObjectKey(parent, prop)) {
6001
5970
  return;
6002
5971
  }
6003
- this.pendingStoreResolutions.push({ node, parent, scope: this.scope.current });
5972
+ this.possibleStores.push({ node, parent, scope: this.scope.current });
6004
5973
  }
6005
5974
  }
6006
- resolveStores() {
6007
- const unresolvedStores = this.pendingStoreResolutions.filter(({ node, scope }) => {
5975
+ getStoreNames() {
5976
+ const stores = this.possibleStores.filter(({ node, scope }) => {
6008
5977
  const name = node.name;
6009
5978
  // if variable starting with '$' was manually declared by the user,
6010
5979
  // this isn't a store access.
6011
5980
  return !scope.hasDefined(name);
6012
5981
  });
6013
- unresolvedStores.forEach(({ node, parent }) => handleStore(node, parent, this.str));
6014
- return unresolvedStores.map(({ node }) => node.name.slice(1));
5982
+ return stores.map(({ node }) => node.name.slice(1));
6015
5983
  }
6016
5984
  notAStore(name) {
6017
5985
  return name[0] !== '$' || reservedNames.has(name);
@@ -6302,9 +6270,15 @@ class Generics {
6302
6270
  /**
6303
6271
  * move imports to top of script so they appear outside our render function
6304
6272
  */
6305
- function handleImportDeclaration(node, str, astOffset, scriptStart) {
6273
+ function handleImportDeclaration(node, str, astOffset, scriptStart, sourceFile) {
6306
6274
  var _a;
6275
+ const scanner = ts__default.createScanner(sourceFile.languageVersion,
6276
+ /*skipTrivia*/ false, sourceFile.languageVariant);
6307
6277
  const comments = (_a = ts__default.getLeadingCommentRanges(node.getFullText(), 0)) !== null && _a !== void 0 ? _a : [];
6278
+ if (!comments.some((comment) => comment.hasTrailingNewLine) &&
6279
+ isNewGroup(sourceFile, node, scanner)) {
6280
+ str.appendRight(node.getStart() + astOffset, '\n');
6281
+ }
6308
6282
  for (const comment of comments) {
6309
6283
  const commentEnd = node.pos + comment.end + astOffset;
6310
6284
  str.move(node.pos + comment.pos + astOffset, commentEnd, scriptStart + 1);
@@ -6317,8 +6291,27 @@ function handleImportDeclaration(node, str, astOffset, scriptStart) {
6317
6291
  const originalEndChar = str.original[node.end + astOffset - 1];
6318
6292
  str.overwrite(node.end + astOffset - 1, node.end + astOffset, originalEndChar + '\n');
6319
6293
  }
6294
+ /**
6295
+ * adopted from https://github.com/microsoft/TypeScript/blob/6e0447fdf165b1cec9fc80802abcc15bd23a268f/src/services/organizeImports.ts#L111
6296
+ */
6297
+ function isNewGroup(sourceFile, topLevelImportDecl, scanner) {
6298
+ const startPos = topLevelImportDecl.getFullStart();
6299
+ const endPos = topLevelImportDecl.getStart();
6300
+ scanner.setText(sourceFile.text, startPos, endPos - startPos);
6301
+ let numberOfNewLines = 0;
6302
+ while (scanner.getTokenPos() < endPos) {
6303
+ const tokenKind = scanner.scan();
6304
+ if (tokenKind === ts__default.SyntaxKind.NewLineTrivia) {
6305
+ numberOfNewLines++;
6306
+ if (numberOfNewLines >= 2) {
6307
+ return true;
6308
+ }
6309
+ }
6310
+ }
6311
+ return false;
6312
+ }
6320
6313
 
6321
- function processInstanceScriptContent(str, script, events, implicitStoreValues, mode) {
6314
+ function processInstanceScriptContent(str, script, events, implicitStoreValues, mode, hasModuleScript) {
6322
6315
  const htmlx = str.original;
6323
6316
  const scriptContent = htmlx.substring(script.content.start, script.content.end);
6324
6317
  const tsAst = ts.createSourceFile('component.ts.svelte', scriptContent, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
@@ -6339,95 +6332,8 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6339
6332
  const rootScope = scope;
6340
6333
  const pushScope = () => (scope = new Scope(scope));
6341
6334
  const popScope = () => (scope = scope.parent);
6342
- const handleStore = (ident, parent) => {
6343
- // ignore "typeof $store"
6344
- if (parent && parent.kind === ts.SyntaxKind.TypeQuery) {
6345
- return;
6346
- }
6347
- // ignore break
6348
- if (parent && parent.kind === ts.SyntaxKind.BreakStatement) {
6349
- return;
6350
- }
6351
- const storename = ident.getText().slice(1); // drop the $
6352
- // handle assign to
6353
- if (parent &&
6354
- ts.isBinaryExpression(parent) &&
6355
- parent.operatorToken.kind == ts.SyntaxKind.EqualsToken &&
6356
- parent.left == ident) {
6357
- //remove $
6358
- const dollar = str.original.indexOf('$', ident.getStart() + astOffset);
6359
- str.remove(dollar, dollar + 1);
6360
- // replace = with .set(
6361
- str.overwrite(ident.end + astOffset, parent.operatorToken.end + astOffset, '.set(');
6362
- // append )
6363
- str.appendLeft(parent.end + astOffset, ')');
6364
- return;
6365
- }
6366
- // handle Assignment operators ($store +=, -=, *=, /=, %=, **=, etc.)
6367
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment
6368
- const operators = {
6369
- [ts.SyntaxKind.PlusEqualsToken]: '+',
6370
- [ts.SyntaxKind.MinusEqualsToken]: '-',
6371
- [ts.SyntaxKind.AsteriskEqualsToken]: '*',
6372
- [ts.SyntaxKind.SlashEqualsToken]: '/',
6373
- [ts.SyntaxKind.PercentEqualsToken]: '%',
6374
- [ts.SyntaxKind.AsteriskAsteriskEqualsToken]: '**',
6375
- [ts.SyntaxKind.LessThanLessThanEqualsToken]: '<<',
6376
- [ts.SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>',
6377
- [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>',
6378
- [ts.SyntaxKind.AmpersandEqualsToken]: '&',
6379
- [ts.SyntaxKind.CaretEqualsToken]: '^',
6380
- [ts.SyntaxKind.BarEqualsToken]: '|'
6381
- };
6382
- if (ts.isBinaryExpression(parent) &&
6383
- parent.left == ident &&
6384
- Object.keys(operators).find((x) => x === String(parent.operatorToken.kind))) {
6385
- const operator = operators[parent.operatorToken.kind];
6386
- str.overwrite(parent.getStart() + astOffset, str.original.indexOf('=', ident.end + astOffset) + 1, `${storename}.set( $${storename} ${operator}`);
6387
- str.appendLeft(parent.end + astOffset, ')');
6388
- return;
6389
- }
6390
- // handle $store++, $store--, ++$store, --$store
6391
- if ((ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent)) &&
6392
- ![
6393
- ts.SyntaxKind.ExclamationToken,
6394
- ts.SyntaxKind.PlusToken,
6395
- ts.SyntaxKind.MinusToken,
6396
- ts.SyntaxKind.TildeToken // ~$store
6397
- ].includes(parent.operator) /* `!$store` etc does not need processing */) {
6398
- let simpleOperator;
6399
- if (parent.operator === ts.SyntaxKind.PlusPlusToken) {
6400
- simpleOperator = '+';
6401
- }
6402
- if (parent.operator === ts.SyntaxKind.MinusMinusToken) {
6403
- simpleOperator = '-';
6404
- }
6405
- if (simpleOperator) {
6406
- str.overwrite(parent.getStart() + astOffset, parent.end + astOffset, `(${storename}.set( $${storename} ${simpleOperator} 1), $${storename})`);
6407
- return;
6408
- }
6409
- else {
6410
- console.warn(`Warning - unrecognized UnaryExpression operator ${parent.operator}!
6411
- This is an edge case unaccounted for in svelte2tsx, please file an issue:
6412
- https://github.com/sveltejs/language-tools/issues/new/choose
6413
- `, parent.getText());
6414
- }
6415
- }
6416
- // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
6417
- // - in order to get ts errors if store is not assignable to SvelteStore
6418
- // - use $store variable defined above to get ts flow control
6419
- const dollar = str.original.indexOf('$', ident.getStart() + astOffset);
6420
- const getPrefix = isSafeToPrefixWithSemicolon(ident)
6421
- ? ';'
6422
- : ts.isShorthandPropertyAssignment(parent)
6423
- ? // { $store } --> { $store: __sveltets_1_store_get(..)}
6424
- ident.text + ': '
6425
- : '';
6426
- str.overwrite(dollar, dollar + 1, getPrefix + '(__sveltets_1_store_get(');
6427
- str.prependLeft(ident.end + astOffset, `), $${storename})`);
6428
- };
6429
6335
  const resolveStore = (pending) => {
6430
- let { node, parent, scope } = pending;
6336
+ let { node, scope } = pending;
6431
6337
  const name = node.text;
6432
6338
  while (scope) {
6433
6339
  if (scope.declared.has(name)) {
@@ -6436,8 +6342,6 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6436
6342
  }
6437
6343
  scope = scope.parent;
6438
6344
  }
6439
- //We haven't been resolved, we must be a store read/write, handle it.
6440
- handleStore(node, parent);
6441
6345
  const storename = node.getText().slice(1);
6442
6346
  implicitStoreValues.addStoreAcess(storename);
6443
6347
  };
@@ -6514,7 +6418,7 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6514
6418
  exportedNames.handleExportDeclaration(node);
6515
6419
  }
6516
6420
  if (ts.isImportDeclaration(node)) {
6517
- handleImportDeclaration(node, str, astOffset, script.start);
6421
+ handleImportDeclaration(node, str, astOffset, script.start, tsAst);
6518
6422
  // Check if import is the event dispatcher
6519
6423
  events.checkIfImportIsEventDispatcher(node);
6520
6424
  }
@@ -6587,7 +6491,9 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
6587
6491
  .filter(ts.isImportDeclaration)
6588
6492
  .sort((a, b) => a.end - b.end)[0];
6589
6493
  if (firstImport) {
6590
- str.appendRight(firstImport.getStart() + astOffset, '\n');
6494
+ // ensure it's in a newline.
6495
+ // if file has module script ensure an empty line to separate imports
6496
+ str.appendRight(firstImport.getStart() + astOffset, '\n' + (hasModuleScript ? '\n' : ''));
6591
6497
  }
6592
6498
  if (mode === 'dts') {
6593
6499
  // Transform interface declarations to type declarations because indirectly
@@ -6911,7 +6817,7 @@ function processSvelteTemplate(str, options) {
6911
6817
  //track $store variables since we are only supposed to give top level scopes special treatment, and users can declare $blah variables at higher scopes
6912
6818
  //which prevents us just changing all instances of Identity that start with $
6913
6819
  const scopeStack = new ScopeStack();
6914
- const stores = new Stores(scopeStack, str, isDeclaration);
6820
+ const stores = new Stores(scopeStack, isDeclaration);
6915
6821
  const scripts = new Scripts(htmlxAst);
6916
6822
  const handleSvelteOptions = (node) => {
6917
6823
  for (let i = 0; i < node.attributes.length; i++) {
@@ -7098,7 +7004,7 @@ function processSvelteTemplate(str, options) {
7098
7004
  const { scriptTag, moduleScriptTag } = scripts.getTopLevelScriptTags();
7099
7005
  scripts.blankOtherScriptTags(str);
7100
7006
  //resolve stores
7101
- const resolvedStores = stores.resolveStores();
7007
+ const resolvedStores = stores.getStoreNames();
7102
7008
  return {
7103
7009
  htmlAst: htmlxAst,
7104
7010
  moduleScriptTag,
@@ -7148,7 +7054,8 @@ function svelte2tsx(svelte, options = {}) {
7148
7054
  if (scriptTag.start != instanceScriptTarget) {
7149
7055
  str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
7150
7056
  }
7151
- const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode);
7057
+ const res = processInstanceScriptContent(str, scriptTag, events, implicitStoreValues, options.mode,
7058
+ /**hasModuleScripts */ !!moduleScriptTag);
7152
7059
  uses$$props = uses$$props || res.uses$$props;
7153
7060
  uses$$restProps = uses$$restProps || res.uses$$restProps;
7154
7061
  uses$$slots = uses$$slots || res.uses$$slots;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.5.9",
3
+ "version": "0.5.12",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "David Pershouse",
6
6
  "license": "MIT",
@@ -18,6 +18,7 @@
18
18
  "module": "index.mjs",
19
19
  "types": "index.d.ts",
20
20
  "devDependencies": {
21
+ "@jridgewell/trace-mapping": "^0.3.9",
21
22
  "@rollup/plugin-commonjs": "^15.0.0",
22
23
  "@rollup/plugin-json": "^4.0.0",
23
24
  "@rollup/plugin-node-resolve": "^9.0.0",
@@ -31,13 +32,12 @@
31
32
  "periscopic": "^2.0.2",
32
33
  "rollup": "2.52.7",
33
34
  "rollup-plugin-delete": "^2.0.0",
34
- "source-map": "^0.6.1",
35
35
  "source-map-support": "^0.5.16",
36
36
  "sourcemap-codec": "^1.4.8",
37
- "svelte": "~3.47.0",
37
+ "svelte": "~3.49.0",
38
38
  "tiny-glob": "^0.2.6",
39
39
  "tslib": "^1.10.0",
40
- "typescript": "^4.6.2"
40
+ "typescript": "^4.7.3"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "svelte": "^3.24",
package/svelte-jsx.d.ts CHANGED
@@ -294,11 +294,11 @@ declare namespace svelteHTML {
294
294
  view: SVGProps<SVGViewElement>;
295
295
 
296
296
  // Svelte specific
297
- sveltewindow: HTMLProps<Window> & SvelteWindowProps;
298
- sveltebody: HTMLProps<HTMLElement>;
299
- sveltefragment: { slot?: string; };
300
- svelteoptions: { [name: string]: any };
301
- sveltehead: { [name: string]: any };
297
+ 'svelte:window': HTMLProps<Window> & SvelteWindowProps;
298
+ 'svelte:body': HTMLProps<HTMLElement>;
299
+ 'svelte:fragment': { slot?: string; };
300
+ 'svelte:options': { [name: string]: any };
301
+ 'svelte:head': { [name: string]: any };
302
302
 
303
303
  [name: string]: { [name: string]: any };
304
304
  }
package/svelte-shims.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  // -- start svelte-ls-remove --
7
7
  declare module '*.svelte' {
8
- export default Svelte2TsxComponent
8
+ export default _SvelteComponent
9
9
  }
10
10
  // -- end svelte-ls-remove --
11
11
 
@@ -53,6 +53,8 @@ declare class Svelte2TsxComponent<
53
53
  $inject_state(): void;
54
54
  }
55
55
 
56
+ type _SvelteComponent<Props=any,Events=any,Slots=any> = typeof import("svelte") extends {SvelteComponentTyped: any} ? import("svelte").SvelteComponentTyped<Props,Events,Slots> : Svelte2TsxComponent<Props,Events,Slots>;
57
+
56
58
  interface Svelte2TsxComponentConstructorParameters<Props extends {}> {
57
59
  /**
58
60
  * An HTMLElement to render to. This option is required.
@@ -167,7 +169,7 @@ declare function __sveltets_1_store_get<T = any>(store: SvelteStore<T>): T
167
169
  declare function __sveltets_1_store_get<Store extends SvelteStore<any> | undefined | null>(store: Store): Store extends SvelteStore<infer T> ? T : Store;
168
170
  declare function __sveltets_1_any(dummy: any): any;
169
171
  declare function __sveltets_1_empty(...dummy: any[]): {};
170
- declare function __sveltets_1_componentType(): AConstructorTypeOf<Svelte2TsxComponent<any, any, any>>
172
+ declare function __sveltets_1_componentType(): AConstructorTypeOf<_SvelteComponent<any, any, any>>
171
173
  declare function __sveltets_1_invalidate<T>(getValue: () => T): T
172
174
 
173
175
  declare function __sveltets_1_mapWindowEvent<K extends keyof HTMLBodyElementEventMap>(
@@ -217,17 +219,18 @@ declare function __sveltets_1_each<T extends ArrayLike<unknown>>(
217
219
 
218
220
  declare function __sveltets_1_createSvelte2TsxComponent<Props, Events, Slots>(
219
221
  render: {props: Props, events: Events, slots: Slots }
220
- ): SvelteComponentConstructor<Svelte2TsxComponent<Props, Events, Slots>,Svelte2TsxComponentConstructorParameters<Props>>;
222
+ ): SvelteComponentConstructor<_SvelteComponent<Props, Events, Slots>,Svelte2TsxComponentConstructorParameters<Props>>;
221
223
 
222
224
  declare function __sveltets_1_unwrapArr<T>(arr: ArrayLike<T>): T
223
225
  declare function __sveltets_1_unwrapPromiseLike<T>(promise: PromiseLike<T> | T): T
224
226
 
225
227
  // v2
226
228
  declare function __sveltets_2_createCreateSlot<Slots = Record<string, Record<string, any>>>(): <SlotName extends keyof Slots>(slotName: SlotName, attrs: Slots[SlotName]) => Record<string, any>;
227
- declare function __sveltets_2_createComponentAny(props: Record<string, any>): Svelte2TsxComponent<any, any, any>;
229
+ declare function __sveltets_2_createComponentAny(props: Record<string, any>): _SvelteComponent<any, any, any>;
228
230
 
229
231
  declare function __sveltets_2_any(...dummy: any[]): any;
230
232
  declare function __sveltets_2_empty(...dummy: any[]): {};
233
+ declare function __sveltets_2_union<T1,T2,T3,T4,T5>(t1:T1,t2?:T2,t3?:T3,t4?:T4,t5?:T5): T1 & T2 & T3 & T4 & T5;
231
234
 
232
235
  declare function __sveltets_2_cssProp(prop: Record<string, any>): {};
233
236
 
@@ -263,7 +266,7 @@ declare function __sveltets_2_ensureType<T1, T2>(type1: AConstructorTypeOf<T1>,
263
266
 
264
267
  // The following is necessary because there are two clashing errors that can't be solved at the same time
265
268
  // when using Svelte2TsxComponent, more precisely the event typings in
266
- // __sveltets_2_ensureComponent<T extends new (..) => Svelte2TsxComponent<any,||any||<-this,any>>(type: T): T;
269
+ // __sveltets_2_ensureComponent<T extends new (..) => _SvelteComponent<any,||any||<-this,any>>(type: T): T;
267
270
  // If we type it as "any", we have an error when using sth like {a: CustomEvent<any>}
268
271
  // If we type it as "{}", we have an error when using sth like {[evt: string]: CustomEvent<any>}
269
272
  // If we type it as "unknown", we get all kinds of follow up errors which we want to avoid