From 8299da167a4f4a6f8ae32760b5e8ea02a3ba8e7a Mon Sep 17 00:00:00 2001
From: Simon H <5968653+dummdidumm@users.noreply.github.com>
Date: Tue, 30 May 2023 21:02:45 +0200
Subject: [PATCH] feat: add Svelte 4 migration (#9729)
Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com>
---
.changeset/lucky-coins-hunt.md | 5 +
packages/migrate/migrations/svelte-4/index.js | 71 +++++++
.../migrate/migrations/svelte-4/migrate.js | 200 ++++++++++++++++++
.../migrations/svelte-4/migrate.spec.js | 197 +++++++++++++++++
packages/migrate/package.json | 3 +-
pnpm-lock.yaml | 56 +++--
6 files changed, 518 insertions(+), 14 deletions(-)
create mode 100644 .changeset/lucky-coins-hunt.md
create mode 100644 packages/migrate/migrations/svelte-4/index.js
create mode 100644 packages/migrate/migrations/svelte-4/migrate.js
create mode 100644 packages/migrate/migrations/svelte-4/migrate.spec.js
diff --git a/.changeset/lucky-coins-hunt.md b/.changeset/lucky-coins-hunt.md
new file mode 100644
index 000000000000..78d11ddc8907
--- /dev/null
+++ b/.changeset/lucky-coins-hunt.md
@@ -0,0 +1,5 @@
+---
+'svelte-migrate': minor
+---
+
+feat: add Svelte 4 migration
diff --git a/packages/migrate/migrations/svelte-4/index.js b/packages/migrate/migrations/svelte-4/index.js
new file mode 100644
index 000000000000..a1acfa7c34a1
--- /dev/null
+++ b/packages/migrate/migrations/svelte-4/index.js
@@ -0,0 +1,71 @@
+import colors from 'kleur';
+import fs from 'node:fs';
+import prompts from 'prompts';
+import glob from 'tiny-glob/sync.js';
+import { bail, check_git } from '../../utils.js';
+import { update_js_file, update_svelte_file } from './migrate.js';
+
+export async function migrate() {
+ if (!fs.existsSync('package.json')) {
+ bail('Please re-run this script in a directory with a package.json');
+ }
+
+ console.log(colors.bold().yellow('\nThis will update files in the current directory\n'));
+
+ const use_git = check_git();
+
+ const response = await prompts({
+ type: 'confirm',
+ name: 'value',
+ message: 'Continue?',
+ initial: false
+ });
+
+ if (!response.value) {
+ process.exit(1);
+ }
+
+ // const { default: config } = fs.existsSync('svelte.config.js')
+ // ? await import(pathToFileURL(path.resolve('svelte.config.js')).href)
+ // : { default: {} };
+
+ /** @type {string[]} */
+ const svelte_extensions = /* config.extensions ?? - disabled because it would break .svx */ ['.svelte'];
+ const extensions = [...svelte_extensions, '.ts', '.js'];
+ // TODO read tsconfig/jsconfig if available? src/** will be good for 99% of cases
+ const files = glob('src/**', { filesOnly: true, dot: true }).map((file) =>
+ file.replace(/\\/g, '/')
+ );
+
+ for (const file of files) {
+ if (extensions.some((ext) => file.endsWith(ext))) {
+ if (svelte_extensions.some((ext) => file.endsWith(ext))) {
+ update_svelte_file(file);
+ } else {
+ update_js_file(file);
+ }
+ }
+ }
+
+ console.log(colors.bold().green('✔ Your project has been migrated'));
+
+ console.log('\nRecommended next steps:\n');
+
+ const cyan = colors.bold().cyan;
+
+ const tasks = [
+ use_git && cyan('git commit -m "migration to Svelte 4"'),
+ 'Review the migration guide at TODO',
+ 'Read the updated docs at https://svelte.dev/docs'
+ ].filter(Boolean);
+
+ tasks.forEach((task, i) => {
+ console.log(` ${i + 1}: ${task}`);
+ });
+
+ console.log('');
+
+ if (use_git) {
+ console.log(`Run ${cyan('git diff')} to review changes.\n`);
+ }
+}
diff --git a/packages/migrate/migrations/svelte-4/migrate.js b/packages/migrate/migrations/svelte-4/migrate.js
new file mode 100644
index 000000000000..5609167f230e
--- /dev/null
+++ b/packages/migrate/migrations/svelte-4/migrate.js
@@ -0,0 +1,200 @@
+import fs from 'node:fs';
+import { Project, ts, Node } from 'ts-morph';
+
+/** @param {string} file_path */
+export function update_svelte_file(file_path) {
+ const content = fs.readFileSync(file_path, 'utf-8');
+ const updated = content.replace(
+ /${whitespace}`;
+ }
+ );
+ fs.writeFileSync(file_path, transform_svelte_code(updated), 'utf-8');
+}
+
+/** @param {string} file_path */
+export function update_js_file(file_path) {
+ const content = fs.readFileSync(file_path, 'utf-8');
+ const updated = transform_code(content);
+ fs.writeFileSync(file_path, updated, 'utf-8');
+}
+
+/** @param {string} code */
+export function transform_code(code) {
+ const project = new Project({ useInMemoryFileSystem: true });
+ const source = project.createSourceFile('svelte.ts', code);
+ update_imports(source);
+ update_typeof_svelte_component(source);
+ update_action_types(source);
+ update_action_return_types(source);
+ return source.getFullText();
+}
+
+/** @param {string} code */
+export function transform_svelte_code(code) {
+ return update_transitions(update_svelte_options(code));
+}
+
+/**
+ * ->
+ * @param {string} code
+ */
+function update_svelte_options(code) {
+ return code.replace(//, (match) => {
+ return match.replace('tag=', 'customElement=');
+ });
+}
+
+/**
+ * transition/in/out:x -> transition/in/out:x|global
+ * @param {string} code
+ */
+function update_transitions(code) {
+ return code.replace(/(\s)(transition:|in:|out:)(\w+)(?=[\s>=])/g, '$1$2$3|global');
+}
+
+/**
+ * Action -> Action
+ * @param {import('ts-morph').SourceFile} source
+ */
+function update_action_types(source) {
+ const imports = get_imports(source, 'svelte/action', 'Action');
+ for (const namedImport of imports) {
+ const identifiers = find_identifiers(source, namedImport.getAliasNode()?.getText() ?? 'Action');
+ for (const id of identifiers) {
+ const parent = id.getParent();
+ if (Node.isTypeReference(parent)) {
+ const type_args = parent.getTypeArguments();
+ if (type_args.length === 1) {
+ parent.addTypeArgument('any');
+ } else if (type_args.length === 0) {
+ parent.addTypeArgument('HTMLElement');
+ parent.addTypeArgument('any');
+ }
+ }
+ }
+ }
+}
+
+/**
+ * ActionReturn -> ActionReturn
+ * @param {import('ts-morph').SourceFile} source
+ */
+function update_action_return_types(source) {
+ const imports = get_imports(source, 'svelte/action', 'ActionReturn');
+ for (const namedImport of imports) {
+ const identifiers = find_identifiers(
+ source,
+ namedImport.getAliasNode()?.getText() ?? 'ActionReturn'
+ );
+ for (const id of identifiers) {
+ const parent = id.getParent();
+ if (Node.isTypeReference(parent)) {
+ const type_args = parent.getTypeArguments();
+ if (type_args.length === 0) {
+ parent.addTypeArgument('any');
+ }
+ }
+ }
+ }
+}
+
+/**
+ * SvelteComponentTyped -> SvelteComponent
+ * @param {import('ts-morph').SourceFile} source
+ */
+function update_imports(source) {
+ const identifiers = find_identifiers(source, 'SvelteComponent');
+ const can_rename = identifiers.every((id) => {
+ const parent = id.getParent();
+ return (
+ (Node.isImportSpecifier(parent) &&
+ !parent.getAliasNode() &&
+ parent.getParent().getParent().getParent().getModuleSpecifier().getText() === 'svelte') ||
+ !is_declaration(parent)
+ );
+ });
+
+ const imports = get_imports(source, 'svelte', 'SvelteComponentTyped');
+ for (const namedImport of imports) {
+ if (can_rename) {
+ namedImport.renameAlias('SvelteComponent');
+ if (
+ namedImport
+ .getParent()
+ .getElements()
+ .some((e) => !e.getAliasNode() && e.getNameNode().getText() === 'SvelteComponent')
+ ) {
+ namedImport.remove();
+ } else {
+ namedImport.setName('SvelteComponent');
+ namedImport.removeAlias();
+ }
+ } else {
+ namedImport.renameAlias('SvelteComponentTyped');
+ namedImport.setName('SvelteComponent');
+ }
+ }
+}
+
+/**
+ * typeof SvelteComponent -> typeof SvelteComponent
+ * @param {import('ts-morph').SourceFile} source
+ */
+function update_typeof_svelte_component(source) {
+ const imports = get_imports(source, 'svelte', 'SvelteComponent');
+
+ for (const type of imports) {
+ if (type) {
+ const name = type.getAliasNode() ?? type.getNameNode();
+ name.findReferencesAsNodes().forEach((ref) => {
+ const parent = ref.getParent();
+ if (parent && Node.isTypeQuery(parent)) {
+ const id = parent.getFirstChildByKind(ts.SyntaxKind.Identifier);
+ if (id?.getText() === name.getText()) {
+ const typeArguments = parent.getTypeArguments();
+ if (typeArguments.length === 0) {
+ parent.addTypeArgument('any');
+ }
+ }
+ }
+ });
+ }
+ }
+}
+
+/**
+ * @param {import('ts-morph').SourceFile} source
+ * @param {string} from
+ * @param {string} name
+ */
+function get_imports(source, from, name) {
+ return source
+ .getImportDeclarations()
+ .filter((i) => i.getModuleSpecifierValue() === from)
+ .flatMap((i) => i.getNamedImports())
+ .filter((i) => i.getName() === name);
+}
+
+/**
+ * @param {import('ts-morph').SourceFile} source
+ * @param {string} name
+ */
+function find_identifiers(source, name) {
+ return source.getDescendantsOfKind(ts.SyntaxKind.Identifier).filter((i) => i.getText() === name);
+}
+
+/**
+ * Does not include imports
+ * @param {Node} node
+ */
+function is_declaration(node) {
+ return (
+ Node.isVariableDeclaration(node) ||
+ Node.isFunctionDeclaration(node) ||
+ Node.isClassDeclaration(node) ||
+ Node.isTypeAliasDeclaration(node) ||
+ Node.isInterfaceDeclaration(node)
+ );
+}
diff --git a/packages/migrate/migrations/svelte-4/migrate.spec.js b/packages/migrate/migrations/svelte-4/migrate.spec.js
new file mode 100644
index 000000000000..d2a01a07e517
--- /dev/null
+++ b/packages/migrate/migrations/svelte-4/migrate.spec.js
@@ -0,0 +1,197 @@
+import { assert, test } from 'vitest';
+import { transform_code, transform_svelte_code } from './migrate.js';
+
+test('Updates SvelteComponentTyped #1', () => {
+ const result = transform_code(
+ `import { SvelteComponentTyped } from 'svelte';
+
+export class Foo extends SvelteComponentTyped<{}> {}
+
+const bar: SvelteComponentTyped = null;`
+ );
+ assert.equal(
+ result,
+ `import { SvelteComponent } from 'svelte';
+
+export class Foo extends SvelteComponent<{}> {}
+
+const bar: SvelteComponent = null;`
+ );
+});
+
+test('Updates SvelteComponentTyped #2', () => {
+ const result = transform_code(
+ `import { SvelteComponentTyped, SvelteComponent } from 'svelte';
+
+export class Foo extends SvelteComponentTyped<{}> {}
+
+const bar: SvelteComponentTyped = null;
+const baz: SvelteComponent = null;`
+ );
+ assert.equal(
+ result,
+ `import { SvelteComponent } from 'svelte';
+
+export class Foo extends SvelteComponent<{}> {}
+
+const bar: SvelteComponent = null;
+const baz: SvelteComponent = null;`
+ );
+});
+
+test('Updates SvelteComponentTyped #3', () => {
+ const result = transform_code(
+ `import { SvelteComponentTyped } from 'svelte';
+
+interface SvelteComponent {}
+
+export class Foo extends SvelteComponentTyped<{}> {}
+
+const bar: SvelteComponentTyped = null;
+const baz: SvelteComponent = null;`
+ );
+ assert.equal(
+ result,
+ `import { SvelteComponent as SvelteComponentTyped } from 'svelte';
+
+interface SvelteComponent {}
+
+export class Foo extends SvelteComponentTyped<{}> {}
+
+const bar: SvelteComponentTyped = null;
+const baz: SvelteComponent = null;`
+ );
+});
+
+test('Updates typeof SvelteComponent', () => {
+ const result = transform_code(
+ `import { SvelteComponent } from 'svelte';
+ import { SvelteComponent as C } from 'svelte';
+
+ const a: typeof SvelteComponent = null;
+ function b(c: typeof SvelteComponent) {}
+ const c: typeof SvelteComponent = null;
+ const d: typeof C = null;
+ `
+ );
+ assert.equal(
+ result,
+ `import { SvelteComponent } from 'svelte';
+ import { SvelteComponent as C } from 'svelte';
+
+ const a: typeof SvelteComponent = null;
+ function b(c: typeof SvelteComponent) {}
+ const c: typeof SvelteComponent = null;
+ const d: typeof C = null;
+ `
+ );
+});
+
+test('Updates Action and ActionReturn', () => {
+ const result = transform_code(
+ `import { Action, ActionReturn } from 'svelte/action';
+
+ const a: Action = () => {};
+ const b: Action = () => {};
+ const c: Action = () => {};
+ const d: Action = () => {};
+ const e: ActionReturn = () => {};
+ const f: ActionReturn = () => {};
+ const g: ActionReturn = () => {};
+ `
+ );
+ assert.equal(
+ result,
+
+ `import { Action, ActionReturn } from 'svelte/action';
+
+ const a: Action = () => {};
+ const b: Action = () => {};
+ const c: Action = () => {};
+ const d: Action = () => {};
+ const e: ActionReturn = () => {};
+ const f: ActionReturn = () => {};
+ const g: ActionReturn = () => {};
+ `
+ );
+});
+
+test('Updates svelte:options #1', () => {
+ const result = transform_svelte_code(
+ `
+
+ hi
`
+ );
+ assert.equal(
+ result,
+ `
+
+ hi
`
+ );
+});
+
+test('Updates svelte:options #2', () => {
+ const result = transform_svelte_code(
+ `
+
+
+
+ hi
`
+ );
+ assert.equal(
+ result,
+ `
+
+
+
+ hi
`
+ );
+});
+
+test('Updates transitions', () => {
+ const result = transform_svelte_code(
+ `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ );
+ assert.equal(
+ result,
+ `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ );
+});
diff --git a/packages/migrate/package.json b/packages/migrate/package.json
index ac4b2bfc226d..c17a4cdb48dd 100644
--- a/packages/migrate/package.json
+++ b/packages/migrate/package.json
@@ -28,7 +28,8 @@
"magic-string": "^0.30.0",
"prompts": "^2.4.2",
"tiny-glob": "^0.2.9",
- "typescript": "^4.9.4"
+ "ts-morph": "^18.0.0",
+ "typescript": "^5.0.4"
},
"devDependencies": {
"@types/node": "^16.18.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c34bd0dcf74a..390bb7b3478a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -938,9 +938,12 @@ importers:
tiny-glob:
specifier: ^0.2.9
version: 0.2.9
+ ts-morph:
+ specifier: ^18.0.0
+ version: 18.0.0
typescript:
- specifier: ^4.9.4
- version: 4.9.4
+ specifier: ^5.0.4
+ version: 5.0.4
devDependencies:
'@types/node':
specifier: ^16.18.6
@@ -1647,12 +1650,10 @@ packages:
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
- dev: true
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
- dev: true
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
@@ -1660,7 +1661,6 @@ packages:
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
- dev: true
/@playwright/test@1.30.0:
resolution: {integrity: sha512-SVxkQw1xvn/Wk/EvBnqWIq6NLo1AppwbYOjNLmyU0R1RoQ3rLEBtmjTnElcnz8VEtn11fptj1ECxK0tgURhajw==}
@@ -1824,6 +1824,15 @@ packages:
- encoding
dev: true
+ /@ts-morph/common@0.19.0:
+ resolution: {integrity: sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ==}
+ dependencies:
+ fast-glob: 3.2.12
+ minimatch: 7.4.6
+ mkdirp: 2.1.6
+ path-browserify: 1.0.1
+ dev: false
+
/@types/chai-subset@1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
@@ -2638,6 +2647,10 @@ packages:
engines: {node: '>=0.8'}
dev: true
+ /code-block-writer@12.0.0:
+ resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==}
+ dev: false
+
/code-point-at@1.1.0:
resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==}
engines: {node: '>=0.10.0'}
@@ -3457,7 +3470,6 @@ packages:
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
- dev: true
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
@@ -3471,7 +3483,6 @@ packages:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
reusify: 1.0.4
- dev: true
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@@ -4382,7 +4393,6 @@ packages:
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
- dev: true
/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
@@ -4422,6 +4432,13 @@ packages:
dependencies:
brace-expansion: 2.0.1
+ /minimatch@7.4.6:
+ resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==}
+ engines: {node: '>=10'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: false
+
/minimatch@9.0.0:
resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -4484,6 +4501,12 @@ packages:
hasBin: true
dev: false
+ /mkdirp@2.1.6:
+ resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dev: false
+
/mlly@1.2.0:
resolution: {integrity: sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==}
dependencies:
@@ -4779,6 +4802,10 @@ packages:
tslib: 2.4.1
dev: false
+ /path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+ dev: false
+
/path-exists@3.0.0:
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
engines: {node: '>=4'}
@@ -5038,7 +5065,6 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- dev: true
/quick-lru@4.0.1:
resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
@@ -5205,7 +5231,6 @@ packages:
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- dev: true
/rework@1.0.1:
resolution: {integrity: sha512-eEjL8FdkdsxApd0yWVZgBGzfCQiT8yqSc2H1p4jpZpQdtz7ohETiDMoje5PlM8I9WgkqkreVxFUKYOiJdVWDXw==}
@@ -5253,7 +5278,6 @@ packages:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
- dev: true
/sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
@@ -5380,7 +5404,7 @@ packages:
'@typescript/twoslash': 3.1.0
'@typescript/vfs': 1.3.4
shiki: 0.10.1
- typescript: 5.0.2
+ typescript: 5.0.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -5958,6 +5982,13 @@ packages:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
dev: true
+ /ts-morph@18.0.0:
+ resolution: {integrity: sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA==}
+ dependencies:
+ '@ts-morph/common': 0.19.0
+ code-block-writer: 12.0.0
+ dev: false
+
/tsconfig-paths@3.14.2:
resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==}
dependencies:
@@ -6052,7 +6083,6 @@ packages:
resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
engines: {node: '>=12.20'}
hasBin: true
- dev: true
/ufo@1.1.2:
resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}