Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type SvelteLogicTag = 'each' | 'if' | 'await' | 'key';
/**
* Special svelte syntax tags.
*/
export type SvelteTag = SvelteLogicTag | 'html' | 'debug';
export type SvelteTag = SvelteLogicTag | 'html' | 'debug' | 'const';

/**
* For each tag, a documentation in markdown format.
Expand Down Expand Up @@ -74,10 +74,15 @@ It logs the values of specific variables whenever they change, ` +
`and pauses code execution if you have devtools open.
It accepts a comma-separated list of variable names (not arbitrary expressions).
#### Usage:
\`{@debug\`}
\`{@debug}\`
\`{@debug var1, var2, ..., varN}\`\\
\\
https://svelte.dev/docs#debug
`,
const: `\`{@const ...}\`\\
TODO
#### Usage:
\`{@const a = b + c}\`\\
`
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ function getCompletionsWithRegardToTriggerCharacter(
if (triggerCharacter === '@') {
return createCompletionItems([
{ tag: 'html', label: 'html' },
{ tag: 'debug', label: 'debug' }
{ tag: 'debug', label: 'debug' },
{ tag: 'const', label: 'const' }
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const tagPossibilities: Array<{ tag: SvelteTag | ':else'; values: string[] }> =
// @
{ tag: 'html' as const, values: ['@html'] },
{ tag: 'debug' as const, values: ['@debug'] },
{ tag: 'const' as const, values: ['@const'] },
// this tag has multiple possibilities
{ tag: ':else' as const, values: [':else'] }
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('SveltePlugin#getCompletions', () => {
});

it('should return completions for @', () => {
expectCompletionsFor('{@').toEqual(['html', 'debug']);
expectCompletionsFor('{@').toEqual(['html', 'debug', 'const']);
});

describe('should return no completions for :', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
[
{
"range": {
"start": { "line": 28, "character": 21 },
"end": { "line": 28, "character": 27 }
},
"severity": 4,
"source": "ts",
"message": "'result' is declared but its value is never read.",
"code": 6133,
"tags": [1]
},
{
"range": {
"start": { "line": 29, "character": 12 },
"end": { "line": 29, "character": 18 }
},
"severity": 4,
"source": "ts",
"message": "'unused' is declared but its value is never read.",
"code": 6133,
"tags": [1]
},
{
"range": { "start": { "line": 32, "character": 8 }, "end": { "line": 32, "character": 9 } },
"severity": 4,
"source": "ts",
"message": "'e' is declared but its value is never read.",
"code": 6133,
"tags": [1]
},
{
"range": {
"start": { "line": 33, "character": 12 },
"end": { "line": 33, "character": 18 }
},
"severity": 4,
"source": "ts",
"message": "'unused' is declared but its value is never read.",
"code": 6133,
"tags": [1]
},
{
"range": {
"start": { "line": 39, "character": 12 },
"end": { "line": 39, "character": 18 }
},
"severity": 4,
"source": "ts",
"message": "'unused' is declared but its value is never read.",
"code": 6133,
"tags": [1]
},
{
"range": {
"start": { "line": 29, "character": 21 },
"end": { "line": 29, "character": 32 }
},
"severity": 1,
"source": "ts",
"message": "Cannot find name 'doesntExist'.",
"code": 2304,
"tags": []
},
{
"range": {
"start": { "line": 31, "character": 5 },
"end": { "line": 31, "character": 17 }
},
"severity": 1,
"source": "ts",
"message": "This condition will always return 'false' since the types 'string' and 'boolean' have no overlap.",
"code": 2367,
"tags": []
},
{
"range": {
"start": { "line": 33, "character": 21 },
"end": { "line": 33, "character": 32 }
},
"severity": 1,
"source": "ts",
"message": "Cannot find name 'doesntExist'.",
"code": 2304,
"tags": []
},
{
"range": {
"start": { "line": 35, "character": 5 },
"end": { "line": 35, "character": 17 }
},
"severity": 1,
"source": "ts",
"message": "This condition will always return 'false' since the types 'string' and 'boolean' have no overlap.",
"code": 2367,
"tags": []
},
{
"range": {
"start": { "line": 39, "character": 21 },
"end": { "line": 39, "character": 32 }
},
"severity": 1,
"source": "ts",
"message": "Cannot find name 'doesntExist'.",
"code": 2304,
"tags": []
},
{
"range": {
"start": { "line": 41, "character": 5 },
"end": { "line": 41, "character": 16 }
},
"severity": 1,
"source": "ts",
"message": "This condition will always return 'false' since the types 'number' and 'string' have no overlap.",
"code": 2367,
"tags": []
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script lang="ts">
const promise = Promise.resolve({foo: true});
const shadowed = true;
shadowed;
</script>

<!-- valid -->
{#await promise then result}
{@const bar = result}
{@const str = "hello"}
{@const shadowed = "shadowed"}
{bar === result}
{str === "hello"}
{shadowed === "shadowed"}
{:catch e}
{@const bar = e}
{@const str = "hello"}
{bar}
{str === "hello"}
{/await}

{#each [1, 2] as item}
{@const x = item * 2}
{@const shadowed = item * 3}
{x === shadowed}
{/each}

<!-- invalid -->
{#await promise then result}
{@const unused = doesntExist}
{@const str = "hello"}
{str === true}
{:catch e}
{@const unused = doesntExist}
{@const str = "hello"}
{str === true}
{/await}

{#each [1, 2] as item}
{@const unused = doesntExist}
{@const x = item * 2}
{x === "asd"}
{/each}
18 changes: 9 additions & 9 deletions packages/svelte2tsx/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ function repl() {
this.addWatchFile(INPUT);
},
writeBundle() {
const BUILD = require.resolve('./index.js');
const BUILD_TEST = require.resolve('./test/build.ts');
try {
const BUILD = require.resolve('./index.js');
const BUILD_TEST = require.resolve('./test/build.ts');

delete require.cache[BUILD];
const { svelte2tsx } = require('./index.js');
delete require.cache[BUILD];
const svelte2tsx = require('./index.js');

delete require.cache[BUILD_TEST];
require.cache[BUILD_TEST] = require.cache[BUILD];
const { process_transformed_text } = require('./test/sourcemaps/process');
delete require.cache[BUILD_TEST];
require.cache[BUILD_TEST] = require.cache[BUILD];
const { process_transformed_text } = require('./test/sourcemaps/process');

const input_content = fs.readFileSync(INPUT, 'utf-8');
const input_content = fs.readFileSync(INPUT, 'utf-8');

try {
const { code, map } = svelte2tsx(input_content);

map.file = 'code.tsx';
Expand Down
21 changes: 9 additions & 12 deletions packages/svelte2tsx/src/htmlxtojsx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { handleSvelteTag } from './nodes/svelte-tag';
import { TemplateScopeManager } from './nodes/template-scope';
import { handleText } from './nodes/text';
import { handleTransitionDirective } from './nodes/transition-directive';
import { usesLet } from './utils/node-utils';

type Walker = (node: TemplateNode, parent: BaseNode, prop: string, index: number) => void;

Expand Down Expand Up @@ -170,17 +169,15 @@ export function convertHtmlxToJsx(
case 'SlotTemplate':
handleSvelteTag(htmlx, str, node);
templateScopeManager.componentOrSlotTemplateOrElementEnter(node);
if (usesLet(node)) {
handleSlot(
htmlx,
str,
node,
parent,
getSlotName(node) || 'default',
ifScope,
templateScopeManager.value
);
}
handleSlot(
htmlx,
str,
node,
parent,
getSlotName(node) || 'default',
ifScope,
templateScopeManager.value
);
break;
case 'Text':
handleText(str, node as Text);
Expand Down
31 changes: 26 additions & 5 deletions packages/svelte2tsx/src/htmlxtojsx/nodes/await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IfScope } from './if-scope';
import { TemplateScopeManager } from './template-scope';
import { surroundWithIgnoreComments } from '../../utils/ignore';
import { BaseNode } from '../../interfaces';
import { extractConstTags } from './const-tag';

/**
* Transform {#await ...} into something JSX understands
Expand Down Expand Up @@ -94,14 +95,22 @@ export function handleAwaitThen(

if (awaitBlock.value) {
str.overwrite(thenStart, awaitBlock.value.start, '__sveltets_1_awaitThen(_$$p, (');
str.overwrite(awaitBlock.value.end, thenEnd, `) => {${ifScope.addPossibleIfCondition()}<>`);
str.overwrite(awaitBlock.value.end, thenEnd, ') => {');
extractConstTags(awaitBlock.then.children).forEach((insertion) => {
insertion(thenEnd, str);
});
str.appendRight(thenEnd, `${ifScope.addPossibleIfCondition()}<>`);
} else {
const awaitThenFn = `__sveltets_1_awaitThen(_$$p, () => {${ifScope.addPossibleIfCondition()}<>`; // eslint-disable-line
const awaitThenFn = '__sveltets_1_awaitThen(_$$p, () => {';
if (thenStart === thenEnd) {
str.appendLeft(thenStart, awaitThenFn);
} else {
str.overwrite(thenStart, thenEnd, awaitThenFn);
}
extractConstTags(awaitBlock.then.children).forEach((insertion) => {
insertion(thenEnd, str);
});
str.appendRight(thenEnd, `${ifScope.addPossibleIfCondition()}<>`); // eslint-disable-line
}
}

Expand All @@ -124,15 +133,23 @@ export function handleAwaitCatch(
awaitBlock.error.start,
'); __sveltets_1_awaitThen(_$$p, () => {}, ('
);
str.overwrite(awaitBlock.error.end, catchBegin, ') => {<>');
str.overwrite(awaitBlock.error.end, catchBegin, ') => {');
extractConstTags(awaitBlock.catch.children).forEach((insertion) => {
insertion(catchBegin, str);
});
str.appendRight(catchBegin, '<>');
} else {
// {#await ... catch}
const catchBegin = htmlx.indexOf('}', awaitBlock.expression.end) + 1;
str.overwrite(
awaitBlock.expression.end,
catchBegin,
'); __sveltets_1_awaitThen(_$$p, () => {}, () => {<>'
'); __sveltets_1_awaitThen(_$$p, () => {}, () => {'
);
extractConstTags(awaitBlock.catch.children).forEach((insertion) => {
insertion(catchBegin, str);
});
str.appendRight(catchBegin, '<>');
}
} else {
//{:catch error} ->
Expand All @@ -146,6 +163,10 @@ export function handleAwaitCatch(
const errorEnd = awaitBlock.error ? awaitBlock.error.end : errorStart;
const catchEnd = htmlx.indexOf('}', errorEnd) + 1;
str.overwrite(catchStart, errorStart, '</>}, (');
str.overwrite(errorEnd, catchEnd, `) => {${ifScope.addPossibleIfCondition()}<>`);
str.overwrite(errorEnd, catchEnd, ') => {');
extractConstTags(awaitBlock.catch.children).forEach((insertion) => {
insertion(catchEnd, str);
});
str.appendRight(catchEnd, `${ifScope.addPossibleIfCondition()}<>`);
}
}
25 changes: 25 additions & 0 deletions packages/svelte2tsx/src/htmlxtojsx/nodes/const-tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import MagicString from 'magic-string';
import { BaseNode, ConstTag } from '../../interfaces';

export function extractConstTags(children: BaseNode[]) {
const tags: Array<(insertionPoint: number, str: MagicString) => void> = [];
for (const child of children) {
if (child.type === 'ConstTag') {
const constTag = child as ConstTag;

tags.push((insertionPoint: number, str: MagicString) => {
str.appendRight(constTag.expression.left.start, 'const ');
str.move(
constTag.expression.left.start,
constTag.expression.right.end,
insertionPoint
);
str.appendLeft(constTag.expression.right.end, ';');
str.overwrite(constTag.start + 1, constTag.expression.left.start - 1, '', {
contentOnly: true
});
});
}
}
return tags;
}
Loading