svelte2tsx 0.4.7 → 0.4.8

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
@@ -1494,6 +1494,12 @@ function surroundWithIgnoreComments(str) {
1494
1494
  return IGNORE_START_COMMENT + str + IGNORE_END_COMMENT;
1495
1495
  }
1496
1496
 
1497
+ /**
1498
+ * Get the constructor type of a component node
1499
+ * @param node The component node to infer the this type from
1500
+ * @param thisValue If node is svelte:component, you may pass the value
1501
+ * of this={..} to use that instead of the more general componentType
1502
+ */
1497
1503
  function getTypeForComponent(node) {
1498
1504
  if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1499
1505
  return '__sveltets_1_componentType()';
@@ -1502,6 +1508,36 @@ function getTypeForComponent(node) {
1502
1508
  return node.name;
1503
1509
  }
1504
1510
  }
1511
+ /**
1512
+ * Get the instance type of a node from its constructor.
1513
+ */
1514
+ function getInstanceTypeSimple(node, str) {
1515
+ const instanceOf = (str) => `__sveltets_1_instanceOf(${str})`;
1516
+ switch (node.type) {
1517
+ case 'InlineComponent':
1518
+ if (node.name === 'svelte:component' && node.expression) {
1519
+ const thisVal = str.original.substring(node.expression.start, node.expression.end);
1520
+ return `new (${thisVal})({target: __sveltets_1_any(''), props: __sveltets_1_any('')})`;
1521
+ }
1522
+ else if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1523
+ return instanceOf('__sveltets_1_componentType()');
1524
+ }
1525
+ else {
1526
+ return `new ${node.name}({target: __sveltets_1_any(''), props: __sveltets_1_any('')})`;
1527
+ }
1528
+ case 'Element':
1529
+ return instanceOf(`__sveltets_1_ctorOf(__sveltets_1_mapElementTag('${node.name}'))`);
1530
+ case 'Body':
1531
+ return instanceOf('HTMLBodyElement');
1532
+ case 'Slot': // Web Components only
1533
+ return instanceOf('HTMLSlotElement');
1534
+ }
1535
+ }
1536
+ /**
1537
+ * Get the instance type of a node from its constructor.
1538
+ * If it's a component, pass in the exact props. This ensures that
1539
+ * the component instance has the right type in case of generic prop types.
1540
+ */
1505
1541
  function getInstanceType(node, originalStr, replacedPropValues = []) {
1506
1542
  if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1507
1543
  return '__sveltets_1_instanceOf(__sveltets_1_componentType())';
@@ -1602,18 +1638,6 @@ function sanitizePropName(name) {
1602
1638
  .map((char) => (/[0-9A-Za-z$_]/.test(char) ? char : '_'))
1603
1639
  .join('');
1604
1640
  }
1605
- function getThisType(node) {
1606
- switch (node.type) {
1607
- case 'InlineComponent':
1608
- return getTypeForComponent(node);
1609
- case 'Element':
1610
- return `__sveltets_1_ctorOf(__sveltets_1_mapElementTag('${node.name}'))`;
1611
- case 'Body':
1612
- return 'HTMLBodyElement';
1613
- case 'Slot': // Web Components only
1614
- return 'HTMLSlotElement';
1615
- }
1616
- }
1617
1641
  function beforeStart(start) {
1618
1642
  return start - 1;
1619
1643
  }
@@ -1981,6 +2005,11 @@ const oneWayBindingAttributes = new Map(['clientWidth', 'clientHeight', 'offsetW
1981
2005
  e,
1982
2006
  'HTMLMediaElement'
1983
2007
  ])));
2008
+ /**
2009
+ * List of all binding names that are transformed to sth like `binding = variable`.
2010
+ * This applies to readonly bindings and the this binding.
2011
+ */
2012
+ const assignmentBindings = new Set([...oneWayBindingAttributes.keys(), 'this']);
1984
2013
  /**
1985
2014
  * Transform bind:xxx into something that conforms to JSX
1986
2015
  */
@@ -2006,11 +2035,19 @@ function handleBinding(htmlx, str, attr, el) {
2006
2035
  ];
2007
2036
  //bind this
2008
2037
  if (attr.name === 'this' && supportsBindThis.includes(el.type)) {
2009
- const thisType = getThisType(el);
2038
+ // bind:this is effectively only works bottom up - the variable is updated by the element, not
2039
+ // the other way round. So we check if the instance is assignable to the variable.
2040
+ // Some notes:
2041
+ // - If the component unmounts (it's inside an if block, or svelte:component this={null},
2042
+ // the value becomes null, but we don't add it to the clause because it would introduce
2043
+ // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2044
+ // - This doesn't do a 100% correct job of infering the instance type in case someone used generics for input props.
2045
+ // For now it errs on the side of "no false positives" at the cost of maybe some missed type bugs
2046
+ const thisType = getInstanceTypeSimple(el, str);
2010
2047
  if (thisType) {
2011
- str.remove(attr.start, attr.expression.start);
2012
- str.appendLeft(attr.expression.start, `{...__sveltets_1_ensureType(${thisType}, `);
2013
- str.overwrite(attr.expression.end, attr.end, ')}');
2048
+ str.overwrite(attr.start, attr.expression.start, '{...__sveltets_1_empty(');
2049
+ const instanceOfThisAssignment = ' = ' + surroundWithIgnoreComments(thisType) + ')}';
2050
+ str.overwrite(attr.expression.end, attr.end, instanceOfThisAssignment);
2014
2051
  return;
2015
2052
  }
2016
2053
  }
@@ -4306,10 +4343,19 @@ function handleStore(node, parent, str) {
4306
4343
  }
4307
4344
  return;
4308
4345
  }
4346
+ const dollar = str.original.indexOf('$', node.start);
4347
+ // handle bindings which are transformed to assignments. These need special treatment because
4348
+ // `(__sveltets_1_store_get(foo), foo$) = something` is syntactically invalid
4349
+ // Therefore remove the outer commas. Note: This relies on the binding expression wrapping
4350
+ // this statement with __sveltets_1_empty
4351
+ if (parent.type === 'Binding' && assignmentBindings.has(parent.name)) {
4352
+ str.overwrite(dollar, dollar + 1, '__sveltets_1_store_get(', { contentOnly: true });
4353
+ str.prependLeft(node.end, `), $${storename}`);
4354
+ return;
4355
+ }
4309
4356
  // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
4310
4357
  // - in order to get ts errors if store is not assignable to SvelteStore
4311
4358
  // - use $store variable defined above to get ts flow control
4312
- const dollar = str.original.indexOf('$', node.start);
4313
4359
  str.overwrite(dollar, dollar + 1, '(__sveltets_1_store_get(', { contentOnly: true });
4314
4360
  str.prependLeft(node.end, `), $${storename})`);
4315
4361
  }
@@ -4718,8 +4764,12 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
4718
4764
  }
4719
4765
  // handle $store++, $store--, ++$store, --$store
4720
4766
  if ((ts__namespace.isPrefixUnaryExpression(parent) || ts__namespace.isPostfixUnaryExpression(parent)) &&
4721
- parent.operator !==
4722
- ts__namespace.SyntaxKind.ExclamationToken /* `!$store` does not need processing */) {
4767
+ ![
4768
+ ts__namespace.SyntaxKind.ExclamationToken,
4769
+ ts__namespace.SyntaxKind.PlusToken,
4770
+ ts__namespace.SyntaxKind.MinusToken,
4771
+ ts__namespace.SyntaxKind.TildeToken // ~$store
4772
+ ].includes(parent.operator) /* `!$store` etc does not need processing */) {
4723
4773
  let simpleOperator;
4724
4774
  if (parent.operator === ts__namespace.SyntaxKind.PlusPlusToken) {
4725
4775
  simpleOperator = '+';
package/index.mjs CHANGED
@@ -1464,6 +1464,12 @@ function surroundWithIgnoreComments(str) {
1464
1464
  return IGNORE_START_COMMENT + str + IGNORE_END_COMMENT;
1465
1465
  }
1466
1466
 
1467
+ /**
1468
+ * Get the constructor type of a component node
1469
+ * @param node The component node to infer the this type from
1470
+ * @param thisValue If node is svelte:component, you may pass the value
1471
+ * of this={..} to use that instead of the more general componentType
1472
+ */
1467
1473
  function getTypeForComponent(node) {
1468
1474
  if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1469
1475
  return '__sveltets_1_componentType()';
@@ -1472,6 +1478,36 @@ function getTypeForComponent(node) {
1472
1478
  return node.name;
1473
1479
  }
1474
1480
  }
1481
+ /**
1482
+ * Get the instance type of a node from its constructor.
1483
+ */
1484
+ function getInstanceTypeSimple(node, str) {
1485
+ const instanceOf = (str) => `__sveltets_1_instanceOf(${str})`;
1486
+ switch (node.type) {
1487
+ case 'InlineComponent':
1488
+ if (node.name === 'svelte:component' && node.expression) {
1489
+ const thisVal = str.original.substring(node.expression.start, node.expression.end);
1490
+ return `new (${thisVal})({target: __sveltets_1_any(''), props: __sveltets_1_any('')})`;
1491
+ }
1492
+ else if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1493
+ return instanceOf('__sveltets_1_componentType()');
1494
+ }
1495
+ else {
1496
+ return `new ${node.name}({target: __sveltets_1_any(''), props: __sveltets_1_any('')})`;
1497
+ }
1498
+ case 'Element':
1499
+ return instanceOf(`__sveltets_1_ctorOf(__sveltets_1_mapElementTag('${node.name}'))`);
1500
+ case 'Body':
1501
+ return instanceOf('HTMLBodyElement');
1502
+ case 'Slot': // Web Components only
1503
+ return instanceOf('HTMLSlotElement');
1504
+ }
1505
+ }
1506
+ /**
1507
+ * Get the instance type of a node from its constructor.
1508
+ * If it's a component, pass in the exact props. This ensures that
1509
+ * the component instance has the right type in case of generic prop types.
1510
+ */
1475
1511
  function getInstanceType(node, originalStr, replacedPropValues = []) {
1476
1512
  if (node.name === 'svelte:component' || node.name === 'svelte:self') {
1477
1513
  return '__sveltets_1_instanceOf(__sveltets_1_componentType())';
@@ -1572,18 +1608,6 @@ function sanitizePropName(name) {
1572
1608
  .map((char) => (/[0-9A-Za-z$_]/.test(char) ? char : '_'))
1573
1609
  .join('');
1574
1610
  }
1575
- function getThisType(node) {
1576
- switch (node.type) {
1577
- case 'InlineComponent':
1578
- return getTypeForComponent(node);
1579
- case 'Element':
1580
- return `__sveltets_1_ctorOf(__sveltets_1_mapElementTag('${node.name}'))`;
1581
- case 'Body':
1582
- return 'HTMLBodyElement';
1583
- case 'Slot': // Web Components only
1584
- return 'HTMLSlotElement';
1585
- }
1586
- }
1587
1611
  function beforeStart(start) {
1588
1612
  return start - 1;
1589
1613
  }
@@ -1951,6 +1975,11 @@ const oneWayBindingAttributes = new Map(['clientWidth', 'clientHeight', 'offsetW
1951
1975
  e,
1952
1976
  'HTMLMediaElement'
1953
1977
  ])));
1978
+ /**
1979
+ * List of all binding names that are transformed to sth like `binding = variable`.
1980
+ * This applies to readonly bindings and the this binding.
1981
+ */
1982
+ const assignmentBindings = new Set([...oneWayBindingAttributes.keys(), 'this']);
1954
1983
  /**
1955
1984
  * Transform bind:xxx into something that conforms to JSX
1956
1985
  */
@@ -1976,11 +2005,19 @@ function handleBinding(htmlx, str, attr, el) {
1976
2005
  ];
1977
2006
  //bind this
1978
2007
  if (attr.name === 'this' && supportsBindThis.includes(el.type)) {
1979
- const thisType = getThisType(el);
2008
+ // bind:this is effectively only works bottom up - the variable is updated by the element, not
2009
+ // the other way round. So we check if the instance is assignable to the variable.
2010
+ // Some notes:
2011
+ // - If the component unmounts (it's inside an if block, or svelte:component this={null},
2012
+ // the value becomes null, but we don't add it to the clause because it would introduce
2013
+ // worse DX for the 99% use case, and because null !== undefined which others might use to type the declaration.
2014
+ // - This doesn't do a 100% correct job of infering the instance type in case someone used generics for input props.
2015
+ // For now it errs on the side of "no false positives" at the cost of maybe some missed type bugs
2016
+ const thisType = getInstanceTypeSimple(el, str);
1980
2017
  if (thisType) {
1981
- str.remove(attr.start, attr.expression.start);
1982
- str.appendLeft(attr.expression.start, `{...__sveltets_1_ensureType(${thisType}, `);
1983
- str.overwrite(attr.expression.end, attr.end, ')}');
2018
+ str.overwrite(attr.start, attr.expression.start, '{...__sveltets_1_empty(');
2019
+ const instanceOfThisAssignment = ' = ' + surroundWithIgnoreComments(thisType) + ')}';
2020
+ str.overwrite(attr.expression.end, attr.end, instanceOfThisAssignment);
1984
2021
  return;
1985
2022
  }
1986
2023
  }
@@ -4276,10 +4313,19 @@ function handleStore(node, parent, str) {
4276
4313
  }
4277
4314
  return;
4278
4315
  }
4316
+ const dollar = str.original.indexOf('$', node.start);
4317
+ // handle bindings which are transformed to assignments. These need special treatment because
4318
+ // `(__sveltets_1_store_get(foo), foo$) = something` is syntactically invalid
4319
+ // Therefore remove the outer commas. Note: This relies on the binding expression wrapping
4320
+ // this statement with __sveltets_1_empty
4321
+ if (parent.type === 'Binding' && assignmentBindings.has(parent.name)) {
4322
+ str.overwrite(dollar, dollar + 1, '__sveltets_1_store_get(', { contentOnly: true });
4323
+ str.prependLeft(node.end, `), $${storename}`);
4324
+ return;
4325
+ }
4279
4326
  // we change "$store" references into "(__sveltets_1_store_get(store), $store)"
4280
4327
  // - in order to get ts errors if store is not assignable to SvelteStore
4281
4328
  // - use $store variable defined above to get ts flow control
4282
- const dollar = str.original.indexOf('$', node.start);
4283
4329
  str.overwrite(dollar, dollar + 1, '(__sveltets_1_store_get(', { contentOnly: true });
4284
4330
  str.prependLeft(node.end, `), $${storename})`);
4285
4331
  }
@@ -4688,8 +4734,12 @@ function processInstanceScriptContent(str, script, events, implicitStoreValues,
4688
4734
  }
4689
4735
  // handle $store++, $store--, ++$store, --$store
4690
4736
  if ((ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent)) &&
4691
- parent.operator !==
4692
- ts.SyntaxKind.ExclamationToken /* `!$store` does not need processing */) {
4737
+ ![
4738
+ ts.SyntaxKind.ExclamationToken,
4739
+ ts.SyntaxKind.PlusToken,
4740
+ ts.SyntaxKind.MinusToken,
4741
+ ts.SyntaxKind.TildeToken // ~$store
4742
+ ].includes(parent.operator) /* `!$store` etc does not need processing */) {
4693
4743
  let simpleOperator;
4694
4744
  if (parent.operator === ts.SyntaxKind.PlusPlusToken) {
4695
4745
  simpleOperator = '+';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte2tsx",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "Convert Svelte components to TSX for type checking",
5
5
  "author": "David Pershouse",
6
6
  "license": "MIT",
package/svelte-jsx.d.ts CHANGED
@@ -59,11 +59,6 @@ declare namespace svelte.JSX {
59
59
  type TransitionEventHandler<T extends EventTarget> = EventHandler<TransitionEvent, T>;
60
60
  type MessageEventHandler<T extends EventTarget> = EventHandler<MessageEvent, T>;
61
61
 
62
- type ClassNameBase = boolean | string | number | void | null;
63
- type ClassName = string | Array<ClassNameBase | ClassNameBase[]> | {
64
- [key: string]: boolean;
65
- }
66
-
67
62
  // See CSS 3 CSS-wide keywords https://www.w3.org/TR/css3-values/#common-keywords
68
63
  // See CSS 3 Explicit Defaulting https://www.w3.org/TR/css-cascade-3/#defaulting-keywords
69
64
  // "all CSS properties can accept these values"
@@ -414,11 +409,9 @@ declare namespace svelte.JSX {
414
409
  }
415
410
 
416
411
  interface HTMLAttributes<T extends EventTarget> extends AriaAttributes, DOMAttributes<T> {
417
- // jsx-dom-specific Attributes
418
- class?: ClassName | undefined;
419
- dataset?: object | undefined; // eslint-disable-line
420
-
421
412
  // Standard HTML Attributes
413
+ class?: string | undefined;
414
+ dataset?: object | undefined; // eslint-disable-line
422
415
  accept?: string | undefined;
423
416
  acceptcharset?: string | undefined;
424
417
  accesskey?: string | undefined;
@@ -441,7 +434,6 @@ declare namespace svelte.JSX {
441
434
  checked?: boolean | undefined;
442
435
  cite?: string | undefined;
443
436
  classid?: string | undefined;
444
- classname?: ClassName | undefined;
445
437
  cols?: number | undefined;
446
438
  colspan?: number | undefined;
447
439
  content?: string | undefined;
package/svelte-shims.d.ts CHANGED
@@ -55,7 +55,7 @@ interface Svelte2TsxComponentConstructorParameters<Props extends {}> {
55
55
  /**
56
56
  * An HTMLElement to render to. This option is required.
57
57
  */
58
- target: Element;
58
+ target: Element | ShadowRoot;
59
59
  /**
60
60
  * A child of `target` to render the component immediately before.
61
61
  */
@@ -160,7 +160,7 @@ declare function __sveltets_1_with_any_event<Props = {}, Events = {}, Slots = {}
160
160
 
161
161
  declare function __sveltets_1_store_get<T = any>(store: SvelteStore<T>): T
162
162
  declare function __sveltets_1_any(dummy: any): any;
163
- declare function __sveltets_1_empty(dummy: any): {};
163
+ declare function __sveltets_1_empty(...dummy: any[]): {};
164
164
  declare function __sveltets_1_componentType(): AConstructorTypeOf<Svelte2TsxComponent<any, any, any>>
165
165
  declare function __sveltets_1_invalidate<T>(getValue: () => T): T
166
166
 
@@ -204,9 +204,9 @@ declare function __sveltets_1_awaitThen<T>(
204
204
  onrejected?: (value: T extends PromiseLike<any> ? any : never) => any
205
205
  ): any;
206
206
 
207
- declare function __sveltets_1_each<T>(
208
- array: ArrayLike<T>,
209
- callbackfn: (value: T, index: number) => any
207
+ declare function __sveltets_1_each<T extends ArrayLike<unknown>>(
208
+ array: T,
209
+ callbackfn: (value: T extends ArrayLike<infer U> ? U : never, index: number) => any
210
210
  ): any;
211
211
 
212
212
  declare function __sveltets_1_createSvelte2TsxComponent<Props, Events, Slots>(