0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-17 22:44:24 -05:00

add typescript support for expressions

This commit is contained in:
Fred K. Schott 2021-03-22 00:26:59 -07:00
parent f28590e640
commit d125d57b3a
6 changed files with 58 additions and 29 deletions

View file

@ -49,7 +49,7 @@
working on!</div> working on!</div>
</article> </article>
{context.news.reverse().map((item) => {context.news.reverse().map((item: any) =>
<Card:dynamic item={item} />)} <Card:dynamic item={item} />)}
</div> </div>

6
package-lock.json generated
View file

@ -67,9 +67,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.13.10", "version": "7.13.11",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.11.tgz",
"integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ==" "integrity": "sha512-PhuoqeHoO9fc4ffMEVk4qb/w/s2iOSWohvbHxLtxui0eBg3Lg5gN1U8wp1V1u61hOWkPQJJyJzGH6Y+grwkq8Q=="
}, },
"@babel/types": { "@babel/types": {
"version": "7.13.0", "version": "7.13.0",

View file

@ -56,6 +56,7 @@
"yargs-parser": "^20.2.7" "yargs-parser": "^20.2.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/parser": "^7.13.11",
"@types/github-slugger": "^1.3.0", "@types/github-slugger": "^1.3.0",
"@types/sass": "^1.16.0", "@types/sass": "^1.16.0",
"@types/yargs-parser": "^20.2.0", "@types/yargs-parser": "^20.2.0",

View file

@ -146,8 +146,8 @@ function getComponentWrapper(_name: string, { type, url }: { type: string; url:
throw new Error('Unknown Component Type: ' + name); throw new Error('Unknown Component Type: ' + name);
} }
function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string { function compileScriptSafe(raw: string): string {
let compiledCode = compileExpressionSafe(raw, loader); let compiledCode = compileExpressionSafe(raw);
// esbuild treeshakes unused imports. In our case these are components, so let's keep them. // esbuild treeshakes unused imports. In our case these are components, so let's keep them.
const imports = eslexer const imports = eslexer
.parse(raw)[0] .parse(raw)[0]
@ -161,9 +161,9 @@ function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
return compiledCode; return compiledCode;
} }
function compileExpressionSafe(raw: string, loader: 'jsx' | 'tsx'): string { function compileExpressionSafe(raw: string): string {
let { code } = transformSync(raw, { let { code } = transformSync(raw, {
loader, loader: 'tsx',
jsxFactory: 'h', jsxFactory: 'h',
jsxFragment: 'Fragment', jsxFragment: 'Fragment',
charset: 'utf8', charset: 'utf8',
@ -175,7 +175,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
await eslexer.init; await eslexer.init;
// Compile scripts as TypeScript, always // Compile scripts as TypeScript, always
const script = compileScriptSafe(ast.module ? ast.module.content : '', 'tsx'); const script = compileScriptSafe(ast.module ? ast.module.content : '');
// Todo: Validate that `h` and `Fragment` aren't defined in the script // Todo: Validate that `h` and `Fragment` aren't defined in the script
const [scriptImports] = eslexer.parse(script, 'optional-sourcename'); const [scriptImports] = eslexer.parse(script, 'optional-sourcename');
@ -198,7 +198,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
enter(node: TemplateNode) { enter(node: TemplateNode) {
switch (node.type) { switch (node.type) {
case 'MustacheTag': case 'MustacheTag':
let code = compileExpressionSafe(node.expression, 'jsx'); let code = compileExpressionSafe(node.expression);
let matches: RegExpExecArray[] = []; let matches: RegExpExecArray[] = [];
let match: RegExpExecArray | null | undefined; let match: RegExpExecArray | null | undefined;

View file

@ -1,20 +1,49 @@
import { Node } from 'acorn'; import type { Node } from 'acorn';
import acorn from 'acorn'; import { parseExpression } from '@babel/parser';
// @ts-ignore // import acorn from 'acorn';
import jsx from 'acorn-jsx'; // // @ts-ignore
// import jsx from 'acorn-jsx';
// const acornJsx = acorn.Parser.extend(jsx());
const acornJsx = acorn.Parser.extend(jsx()); export const parse = (source: string): Node => {
throw new Error('No longer used.');
// acorn.parse(source, {
// sourceType: 'module',
// ecmaVersion: 2020,
// locations: true,
// });
};
export const parse = (source: string): Node => export const parse_expression_at = (source: string, index: number) => {
acorn.parse(source, { // TODO: Clean up after acorn -> @babel/parser move
sourceType: 'module', try {
ecmaVersion: 2020, parseExpression(source.slice(index), {
locations: true, sourceType: 'module',
}); plugins: ['jsx', 'typescript'],
});
export const parse_expression_at = (source: string, index: number): Node => throw new Error('Parse error.'); // Expected to fail.
acornJsx.parseExpressionAt(source, index, { } catch (err) {
sourceType: 'module', if (!err.pos) {
ecmaVersion: 2020, throw err;
locations: true, }
}); try {
const result = parseExpression(source.slice(index, index + err.pos), {
sourceType: 'module',
plugins: ['jsx', 'typescript'],
});
result.start = index;
result.end = index + err.pos;
return result;
} catch (err2) {
if (err2.pos) {
err2.pos = index + err2.pos;
}
throw err2;
}
}
};
// acornJsx.parseExpressionAt(source, index, {
// sourceType: 'module',
// ecmaVersion: 2020,
// locations: true,
// });

View file

@ -8,7 +8,6 @@ import { whitespace } from '../../utils/patterns.js';
export default function read_expression(parser: Parser): string { export default function read_expression(parser: Parser): string {
try { try {
const node = parse_expression_at(parser.template, parser.index); const node = parse_expression_at(parser.template, parser.index);
let num_parens = 0; let num_parens = 0;
for (let i = parser.index; i < node.start; i += 1) { for (let i = parser.index; i < node.start; i += 1) {