diff --git a/packages/adders/drizzle/index.ts b/packages/adders/drizzle/index.ts index 8b651969..2ccc9026 100644 --- a/packages/adders/drizzle/index.ts +++ b/packages/adders/drizzle/index.ts @@ -229,8 +229,8 @@ export default defineAdder({ url: common.expressionFromString('process.env.DATABASE_URL'), authToken }), - verbose: { type: 'BooleanLiteral', value: true }, - strict: { type: 'BooleanLiteral', value: true }, + verbose: { type: 'Literal', value: true }, + strict: { type: 'Literal', value: true }, driver }); diff --git a/packages/adders/eslint/index.ts b/packages/adders/eslint/index.ts index 00aede29..a25d10a4 100644 --- a/packages/adders/eslint/index.ts +++ b/packages/adders/eslint/index.ts @@ -9,7 +9,6 @@ import { functions, imports, object, - type AstKinds, type AstTypes } from '@sveltejs/cli-core/js'; import { parseJson, parseScript } from '@sveltejs/cli-core/parsers'; @@ -71,7 +70,7 @@ export default defineAdder({ const { ast, generateCode } = parseScript(content); const eslintConfigs: Array< - AstKinds.ExpressionKind | AstTypes.SpreadElement | AstTypes.ObjectExpression + AstTypes.Expression | AstTypes.SpreadElement | AstTypes.ObjectExpression > = []; const jsConfig = common.expressionFromString('js.configs.recommended'); diff --git a/packages/adders/lucia/index.ts b/packages/adders/lucia/index.ts index 7f689c53..2abae0ab 100644 --- a/packages/adders/lucia/index.ts +++ b/packages/adders/lucia/index.ts @@ -61,17 +61,17 @@ export default defineAdder({ name: ({ typescript }) => `drizzle.config.${typescript ? 'ts' : 'js'}`, content: ({ content }) => { const { ast, generateCode } = parseScript(content); - const isProp = (name: string, node: AstTypes.ObjectProperty) => + const isProp = (name: string, node: AstTypes.Property) => node.key.type === 'Identifier' && node.key.name === name; // prettier-ignore - Walker.walk(ast as AstTypes.ASTNode, {}, { - ObjectProperty(node) { - if (isProp('dialect', node) && node.value.type === 'StringLiteral') { + Walker.walk(ast as AstTypes.Node, {}, { + Property(node) { + if (isProp('dialect', node) && node.value.type === 'Literal') { drizzleDialect = node.value.value as Dialect; } - if (isProp('schema', node) && node.value.type === 'StringLiteral') { - schemaPath = node.value.value; + if (isProp('schema', node) && node.value.type === 'Literal') { + schemaPath = node.value.value as string; } } }) @@ -549,6 +549,7 @@ function createLuciaType(name: string): AstTypes.TSInterfaceBody['body'][number] type: 'Identifier', name }, + computed: false, typeAnnotation: { type: 'TSTypeAnnotation', typeAnnotation: { @@ -556,7 +557,7 @@ function createLuciaType(name: string): AstTypes.TSInterfaceBody['body'][number] types: [ { type: 'TSImportType', - argument: { type: 'StringLiteral', value: 'lucia' }, + argument: { type: 'Literal', value: 'lucia' }, qualifier: { type: 'Identifier', // capitalize first letter @@ -603,7 +604,7 @@ function getAuthHandleContent() { };`; } -function getCallExpression(ast: AstTypes.ASTNode): AstTypes.CallExpression | undefined { +function getCallExpression(ast: AstTypes.Node): AstTypes.CallExpression | undefined { let callExpression; // prettier-ignore diff --git a/packages/adders/vitest/index.ts b/packages/adders/vitest/index.ts index 2a991560..e1e3535d 100644 --- a/packages/adders/vitest/index.ts +++ b/packages/adders/vitest/index.ts @@ -55,7 +55,9 @@ export default defineAdder({ importDecl.importKind === 'value' && importDecl.specifiers?.some( (specifier) => - specifier.type === 'ImportSpecifier' && specifier.imported.name === 'defineConfig' + specifier.type === 'ImportSpecifier' && + specifier.imported.type == 'Identifier' && + specifier.imported.name === 'defineConfig' ) ); @@ -67,7 +69,10 @@ export default defineAdder({ } else { // otherwise, just remove the `defineConfig` specifier const idxToRemove = defineConfigImportDecl?.specifiers?.findIndex( - (s) => s.type === 'ImportSpecifier' && s.imported.name === 'defineConfig' + (specifier) => + specifier.type === 'ImportSpecifier' && + specifier.imported.type == 'Identifier' && + specifier.imported.name === 'defineConfig' ); if (idxToRemove) defineConfigImportDecl?.specifiers?.splice(idxToRemove, 1); } @@ -86,7 +91,10 @@ export default defineAdder({ ) { // if the previous `defineConfig` was aliased, reuse the alias for the "vitest/config" import const importSpecifier = defineConfigImportDecl?.specifiers?.find( - (sp) => sp.type === 'ImportSpecifier' && sp.imported.name === 'defineConfig' + (specifier) => + specifier.type === 'ImportSpecifier' && + specifier.imported.type == 'Identifier' && + specifier.imported.name === 'defineConfig' ); const defineConfigAlias = importSpecifier?.local?.name ?? 'defineConfig'; imports.addNamed(ast, 'vitest/config', { defineConfig: defineConfigAlias }); diff --git a/packages/ast-tooling/index.ts b/packages/ast-tooling/index.ts index 110ca956..e95f26d2 100644 --- a/packages/ast-tooling/index.ts +++ b/packages/ast-tooling/index.ts @@ -1,5 +1,3 @@ -import { parse as tsParse } from 'recast/parsers/typescript.js'; -import { parse as recastParse, print as recastPrint } from 'recast'; import { Document, Element, Text, type ChildNode } from 'domhandler'; import { ElementType, parseDocument } from 'htmlparser2'; import { appendChild, prependChild, removeElement, textContent } from 'domutils'; @@ -15,8 +13,11 @@ import { } from 'postcss'; import * as fleece from 'silver-fleece'; import * as Walker from 'zimmerframe'; -import type { namedTypes as AstTypes } from 'ast-types'; -import type * as AstKinds from 'ast-types/gen/kinds.d.ts'; +import * as acorn from 'acorn'; +import { tsPlugin } from 'acorn-typescript'; +import { print as esrapPrint } from 'esrap-typescript-temp'; +// todo: why is this file only generated during `dev` startup, if it's prefixed with type? +import { TsEstree } from './ts-estree.ts'; /** * Most of the AST tooling is pretty big in bundle size and bundling takes forever. @@ -48,25 +49,70 @@ export type { ChildNode as HtmlChildNode, // js - AstTypes, - AstKinds, + TsEstree as AstTypes, //css CssChildNode }; -export function parseScript(content: string): AstTypes.Program { - const recastOutput: { program: AstTypes.Program } = recastParse(content, { - parser: { - parse: tsParse +export function parseScript(content: string): TsEstree.Program { + const comments: any[] = []; + + // @ts-expect-error + const acornTs = acorn.Parser.extend(tsPlugin({ allowSatisfies: true })); + + const ast = acornTs.parse(content, { + ecmaVersion: 'latest', + sourceType: 'module', + locations: true, + onComment: (block, value, start, end) => { + if (block && /\n/.test(value)) { + let a = start; + while (a > 0 && content[a - 1] !== '\n') a -= 1; + + let b = a; + // @ts-expect-error + while (/[ \t]/.test(content[b])) b += 1; + + const indentation = content.slice(a, b); + value = value.replace(new RegExp(`^${indentation}`, 'gm'), ''); + } + + comments.push({ type: block ? 'Block' : 'Line', value, start, end }); + } + }); + + Walker.walk(ast, null, { + _(node, { next }) { + const commentNode /** @type {import('../../src/types').NodeWithComments} */ = + /** @type {any} */ node; + let comment; + + while (comments[0] && comments[0].start < node.start) { + comment = comments.shift(); + // @ts-expect-error + (commentNode.leadingComments ||= []).push(comment); + } + + next(); + + if (comments[0]) { + const slice = content.slice(node.end, comments[0].start); + + if (/^[,) \t]*$/.test(slice)) { + // @ts-expect-error + commentNode.trailingComments = [comments.shift()]; + } + } } }); - return recastOutput.program; + return ast as TsEstree.Program; } -export function serializeScript(ast: AstTypes.ASTNode): string { - return recastPrint(ast).code; +export function serializeScript(ast: TsEstree.Node): string { + const { code } = esrapPrint(ast, {}); + return code; } export function parseCss(content: string): CssAst { @@ -108,7 +154,7 @@ export function stripAst(node: T, propToRemove: string): T { } export type SvelteAst = { - jsAst: AstTypes.Program; + jsAst: TsEstree.Program; htmlAst: Document; cssAst: CssAst; }; diff --git a/packages/ast-tooling/package.json b/packages/ast-tooling/package.json index 80cb4397..29220bb3 100644 --- a/packages/ast-tooling/package.json +++ b/packages/ast-tooling/package.json @@ -19,14 +19,15 @@ "dist" ], "devDependencies": { - "@babel/parser": "^7.24.7", - "ast-types": "^0.14.2", + "@types/estree": "^1.0.6", + "acorn": "^8.12.1", + "acorn-typescript": "^1.4.13", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", + "esrap-typescript-temp": "^0.0.1", "htmlparser2": "^9.1.0", "postcss": "^8.4.38", - "recast": "^0.23.7", "silver-fleece": "^1.1.0", "zimmerframe": "^1.1.2" }, diff --git a/packages/ast-tooling/ts-estree.ts b/packages/ast-tooling/ts-estree.ts new file mode 100644 index 00000000..919cc91e --- /dev/null +++ b/packages/ast-tooling/ts-estree.ts @@ -0,0 +1,79 @@ +import type * as estree from 'estree'; + +declare module 'estree' { + // new types + interface TSTypeAnnotation { + type: 'TSTypeAnnotation'; + typeAnnotation: TSStringKeyword | TSTypeReference | TSUnionType; + } + interface TSStringKeyword { + type: 'TSStringKeyword'; + } + interface TSNullKeyword { + type: 'TSNullKeyword'; + } + interface TSTypeReference { + type: 'TSTypeReference'; + typeName: Identifier; + } + interface TSAsExpression extends BaseNode { + type: 'TSAsExpression'; + expression: Expression; + typeAnnotation: TSTypeAnnotation['typeAnnotation']; + } + interface TSModuleDeclaration extends BaseNode { + type: 'TSModuleDeclaration'; + global: boolean; + declare: boolean; + id: Identifier; + body: TSModuleBlock; + } + interface TSModuleBlock extends BaseNode { + type: 'TSModuleBlock'; + body: Array; + } + interface TSInterfaceDeclaration extends BaseNode { + type: 'TSInterfaceDeclaration'; + id: Identifier; + body: TSInterfaceBody; + } + interface TSInterfaceBody extends BaseNode { + type: 'TSInterfaceBody'; + body: TSPropertySignature[]; + } + interface TSPropertySignature extends BaseNode { + type: 'TSPropertySignature'; + computed: boolean; + key: Identifier; + typeAnnotation: TSTypeAnnotation; + } + interface TSProgram extends Omit { + body: Array; + } + interface TSUnionType { + type: 'TSUnionType'; + types: Array; + } + interface TSImportType { + type: 'TSImportType'; + argument: Literal; + qualifier: Identifier; + } + + // enhanced types + interface Identifier { + typeAnnotation?: TSTypeAnnotation; + } + interface ExpressionMap { + TSAsExpression: TSAsExpression; + } + interface NodeMap { + TSModuleDeclaration: TSModuleDeclaration; + TSInterfaceDeclaration: TSInterfaceDeclaration; + } + interface ImportDeclaration { + importKind: 'type' | 'value'; + } +} + +export type { estree as TsEstree }; diff --git a/packages/core/tests/css/common/add-at-rule/run.ts b/packages/core/tests/css/common/add-at-rule/run.ts index fd53c285..11de1450 100644 --- a/packages/core/tests/css/common/add-at-rule/run.ts +++ b/packages/core/tests/css/common/add-at-rule/run.ts @@ -1,7 +1,7 @@ import { addAtRule } from '@sveltejs/cli-core/css'; -import type { CssFileEditor } from '@sveltejs/cli-core'; +import type { CssAst } from '@sveltejs/ast-tooling'; -export function run({ ast }: CssFileEditor): void { +export function run(ast: CssAst): void { addAtRule(ast, 'tailwind', "'lib/path/file.ext'", false); addAtRule(ast, 'tailwind', "'lib/path/file1.ext'", true); } diff --git a/packages/core/tests/css/common/add-comment/run.ts b/packages/core/tests/css/common/add-comment/run.ts index b8481ab4..5f8d4999 100644 --- a/packages/core/tests/css/common/add-comment/run.ts +++ b/packages/core/tests/css/common/add-comment/run.ts @@ -1,6 +1,6 @@ import { addComment } from '@sveltejs/cli-core/css'; -import type { CssFileEditor } from '@sveltejs/cli-core'; +import type { CssAst } from '@sveltejs/ast-tooling'; -export function run({ ast }: CssFileEditor): void { +export function run(ast: CssAst): void { addComment(ast, 'foo comment'); } diff --git a/packages/core/tests/css/common/add-imports/run.ts b/packages/core/tests/css/common/add-imports/run.ts index 12b0033a..18ccb618 100644 --- a/packages/core/tests/css/common/add-imports/run.ts +++ b/packages/core/tests/css/common/add-imports/run.ts @@ -1,6 +1,6 @@ import { addImports } from '@sveltejs/cli-core/css'; -import type { CssFileEditor } from '@sveltejs/cli-core'; +import type { CssAst } from '@sveltejs/ast-tooling'; -export function run({ ast }: CssFileEditor): void { +export function run(ast: CssAst): void { addImports(ast, ["'lib/path/file.css'"]); } diff --git a/packages/core/tests/css/common/add-rule/run.ts b/packages/core/tests/css/common/add-rule/run.ts index 7639c5c4..57c83df3 100644 --- a/packages/core/tests/css/common/add-rule/run.ts +++ b/packages/core/tests/css/common/add-rule/run.ts @@ -1,7 +1,7 @@ import { addDeclaration, addRule } from '@sveltejs/cli-core/css'; -import type { CssFileEditor } from '@sveltejs/cli-core'; +import type { CssAst } from '@sveltejs/ast-tooling'; -export function run({ ast }: CssFileEditor): void { +export function run(ast: CssAst): void { const barSelectorRule = addRule(ast, '.bar'); addDeclaration(barSelectorRule, 'color', 'blue'); } diff --git a/packages/core/tests/css/index.ts b/packages/core/tests/css/index.ts index 738e1cb8..3880e5eb 100644 --- a/packages/core/tests/css/index.ts +++ b/packages/core/tests/css/index.ts @@ -20,7 +20,7 @@ for (const categoryDirectory of categoryDirectories) { // dynamic imports always need to provide the path inline for static analysis const module = await import(`./${categoryDirectory}/${testName}/run.ts`); - module.run({ ast }); + module.run(ast); const output = serializeCss(ast); await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.css`); diff --git a/packages/core/tests/html/common/create-div/run.ts b/packages/core/tests/html/common/create-div/run.ts index 36a582bd..4e4d9642 100644 --- a/packages/core/tests/html/common/create-div/run.ts +++ b/packages/core/tests/html/common/create-div/run.ts @@ -1,7 +1,6 @@ -import { div, appendElement, insertElement } from '@sveltejs/cli-core/html'; -import type { HtmlFileEditor } from '@sveltejs/cli-core'; +import { div, appendElement, insertElement, type HtmlDocument } from '@sveltejs/cli-core/html'; -export function run({ ast }: HtmlFileEditor): void { +export function run(ast: HtmlDocument): void { const emptyDiv = div(); insertElement(ast.childNodes, emptyDiv); appendElement(ast.childNodes, emptyDiv); diff --git a/packages/core/tests/html/common/create-element/run.ts b/packages/core/tests/html/common/create-element/run.ts index 12658d28..99205f4d 100644 --- a/packages/core/tests/html/common/create-element/run.ts +++ b/packages/core/tests/html/common/create-element/run.ts @@ -1,7 +1,6 @@ -import { element, appendElement, insertElement } from '@sveltejs/cli-core/html'; -import type { HtmlFileEditor } from '@sveltejs/cli-core'; +import { element, appendElement, insertElement, type HtmlDocument } from '@sveltejs/cli-core/html'; -export function run({ ast }: HtmlFileEditor): void { +export function run(ast: HtmlDocument): void { const emptySpan = element('span'); insertElement(ast.childNodes, emptySpan); appendElement(ast.childNodes, emptySpan); diff --git a/packages/core/tests/html/common/from-raw/run.ts b/packages/core/tests/html/common/from-raw/run.ts index d1cfa163..3270c972 100644 --- a/packages/core/tests/html/common/from-raw/run.ts +++ b/packages/core/tests/html/common/from-raw/run.ts @@ -1,6 +1,5 @@ -import { addFromRawHtml } from '@sveltejs/cli-core/html'; -import type { HtmlFileEditor } from '@sveltejs/cli-core'; +import { addFromRawHtml, type HtmlDocument } from '@sveltejs/cli-core/html'; -export function run({ ast }: HtmlFileEditor): void { +export function run(ast: HtmlDocument): void { addFromRawHtml(ast.childNodes, '
foo
'); } diff --git a/packages/core/tests/html/index.ts b/packages/core/tests/html/index.ts index 6719acd4..d3d7707c 100644 --- a/packages/core/tests/html/index.ts +++ b/packages/core/tests/html/index.ts @@ -20,7 +20,7 @@ for (const categoryDirectory of categoryDirectories) { // dynamic imports always need to provide the path inline for static analysis const module = await import(`./${categoryDirectory}/${testName}/run.ts`); - module.run({ ast }); + module.run(ast); const output = serializeHtml(ast); await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.html`); diff --git a/packages/core/tests/js/arrays/empty-array/run.ts b/packages/core/tests/js/arrays/empty-array/run.ts index d3b4a0b1..0d4241da 100644 --- a/packages/core/tests/js/arrays/empty-array/run.ts +++ b/packages/core/tests/js/arrays/empty-array/run.ts @@ -1,7 +1,6 @@ -import { array, variables } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { array, variables, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const emptyArray = array.createEmpty(); // create declaration so that we serialize everything diff --git a/packages/core/tests/js/arrays/object-array/output.ts b/packages/core/tests/js/arrays/object-array/output.ts index ed083891..abe02af1 100644 --- a/packages/core/tests/js/arrays/object-array/output.ts +++ b/packages/core/tests/js/arrays/object-array/output.ts @@ -1,5 +1 @@ -const array = [{ - test: true -}, { - test2: "string" -}]; +const array = [{ test: true }, { test2: "string" }]; \ No newline at end of file diff --git a/packages/core/tests/js/arrays/object-array/run.ts b/packages/core/tests/js/arrays/object-array/run.ts index 622cc377..26ba00e8 100644 --- a/packages/core/tests/js/arrays/object-array/run.ts +++ b/packages/core/tests/js/arrays/object-array/run.ts @@ -1,7 +1,6 @@ -import { array, object, common, variables } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { array, object, common, variables, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const array1 = array.createEmpty(); const object1 = object.create({ test: common.expressionFromString('true') }); diff --git a/packages/core/tests/js/arrays/string-array/run.ts b/packages/core/tests/js/arrays/string-array/run.ts index 9d779482..80d5ea12 100644 --- a/packages/core/tests/js/arrays/string-array/run.ts +++ b/packages/core/tests/js/arrays/string-array/run.ts @@ -1,7 +1,6 @@ -import { array, variables } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { array, variables, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const array1 = array.createEmpty(); array.push(array1, 'test'); array.push(array1, 'test2'); diff --git a/packages/core/tests/js/exports/default-export-with-variable/output.ts b/packages/core/tests/js/exports/default-export-with-variable/output.ts index 14a059d1..8bbe7280 100644 --- a/packages/core/tests/js/exports/default-export-with-variable/output.ts +++ b/packages/core/tests/js/exports/default-export-with-variable/output.ts @@ -1,5 +1,3 @@ -const object = { - test: "string" -}; +const object = { test: "string" }; export default object; \ No newline at end of file diff --git a/packages/core/tests/js/exports/default-export-with-variable/run.ts b/packages/core/tests/js/exports/default-export-with-variable/run.ts index 89137ad3..6515509e 100644 --- a/packages/core/tests/js/exports/default-export-with-variable/run.ts +++ b/packages/core/tests/js/exports/default-export-with-variable/run.ts @@ -1,7 +1,6 @@ -import { object, common, variables, exports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { object, common, variables, exports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const object1 = object.create({ test: common.createLiteral('string') }); diff --git a/packages/core/tests/js/exports/default-export/output.ts b/packages/core/tests/js/exports/default-export/output.ts index 3811fee1..60044a85 100644 --- a/packages/core/tests/js/exports/default-export/output.ts +++ b/packages/core/tests/js/exports/default-export/output.ts @@ -1,3 +1 @@ -export default { - test: "string" -}; \ No newline at end of file +export default { test: "string" }; \ No newline at end of file diff --git a/packages/core/tests/js/exports/default-export/run.ts b/packages/core/tests/js/exports/default-export/run.ts index 7e350fb2..8e0d9fc1 100644 --- a/packages/core/tests/js/exports/default-export/run.ts +++ b/packages/core/tests/js/exports/default-export/run.ts @@ -1,7 +1,6 @@ -import { object, common, exports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { object, common, exports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const object1 = object.create({ test: common.createLiteral('string') }); diff --git a/packages/core/tests/js/exports/named-export-with-existing/output.ts b/packages/core/tests/js/exports/named-export-with-existing/output.ts index 9bcf50f5..6f504226 100644 --- a/packages/core/tests/js/exports/named-export-with-existing/output.ts +++ b/packages/core/tests/js/exports/named-export-with-existing/output.ts @@ -1,4 +1 @@ -export const named = { - test: 'string', - test2: "string2" -}; \ No newline at end of file +export const named = { test: 'string', test2: "string2" }; \ No newline at end of file diff --git a/packages/core/tests/js/exports/named-export-with-existing/run.ts b/packages/core/tests/js/exports/named-export-with-existing/run.ts index 6f8b8c1c..fc0609f2 100644 --- a/packages/core/tests/js/exports/named-export-with-existing/run.ts +++ b/packages/core/tests/js/exports/named-export-with-existing/run.ts @@ -1,7 +1,6 @@ import { common, variables, object, exports, type AstTypes } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const variableFallback = variables.declaration(ast, 'const', 'variable', object.createEmpty()); const existingExport = exports.namedExport(ast, 'named', variableFallback); diff --git a/packages/core/tests/js/exports/named-export/output.ts b/packages/core/tests/js/exports/named-export/output.ts index 937841dc..3a8a9906 100644 --- a/packages/core/tests/js/exports/named-export/output.ts +++ b/packages/core/tests/js/exports/named-export/output.ts @@ -1,7 +1,2 @@ -export const variable = { - test: "string" -}; - -export const variable2 = { - test2: "string2" -}; \ No newline at end of file +export const variable = { test: "string" }; +export const variable2 = { test2: "string2" }; \ No newline at end of file diff --git a/packages/core/tests/js/exports/named-export/run.ts b/packages/core/tests/js/exports/named-export/run.ts index ead2b2d5..67d468df 100644 --- a/packages/core/tests/js/exports/named-export/run.ts +++ b/packages/core/tests/js/exports/named-export/run.ts @@ -1,7 +1,6 @@ -import { common, variables, object, exports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { common, variables, object, exports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const object1 = object.create({ test: common.createLiteral('string') }); diff --git a/packages/core/tests/js/functions/arrow-function/output.ts b/packages/core/tests/js/functions/arrow-function/output.ts index c74b611e..766f9934 100644 --- a/packages/core/tests/js/functions/arrow-function/output.ts +++ b/packages/core/tests/js/functions/arrow-function/output.ts @@ -1,6 +1,6 @@ () => console.log('foo'); () => { - console.log('foo'); - console.log('bar'); + console.log('foo'); + console.log('bar'); }; \ No newline at end of file diff --git a/packages/core/tests/js/functions/arrow-function/run.ts b/packages/core/tests/js/functions/arrow-function/run.ts index 56250235..5856f8bb 100644 --- a/packages/core/tests/js/functions/arrow-function/run.ts +++ b/packages/core/tests/js/functions/arrow-function/run.ts @@ -1,7 +1,6 @@ -import { functions, common } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { functions, common, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const insideExpression = common.expressionFromString("console.log('foo')"); const functionCall = functions.arrowFunction(false, insideExpression); const expression = common.expressionStatement(functionCall); diff --git a/packages/core/tests/js/functions/function-call-by-identifier/output.ts b/packages/core/tests/js/functions/function-call-by-identifier/output.ts index 8b54d5a3..9a883838 100644 --- a/packages/core/tests/js/functions/function-call-by-identifier/output.ts +++ b/packages/core/tests/js/functions/function-call-by-identifier/output.ts @@ -3,4 +3,5 @@ function foo(bar: string) { } const a = 'bar'; -foo(a); + +foo(a); \ No newline at end of file diff --git a/packages/core/tests/js/functions/function-call-by-identifier/run.ts b/packages/core/tests/js/functions/function-call-by-identifier/run.ts index 28ef6ceb..ebbb3734 100644 --- a/packages/core/tests/js/functions/function-call-by-identifier/run.ts +++ b/packages/core/tests/js/functions/function-call-by-identifier/run.ts @@ -1,7 +1,6 @@ -import { functions, common } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { functions, common, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const functionCall = functions.callByIdentifier('foo', ['a']); const expression = common.expressionStatement(functionCall); ast.body.push(expression); diff --git a/packages/core/tests/js/functions/function-call/output.ts b/packages/core/tests/js/functions/function-call/output.ts index 6a886f44..33f6bd7a 100644 --- a/packages/core/tests/js/functions/function-call/output.ts +++ b/packages/core/tests/js/functions/function-call/output.ts @@ -1,4 +1,5 @@ function foo(bar: string) { console.log(bar); } + foo("bar"); \ No newline at end of file diff --git a/packages/core/tests/js/functions/function-call/run.ts b/packages/core/tests/js/functions/function-call/run.ts index acce02d3..41fe064e 100644 --- a/packages/core/tests/js/functions/function-call/run.ts +++ b/packages/core/tests/js/functions/function-call/run.ts @@ -1,7 +1,6 @@ -import { functions, common } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { functions, common, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const functionCall = functions.call('foo', ['bar']); const expression = common.expressionStatement(functionCall); ast.body.push(expression); diff --git a/packages/core/tests/js/imports/avoid-duplicating-imports/run.ts b/packages/core/tests/js/imports/avoid-duplicating-imports/run.ts index 496abb10..faacdcda 100644 --- a/packages/core/tests/js/imports/avoid-duplicating-imports/run.ts +++ b/packages/core/tests/js/imports/avoid-duplicating-imports/run.ts @@ -1,7 +1,6 @@ -import { imports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { imports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { imports.addEmpty(ast, 'package/file.js'); imports.addDefault(ast, 'package', 'MyPackage'); imports.addNamed(ast, 'package2', { Named: 'Named' }); diff --git a/packages/core/tests/js/imports/default-import/run.ts b/packages/core/tests/js/imports/default-import/run.ts index 003f65bd..7f50dd3b 100644 --- a/packages/core/tests/js/imports/default-import/run.ts +++ b/packages/core/tests/js/imports/default-import/run.ts @@ -1,6 +1,5 @@ -import { imports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { imports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { imports.addDefault(ast, 'package', 'MyPackage'); } diff --git a/packages/core/tests/js/imports/empty-import/run.ts b/packages/core/tests/js/imports/empty-import/run.ts index 4d89d304..505bce37 100644 --- a/packages/core/tests/js/imports/empty-import/run.ts +++ b/packages/core/tests/js/imports/empty-import/run.ts @@ -1,7 +1,6 @@ -import { imports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { imports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { imports.addEmpty(ast, './relativ/file.css'); // allow importing from npm packages diff --git a/packages/core/tests/js/imports/named-import-merging/run.ts b/packages/core/tests/js/imports/named-import-merging/run.ts index 29aeac9b..c6cb2c65 100644 --- a/packages/core/tests/js/imports/named-import-merging/run.ts +++ b/packages/core/tests/js/imports/named-import-merging/run.ts @@ -1,6 +1,5 @@ -import { imports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { imports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { imports.addNamed(ast, 'package', { namedTwo: 'namedTwo' }, false); } diff --git a/packages/core/tests/js/imports/named-import/run.ts b/packages/core/tests/js/imports/named-import/run.ts index 163c9c42..f16bd0e9 100644 --- a/packages/core/tests/js/imports/named-import/run.ts +++ b/packages/core/tests/js/imports/named-import/run.ts @@ -1,7 +1,6 @@ -import { imports } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { imports, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { imports.addNamed(ast, 'package', { namedOne: 'namedOne' }, false); imports.addNamed(ast, '@sveltejs/kit', { Handle: 'Handle' }, false); diff --git a/packages/core/tests/js/index.ts b/packages/core/tests/js/index.ts index a1ab2ed5..e0edcd98 100644 --- a/packages/core/tests/js/index.ts +++ b/packages/core/tests/js/index.ts @@ -20,7 +20,7 @@ for (const categoryDirectory of categoryDirectories) { // dynamic imports always need to provide the path inline for static analysis const module = await import(`./${categoryDirectory}/${testName}/run.ts`); - module.run({ ast }); + module.run(ast); const output = serializeScript(ast); await expect(output).toMatchFileSnapshot(`${testDirectoryPath}/output.ts`); diff --git a/packages/core/tests/js/object/create/output.ts b/packages/core/tests/js/object/create/output.ts index 7ae0ab02..fe84f3fe 100644 --- a/packages/core/tests/js/object/create/output.ts +++ b/packages/core/tests/js/object/create/output.ts @@ -1,6 +1,2 @@ const empty = {}; - -const created = { - foo: 1, - bar: "string" -}; \ No newline at end of file +const created = { foo: 1, bar: "string" }; \ No newline at end of file diff --git a/packages/core/tests/js/object/create/run.ts b/packages/core/tests/js/object/create/run.ts index 8bd864b4..f5b51c32 100644 --- a/packages/core/tests/js/object/create/run.ts +++ b/packages/core/tests/js/object/create/run.ts @@ -1,7 +1,6 @@ -import { variables, object, common } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { variables, object, common, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const emptyObject = object.createEmpty(); const emptyVariable = variables.declaration(ast, 'const', 'empty', emptyObject); ast.body.push(emptyVariable); diff --git a/packages/core/tests/js/object/override-property/output.ts b/packages/core/tests/js/object/override-property/output.ts index d759f951..107e01e5 100644 --- a/packages/core/tests/js/object/override-property/output.ts +++ b/packages/core/tests/js/object/override-property/output.ts @@ -1,5 +1 @@ -const test = { - foo: 2, - bar: "string2", - lorem: false -} \ No newline at end of file +const test = { foo: 2, bar: "string2", lorem: false }; \ No newline at end of file diff --git a/packages/core/tests/js/object/override-property/run.ts b/packages/core/tests/js/object/override-property/run.ts index 8ab3425c..9f284df3 100644 --- a/packages/core/tests/js/object/override-property/run.ts +++ b/packages/core/tests/js/object/override-property/run.ts @@ -1,7 +1,6 @@ import { variables, object, common, type AstTypes } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const variable = variables.declaration(ast, 'const', 'test', object.createEmpty()); const objectDeclarator = variable.declarations[0] as AstTypes.VariableDeclarator; const objectExpression = objectDeclarator.init as AstTypes.ObjectExpression; diff --git a/packages/core/tests/js/object/property/output.ts b/packages/core/tests/js/object/property/output.ts index 022a2a8b..a6d02e00 100644 --- a/packages/core/tests/js/object/property/output.ts +++ b/packages/core/tests/js/object/property/output.ts @@ -1,4 +1 @@ -const test = { - foo: 1, - bar: "string" -} \ No newline at end of file +const test = { foo: 1, bar: "string" }; \ No newline at end of file diff --git a/packages/core/tests/js/object/property/run.ts b/packages/core/tests/js/object/property/run.ts index c288c301..59866dfe 100644 --- a/packages/core/tests/js/object/property/run.ts +++ b/packages/core/tests/js/object/property/run.ts @@ -1,7 +1,6 @@ import { variables, object, common, type AstTypes } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const variable = variables.declaration(ast, 'const', 'test', object.createEmpty()); const objectDeclarator = variable.declarations[0] as AstTypes.VariableDeclarator; const objectExpression = objectDeclarator.init as AstTypes.ObjectExpression; diff --git a/packages/core/tests/js/object/remove-property/output.ts b/packages/core/tests/js/object/remove-property/output.ts index e51fe4a1..16531108 100644 --- a/packages/core/tests/js/object/remove-property/output.ts +++ b/packages/core/tests/js/object/remove-property/output.ts @@ -1 +1 @@ -const test = {} +const test = {}; \ No newline at end of file diff --git a/packages/core/tests/js/object/remove-property/run.ts b/packages/core/tests/js/object/remove-property/run.ts index 0971c07a..d5c38e04 100644 --- a/packages/core/tests/js/object/remove-property/run.ts +++ b/packages/core/tests/js/object/remove-property/run.ts @@ -1,7 +1,6 @@ import { variables, object, type AstTypes } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const variable = variables.declaration(ast, 'const', 'test', object.createEmpty()); const objectDeclarator = variable.declarations[0] as AstTypes.VariableDeclarator; const objectExpression = objectDeclarator.init as AstTypes.ObjectExpression; diff --git a/packages/core/tests/js/variables/declaration/output.ts b/packages/core/tests/js/variables/declaration/output.ts index 63df3119..b3bbf707 100644 --- a/packages/core/tests/js/variables/declaration/output.ts +++ b/packages/core/tests/js/variables/declaration/output.ts @@ -1,5 +1,2 @@ const testNumber = 2; - -const testObject = { - foo: "bar" -}; \ No newline at end of file +const testObject = { foo: "bar" }; \ No newline at end of file diff --git a/packages/core/tests/js/variables/declaration/run.ts b/packages/core/tests/js/variables/declaration/run.ts index ba1880e7..01b7a047 100644 --- a/packages/core/tests/js/variables/declaration/run.ts +++ b/packages/core/tests/js/variables/declaration/run.ts @@ -1,7 +1,6 @@ -import { variables, common, object } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { variables, common, object, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const testNumberVariable = variables.declaration( ast, 'const', diff --git a/packages/core/tests/js/variables/identifier/run.ts b/packages/core/tests/js/variables/identifier/run.ts index a5870f4d..5ab8962e 100644 --- a/packages/core/tests/js/variables/identifier/run.ts +++ b/packages/core/tests/js/variables/identifier/run.ts @@ -1,7 +1,6 @@ -import { variables } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { variables, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const barVariable = variables.declaration(ast, 'const', 'bar', variables.identifier('foo')); ast.body.push(barVariable); } diff --git a/packages/core/tests/js/variables/type-annotate-declarator/run.ts b/packages/core/tests/js/variables/type-annotate-declarator/run.ts index 4a0de3af..fc074609 100644 --- a/packages/core/tests/js/variables/type-annotate-declarator/run.ts +++ b/packages/core/tests/js/variables/type-annotate-declarator/run.ts @@ -1,7 +1,6 @@ -import { variables } from '@sveltejs/cli-core/js'; -import type { ScriptFileEditor } from '@sveltejs/cli-core'; +import { variables, type AstTypes } from '@sveltejs/cli-core/js'; -export function run({ ast }: ScriptFileEditor): void { +export function run(ast: AstTypes.Program): void { const decl = ast.body[0] as any; const annotatedDecl = variables.typeAnnotateDeclarator(decl.declarations[0], 'string'); decl.declarations[0] = annotatedDecl; diff --git a/packages/core/tooling/js/array.ts b/packages/core/tooling/js/array.ts index 7b43cd91..eb947020 100644 --- a/packages/core/tooling/js/array.ts +++ b/packages/core/tooling/js/array.ts @@ -1,5 +1,5 @@ import { areNodesEqual } from './common.ts'; -import type { AstKinds, AstTypes } from '@sveltejs/ast-tooling'; +import type { AstTypes } from '@sveltejs/ast-tooling'; export function createEmpty(): AstTypes.ArrayExpression { const arrayExpression: AstTypes.ArrayExpression = { @@ -11,24 +11,24 @@ export function createEmpty(): AstTypes.ArrayExpression { export function push( ast: AstTypes.ArrayExpression, - data: string | AstKinds.ExpressionKind | AstKinds.SpreadElementKind + data: string | AstTypes.Expression | AstTypes.SpreadElement ): void { if (typeof data === 'string') { const existingLiterals = ast.elements.filter( - (x): x is AstTypes.StringLiteral => x?.type == 'StringLiteral' + (x): x is AstTypes.Literal => x?.type == 'Literal' ); let literal = existingLiterals.find((x) => x.value == data); if (!literal) { literal = { - type: 'StringLiteral', + type: 'Literal', value: data }; ast.elements.push(literal); } } else { let anyNodeEquals = false; - const elements = ast.elements as AstTypes.ASTNode[]; + const elements = ast.elements as AstTypes.Node[]; for (const node of elements) { if (areNodesEqual(data, node)) { anyNodeEquals = true; diff --git a/packages/core/tooling/js/common.ts b/packages/core/tooling/js/common.ts index 53c1fbfb..45643672 100644 --- a/packages/core/tooling/js/common.ts +++ b/packages/core/tooling/js/common.ts @@ -1,5 +1,4 @@ import { - type AstKinds, type AstTypes, Walker, parseScript, @@ -9,21 +8,20 @@ import { import decircular from 'decircular'; import dedent from 'dedent'; -export function addJsDocTypeComment(node: AstTypes.Node, type: string): void { - const comment: AstTypes.CommentBlock = { - type: 'CommentBlock', - value: `* @type {${type}} `, - leading: true +export function addJsDocTypeComment(node: AstTypes.BaseNode, type: string): void { + const comment: AstTypes.Comment = { + type: 'Line', + value: `* @type {${type}} ` }; - node.comments ??= []; + node.leadingComments ??= []; - const found = node.comments.find((n) => n.type === 'CommentBlock' && n.value === comment.value); - if (!found) node.comments.push(comment); + const found = node.leadingComments.find((n) => n.type === 'Line' && n.value === comment.value); + if (!found) node.leadingComments.push(comment); } export function typeAnnotateExpression( - node: AstKinds.ExpressionKind, + node: AstTypes.Expression, type: string ): AstTypes.TSAsExpression { const expression: AstTypes.TSAsExpression = { @@ -35,7 +33,7 @@ export function typeAnnotateExpression( return expression; } -export function createSpreadElement(expression: AstKinds.ExpressionKind): AstTypes.SpreadElement { +export function createSpreadElement(expression: AstTypes.Expression): AstTypes.SpreadElement { return { type: 'SpreadElement', argument: expression @@ -51,13 +49,15 @@ export function createLiteral(value: string | number | boolean | null = null): A return literal; } -export function areNodesEqual(ast1: AstTypes.ASTNode, ast2: AstTypes.ASTNode): boolean { +export function areNodesEqual(ast1: AstTypes.Node, ast2: AstTypes.Node): boolean { // We're deep cloning these trees so that we can strip the locations off of them for comparisons. // Without this, we'd be getting false negatives due to slight differences in formatting style. // These ASTs are also filled to the brim with circular references, which prevents // us from using `structuredCloned` directly - const ast1Clone = stripAst(decircular(ast1), 'loc'); - const ast2Clone = stripAst(decircular(ast2), 'loc'); + + // todo: can we simplify this duplicated call? + const ast1Clone = stripAst(stripAst(decircular(ast1), 'loc'), 'raw'); + const ast2Clone = stripAst(stripAst(decircular(ast2), 'loc'), 'raw'); return serializeScript(ast1Clone) === serializeScript(ast2Clone); } @@ -69,9 +69,7 @@ export function blockStatement(): AstTypes.BlockStatement { return statement; } -export function expressionStatement( - expression: AstKinds.ExpressionKind -): AstTypes.ExpressionStatement { +export function expressionStatement(expression: AstTypes.Expression): AstTypes.ExpressionStatement { const statement: AstTypes.ExpressionStatement = { type: 'ExpressionStatement', expression @@ -86,11 +84,12 @@ export function addFromString( const program = parseScript(dedent(value)); for (const childNode of program.body) { + // @ts-expect-error ast.body.push(childNode); } } -export function expressionFromString(value: string): AstKinds.ExpressionKind { +export function expressionFromString(value: string): AstTypes.Expression { const program = parseScript(dedent(value)); const statement = program.body[0]!; if (statement.type !== 'ExpressionStatement') { @@ -100,23 +99,27 @@ export function expressionFromString(value: string): AstKinds.ExpressionKind { return statement.expression; } -export function statementFromString(value: string): AstKinds.StatementKind { +export function statementFromString(value: string): AstTypes.Statement { + return fromString(value); +} + +export function fromString(value: string): T { const program = parseScript(dedent(value)); const statement = program.body[0]!; - return statement; + return statement as T; } /** Appends the statement to body of the block if it doesn't already exist */ export function addStatement( ast: AstTypes.BlockStatement | AstTypes.Program, - statement: AstKinds.StatementKind + statement: AstTypes.Statement ): void { if (!hasNode(ast, statement)) ast.body.push(statement); } /** Returns `true` if the provided node exists in the AST */ -export function hasNode(ast: AstTypes.ASTNode, nodeToMatch: AstTypes.ASTNode): boolean { +export function hasNode(ast: AstTypes.Node, nodeToMatch: AstTypes.Node): boolean { let found = false; // prettier-ignore // this gets needlessly butchered by prettier diff --git a/packages/core/tooling/js/exports.ts b/packages/core/tooling/js/exports.ts index 92543660..2839a0fc 100644 --- a/packages/core/tooling/js/exports.ts +++ b/packages/core/tooling/js/exports.ts @@ -1,11 +1,11 @@ -import type { AstKinds, AstTypes } from '@sveltejs/ast-tooling'; +import type { AstTypes } from '@sveltejs/ast-tooling'; export type ExportDefaultReturn = { astNode: AstTypes.ExportDefaultDeclaration; value: T; }; -export function defaultExport( +export function defaultExport( ast: AstTypes.Program, fallbackDeclaration: T ): ExportDefaultReturn { @@ -72,7 +72,8 @@ export function namedExport( namedExport = { type: 'ExportNamedDeclaration', - declaration: fallback + declaration: fallback, + specifiers: [] }; ast.body.push(namedExport); return namedExport; diff --git a/packages/core/tooling/js/function.ts b/packages/core/tooling/js/function.ts index 84445a7c..56040113 100644 --- a/packages/core/tooling/js/function.ts +++ b/packages/core/tooling/js/function.ts @@ -1,4 +1,4 @@ -import type { AstKinds, AstTypes } from '@sveltejs/ast-tooling'; +import type { AstTypes } from '@sveltejs/ast-tooling'; export function call(name: string, args: string[]): AstTypes.CallExpression { const callExpression: AstTypes.CallExpression = { @@ -7,7 +7,8 @@ export function call(name: string, args: string[]): AstTypes.CallExpression { type: 'Identifier', name }, - arguments: [] + arguments: [], + optional: false }; for (const argument of args) { @@ -27,7 +28,8 @@ export function callByIdentifier(name: string, args: string[]): AstTypes.CallExp type: 'Identifier', name }, - arguments: [] + arguments: [], + optional: false }; for (const argument of args) { @@ -43,19 +45,20 @@ export function callByIdentifier(name: string, args: string[]): AstTypes.CallExp export function arrowFunction( async: boolean, - body: AstKinds.ExpressionKind | AstTypes.BlockStatement + body: AstTypes.Expression | AstTypes.BlockStatement ): AstTypes.ArrowFunctionExpression { const arrowFunction: AstTypes.ArrowFunctionExpression = { type: 'ArrowFunctionExpression', async, body, - params: [] + params: [], + expression: true }; return arrowFunction; } -export function argumentByIndex( +export function argumentByIndex( ast: AstTypes.CallExpression, i: number, fallback: T diff --git a/packages/core/tooling/js/imports.ts b/packages/core/tooling/js/imports.ts index 7abd01ad..11d1795f 100644 --- a/packages/core/tooling/js/imports.ts +++ b/packages/core/tooling/js/imports.ts @@ -8,7 +8,8 @@ export function addEmpty(ast: AstTypes.Program, importFrom: string): void { type: 'Literal', value: importFrom }, - specifiers: [] + specifiers: [], + importKind: 'value' }; addImportIfNecessary(ast, expectedImportDeclaration); @@ -29,7 +30,8 @@ export function addDefault(ast: AstTypes.Program, importFrom: string, importAs: name: importAs } } - ] + ], + importKind: 'value' }; addImportIfNecessary(ast, expectedImportDeclaration); @@ -58,7 +60,7 @@ export function addNamed( let importDecl: AstTypes.ImportDeclaration | undefined; // prettier-ignore - Walker.walk(ast as AstTypes.ASTNode, {}, { + Walker.walk(ast as AstTypes.Node, {}, { ImportDeclaration(node) { if (node.source.value === importFrom && node.specifiers) { importDecl = node; @@ -74,6 +76,8 @@ export function addNamed( (existingSpecifier) => existingSpecifier.type === 'ImportSpecifier' && existingSpecifier.local?.name !== specifierToAdd.local?.name && + existingSpecifier.imported.type == 'Identifier' && + specifierToAdd.imported.type == 'Identifier' && existingSpecifier.imported.name !== specifierToAdd.imported.name ) ) { @@ -90,7 +94,7 @@ export function addNamed( value: importFrom }, specifiers, - importKind: isType ? 'type' : undefined + importKind: isType ? 'type' : 'value' }; ast.body.unshift(expectedImportDeclaration); diff --git a/packages/core/tooling/js/index.ts b/packages/core/tooling/js/index.ts index 5e252626..7e556569 100644 --- a/packages/core/tooling/js/index.ts +++ b/packages/core/tooling/js/index.ts @@ -6,4 +6,4 @@ export * as imports from './imports.ts'; export * as variables from './variables.ts'; export * as exports from './exports.ts'; export * as kit from './kit.ts'; -export type { AstTypes, AstKinds } from '@sveltejs/ast-tooling'; +export type { AstTypes } from '@sveltejs/ast-tooling'; diff --git a/packages/core/tooling/js/kit.ts b/packages/core/tooling/js/kit.ts index 3126d748..20317e82 100644 --- a/packages/core/tooling/js/kit.ts +++ b/packages/core/tooling/js/kit.ts @@ -1,8 +1,8 @@ -import { Walker, type AstKinds } from '@sveltejs/ast-tooling'; -import { common, functions, imports, variables, exports, type AstTypes } from '../js/index.ts'; +import { Walker } from '@sveltejs/ast-tooling'; +import { type AstTypes, common, functions, imports, variables, exports } from '../js/index.ts'; export function addGlobalAppInterface( - ast: AstTypes.Program, + ast: AstTypes.TSProgram, name: 'Error' | 'Locals' | 'PageData' | 'PageState' | 'Platform' ): AstTypes.TSInterfaceDeclaration { let globalDecl = ast.body @@ -10,7 +10,7 @@ export function addGlobalAppInterface( .find((m) => m.global && m.declare); if (!globalDecl) { - globalDecl = common.statementFromString('declare global {}') as AstTypes.TSModuleDeclaration; + globalDecl = common.fromString('declare global {}'); ast.body.push(globalDecl); } @@ -22,7 +22,7 @@ export function addGlobalAppInterface( let interfaceNode: AstTypes.TSInterfaceDeclaration | undefined; // prettier-ignore - Walker.walk(globalDecl as AstTypes.ASTNode, {}, { + Walker.walk(globalDecl as AstTypes.Node, {}, { TSModuleDeclaration(node, { next }) { if (node.id.type === 'Identifier' && node.id.name === 'App') { app = node; @@ -37,7 +37,7 @@ export function addGlobalAppInterface( }); if (!app) { - app = common.statementFromString('namespace App {}') as AstTypes.TSModuleDeclaration; + app = common.fromString('namespace App {}'); globalDecl.body.body.push(app); } @@ -47,9 +47,7 @@ export function addGlobalAppInterface( if (!interfaceNode) { // add the interface if it's missing - interfaceNode = common.statementFromString( - `interface ${name} {}` - ) as AstTypes.TSInterfaceDeclaration; + interfaceNode = common.fromString(`interface ${name} {}`); app.body.body.push(interfaceNode); } @@ -70,20 +68,20 @@ export function addHooksHandle( let isSpecifier: boolean = false; let handleName = 'handle'; let exportDecl: AstTypes.ExportNamedDeclaration | undefined; - let originalHandleDecl: AstKinds.DeclarationKind | undefined; + let originalHandleDecl: AstTypes.Declaration | undefined; // We'll first visit all of the named exports and grab their references if they export `handle`. // This will grab export references for: // `export { handle }` & `export { foo as handle }` // `export const handle = ...`, & `export function handle() {...}` // prettier-ignore - Walker.walk(ast as AstTypes.ASTNode, {}, { + Walker.walk(ast as AstTypes.Node, {}, { ExportNamedDeclaration(node) { - let maybeHandleDecl: AstKinds.DeclarationKind | undefined; + let maybeHandleDecl: AstTypes.Declaration | undefined; // `export { handle }` & `export { foo as handle }` - const handleSpecifier = node.specifiers?.find((s) => s.exported.name === 'handle'); - if (handleSpecifier) { + const handleSpecifier = node.specifiers?.find((s) => s.exported.type == 'Identifier' && s.exported.name === 'handle'); + if (handleSpecifier && handleSpecifier.local.type == 'Identifier' && handleSpecifier.exported.type == 'Identifier') { isSpecifier = true; // we'll search for the local name in case it's aliased (e.g. `export { foo as handle }`) handleName = handleSpecifier.local?.name ?? handleSpecifier.exported.name; @@ -257,7 +255,7 @@ function usingSequence(node: AstTypes.VariableDeclarator, handleName: string) { } function isVariableDeclaration( - node: AstTypes.ASTNode, + node: AstTypes.Node, variableName: string ): node is AstTypes.VariableDeclaration { return ( @@ -275,7 +273,7 @@ function getVariableDeclarator( } function isFunctionDeclaration( - node: AstTypes.ASTNode, + node: AstTypes.Node, funcName: string ): node is AstTypes.FunctionDeclaration { return node.type === 'FunctionDeclaration' && node.id?.name === funcName; diff --git a/packages/core/tooling/js/object.ts b/packages/core/tooling/js/object.ts index e0a5fb63..4163921f 100644 --- a/packages/core/tooling/js/object.ts +++ b/packages/core/tooling/js/object.ts @@ -1,13 +1,13 @@ -import type { AstKinds, AstTypes } from '@sveltejs/ast-tooling'; +import type { AstTypes } from '@sveltejs/ast-tooling'; -export function property( +export function property( ast: AstTypes.ObjectExpression, name: string, fallback: T ): T { const objectExpression = ast; const properties = objectExpression.properties.filter( - (x): x is AstTypes.ObjectProperty => x.type == 'ObjectProperty' + (x): x is AstTypes.Property => x.type == 'Property' ); let property = properties.find((x) => (x.key as AstTypes.Identifier).name == name); let propertyValue: T; @@ -23,13 +23,16 @@ export function property( +export function overrideProperty( ast: AstTypes.ObjectExpression, name: string, value: T ): T { const objectExpression = ast; const properties = objectExpression.properties.filter( - (x): x is AstTypes.ObjectProperty => x.type == 'ObjectProperty' + (x): x is AstTypes.Property => x.type == 'Property' ); const prop = properties.find((x) => (x.key as AstTypes.Identifier).name == name); @@ -58,7 +61,7 @@ export function overrideProperty( return value; } -export function overrideProperties( +export function overrideProperties( ast: AstTypes.ObjectExpression, obj: Record ): void { @@ -68,7 +71,7 @@ export function overrideProperties( } } -export function properties( +export function properties( ast: AstTypes.ObjectExpression, obj: Record ): void { @@ -79,9 +82,7 @@ export function properties( } export function removeProperty(ast: AstTypes.ObjectExpression, property: string): void { - const properties = ast.properties.filter( - (x): x is AstTypes.ObjectProperty => x.type === 'ObjectProperty' - ); + const properties = ast.properties.filter((x): x is AstTypes.Property => x.type === 'Property'); const propIdx = properties.findIndex((x) => (x.key as AstTypes.Identifier).name === property); if (propIdx !== -1) { @@ -89,7 +90,7 @@ export function removeProperty(ast: AstTypes.ObjectExpression, property: string) } } -export function create( +export function create( obj: Record ): AstTypes.ObjectExpression { const objExpression = createEmpty(); diff --git a/packages/core/tooling/js/variables.ts b/packages/core/tooling/js/variables.ts index 968ea9a4..7818b548 100644 --- a/packages/core/tooling/js/variables.ts +++ b/packages/core/tooling/js/variables.ts @@ -1,10 +1,10 @@ -import type { AstKinds, AstTypes } from '@sveltejs/ast-tooling'; +import type { AstTypes } from '@sveltejs/ast-tooling'; export function declaration( - ast: AstTypes.Program | AstKinds.DeclarationKind, + ast: AstTypes.Program | AstTypes.Declaration, kind: 'const' | 'let' | 'var', name: string, - value: AstKinds.ExpressionKind + value: AstTypes.Expression ): AstTypes.VariableDeclaration { const declarations = ast.type == 'Program' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26924ec7..56a320fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,12 +96,15 @@ importers: packages/ast-tooling: devDependencies: - '@babel/parser': - specifier: ^7.24.7 - version: 7.25.3 - ast-types: - specifier: ^0.14.2 - version: 0.14.2 + '@types/estree': + specifier: ^1.0.6 + version: 1.0.6 + acorn: + specifier: ^8.12.1 + version: 8.12.1 + acorn-typescript: + specifier: ^1.4.13 + version: 1.4.13(acorn@8.12.1) dom-serializer: specifier: ^2.0.0 version: 2.0.0 @@ -111,15 +114,15 @@ importers: domutils: specifier: ^3.1.0 version: 3.1.0 + esrap-typescript-temp: + specifier: ^0.0.1 + version: 0.0.1 htmlparser2: specifier: ^9.1.0 version: 9.1.0 postcss: specifier: ^8.4.38 version: 8.4.45 - recast: - specifier: ^0.23.7 - version: 0.23.9 silver-fleece: specifier: ^1.1.0 version: 1.1.0 @@ -236,27 +239,10 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@babel/helper-string-parser@7.24.8': - resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.24.7': - resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.25.3': - resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/runtime@7.25.0': resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==} engines: {node: '>=6.9.0'} - '@babel/types@7.25.2': - resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} - engines: {node: '>=6.9.0'} - '@changesets/apply-release-plan@7.0.5': resolution: {integrity: sha512-1cWCk+ZshEkSVEZrm2fSj1Gz8sYvxgUL4Q78+1ZZqeqfuevPTPk033/yUZ3df8BKMohkqqHfzj0HOOrG0KtXTw==} @@ -727,6 +713,9 @@ packages: '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/gitignore-parser@0.0.3': resolution: {integrity: sha512-sbdu1sG2pQcwjEYWTsX78OqJo5pKnonwC4FV3m2JeQRE2xYb3q0icHHopCHEvpn4uIBuvWBTpJUCJ76ISK24CA==} @@ -884,14 +873,6 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-types@0.14.2: - resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} - engines: {node: '>=4'} - - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - astring@1.8.6: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true @@ -1179,6 +1160,9 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + esrap-typescript-temp@0.0.1: + resolution: {integrity: sha512-7CtMLBfcpwqzI42svwz3CYEujMUzWqqv/s1ezaWXdFZlFnMaAQoxh1BYo5emZeeP+fNmqGRc/9cvazg5N5zlLg==} + esrap@1.2.2: resolution: {integrity: sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==} @@ -1729,10 +1713,6 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} - recast@0.23.9: - resolution: {integrity: sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==} - engines: {node: '>= 4'} - regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -1827,10 +1807,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead @@ -1934,9 +1910,6 @@ packages: tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1959,10 +1932,6 @@ packages: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} - to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1983,9 +1952,6 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2173,24 +2139,10 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@babel/helper-string-parser@7.24.8': {} - - '@babel/helper-validator-identifier@7.24.7': {} - - '@babel/parser@7.25.3': - dependencies: - '@babel/types': 7.25.2 - '@babel/runtime@7.25.0': dependencies: regenerator-runtime: 0.14.1 - '@babel/types@7.25.2': - dependencies: - '@babel/helper-string-parser': 7.24.8 - '@babel/helper-validator-identifier': 7.24.7 - to-fast-properties: 2.0.0 - '@changesets/apply-release-plan@7.0.5': dependencies: '@changesets/config': 3.0.3 @@ -2653,6 +2605,8 @@ snapshots: '@types/estree@1.0.5': {} + '@types/estree@1.0.6': {} + '@types/gitignore-parser@0.0.3': {} '@types/node@12.20.55': {} @@ -2840,14 +2794,6 @@ snapshots: assertion-error@2.0.1: {} - ast-types@0.14.2: - dependencies: - tslib: 2.6.3 - - ast-types@0.16.1: - dependencies: - tslib: 2.6.3 - astring@1.8.6: {} axobject-query@4.1.0: {} @@ -3166,10 +3112,15 @@ snapshots: dependencies: estraverse: 5.3.0 + esrap-typescript-temp@0.0.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@typescript-eslint/types': 8.5.0 + esrap@1.2.2: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 esrecurse@4.3.0: dependencies: @@ -3181,7 +3132,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.6 esutils@2.0.3: {} @@ -3662,14 +3613,6 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 - recast@0.23.9: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.6.3 - regenerator-runtime@0.14.1: {} resolve-from@4.0.0: {} @@ -3764,8 +3707,6 @@ snapshots: source-map-js@1.2.1: {} - source-map@0.6.1: {} - sourcemap-codec@1.4.8: {} spawndamnit@2.0.0: @@ -3892,8 +3833,6 @@ snapshots: globalyzer: 0.1.0 globrex: 0.1.2 - tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} tinyexec@0.3.0: {} @@ -3908,8 +3847,6 @@ snapshots: dependencies: os-tmpdir: 1.0.2 - to-fast-properties@2.0.0: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -3924,8 +3861,6 @@ snapshots: ts-interface-checker@0.1.13: {} - tslib@2.6.3: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1