Skip to content

Commit

Permalink
(feat) support new const tag (#1072)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau authored Jan 13, 2022
1 parent e4c2194 commit 7c7f9d7
Show file tree
Hide file tree
Showing 32 changed files with 717 additions and 56 deletions.
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

0 comments on commit 7c7f9d7

Please sign in to comment.