Skip to content

Commit be04a23

Browse files
authoredDec 14, 2021
Fix error when {#await} with literal (#125)
1 parent d130714 commit be04a23

6 files changed

+12733
-24
lines changed
 

‎src/context/script-let.ts

+50-16
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ export class ScriptLetContext {
337337
| string[]
338338
| ((helper: TypeGenHelper) => {
339339
typings: string[]
340-
preparationScript?: string
340+
preparationScript?: string[]
341341
}),
342342
): void
343343

@@ -353,7 +353,7 @@ export class ScriptLetContext {
353353
| string[]
354354
| ((helper: TypeGenHelper) => {
355355
typings: string[]
356-
preparationScript?: string
356+
preparationScript?: string[]
357357
}),
358358
): void {
359359
let arrayTypings: string[] = []
@@ -366,14 +366,16 @@ export class ScriptLetContext {
366366
})
367367
arrayTypings = generatedTypes.typings
368368
if (generatedTypes.preparationScript) {
369-
this.appendScriptWithoutOffset(
370-
generatedTypes.preparationScript,
371-
(node, tokens, comments, result) => {
372-
tokens.length = 0
373-
comments.length = 0
374-
removeAllReference(node, result)
375-
},
376-
)
369+
for (const preparationScript of generatedTypes.preparationScript) {
370+
this.appendScriptWithoutOffset(
371+
preparationScript,
372+
(node, tokens, comments, result) => {
373+
tokens.length = 0
374+
comments.length = 0
375+
removeAllScope(node, result)
376+
},
377+
)
378+
}
377379
}
378380
}
379381
}
@@ -445,7 +447,7 @@ export class ScriptLetContext {
445447
column: typeAnnotation.loc.start.column,
446448
}
447449

448-
removeAllReference(typeAnnotation, result)
450+
removeAllScope(typeAnnotation, result)
449451
}
450452
}
451453

@@ -869,23 +871,55 @@ function applyLocs(target: Locations | ESTree.Node, locs: Locations) {
869871
}
870872

871873
/** Remove all reference */
872-
function removeAllReference(
873-
target: ESTree.Node,
874-
result: ScriptLetCallbackOption,
875-
) {
874+
function removeAllScope(target: ESTree.Node, result: ScriptLetCallbackOption) {
875+
const targetScopes = new Set<Scope>()
876876
traverseNodes(target, {
877877
visitorKeys: result.visitorKeys,
878878
enterNode(node) {
879+
const scope = result.scopeManager.acquire(node)
880+
if (scope) {
881+
targetScopes.add(scope)
882+
return
883+
}
879884
if (node.type === "Identifier") {
880-
const scope = result.getScope(node)
885+
let scope = result.getScope(node)
886+
if (
887+
(scope.block as any).type === "TSTypeAliasDeclaration" &&
888+
(scope.block as any).id === node
889+
) {
890+
scope = scope.upper!
891+
}
892+
if (targetScopes.has(scope)) {
893+
return
894+
}
881895

896+
removeIdentifierVariable(node, scope)
882897
removeIdentifierReference(node, scope)
883898
}
884899
},
885900
leaveNode() {
886901
// noop
887902
},
888903
})
904+
905+
for (const scope of targetScopes) {
906+
removeScope(result.scopeManager, scope)
907+
}
908+
}
909+
910+
/** Remove variable */
911+
function removeIdentifierVariable(node: ESTree.Identifier, scope: Scope): void {
912+
const varIndex = scope.variables.findIndex((v) =>
913+
v.defs.some((def) => def.name === node),
914+
)
915+
if (varIndex >= 0) {
916+
const variable = scope.variables[varIndex]
917+
scope.variables.splice(varIndex, 1)
918+
const name = node.name
919+
if (variable === scope.set.get(name)) {
920+
scope.set.delete(name)
921+
}
922+
}
889923
}
890924

891925
/** Remove reference */

‎src/parser/converts/block.ts

+26-8
Original file line numberDiff line numberDiff line change
@@ -293,22 +293,29 @@ export function convertAwaitBlock(
293293
},
294294
({ generateUniqueId }) => {
295295
const expression = ctx.getText(node.expression)
296-
if (
297-
node.expression.type === "Identifier" ||
298-
node.expression.type === "Literal"
299-
) {
296+
if (node.expression.type === "Literal") {
300297
return {
298+
typings: [expression],
299+
}
300+
}
301+
const idAwaitThenValue = generateUniqueId("AwaitThenValue")
302+
if (node.expression.type === "Identifier") {
303+
return {
304+
preparationScript: [
305+
generateAwaitThenValueType(idAwaitThenValue),
306+
],
301307
typings: [
302-
`Parameters<Parameters<(typeof ${expression})["then"]>[0]>[0]`,
308+
`${idAwaitThenValue}<(typeof ${expression})>`,
303309
],
304310
}
305311
}
306312
const id = generateUniqueId(expression)
307313
return {
308-
preparationScript: `const ${id} = ${expression};`,
309-
typings: [
310-
`Parameters<Parameters<(typeof ${id})["then"]>[0]>[0]`,
314+
preparationScript: [
315+
`const ${id} = ${expression};`,
316+
generateAwaitThenValueType(idAwaitThenValue),
311317
],
318+
typings: [`${idAwaitThenValue}<(typeof ${id})>`],
312319
}
313320
},
314321
)
@@ -465,3 +472,14 @@ function extractMustacheBlockTokens(
465472
end: endSectionNameEnd,
466473
})
467474
}
475+
476+
/** Generate Awaited like type code */
477+
function generateAwaitThenValueType(id: string) {
478+
return `type ${id}<T> = T extends null | undefined
479+
? T
480+
: T extends { then(value: infer F): any }
481+
? F extends (value: infer V, ...args: any) => any
482+
? ${id}<V>
483+
: never
484+
: T;`
485+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
const str = 'abc' as const
3+
</script>
4+
5+
{#await 1234 then number}
6+
<p>The number is {number}</p>
7+
{/await}
8+
9+
{#await str then s}
10+
<p>The string is {s}</p>
11+
{/await}
12+
13+
{#await str.slice(0) then s}
14+
<p>The string is {s}</p>
15+
{/await}

0 commit comments

Comments
 (0)
Please sign in to comment.