Repository: sveltejs/cli
Pull request #610 (2025-06-25 04:20:33)

chore: use project service for typescript-eslint to auto-detect tsconfig.json
This PR intends to remove the eslint errors that show up in the IDE about certain .ts files not being included by the tsconfig.json . An example of this is `packages/core/tests/utils.ts`.

More about project service replacing the project setting: https://typescript-eslint.io/packages/parser/#projectservice

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: b2061d7a0331ca28ec1791e7c43f32c290388ffb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/sveltejs/cli/new/fix-lint?filename=.changeset/pink-pandas-watch.md&value=---%0A%22%40sveltejs%2Fcli-core%22%3A%20patch%0A---%0A%0Achore%3A%20use%20project%20service%20for%20typescript-eslint%20to%20auto-detect%20tsconfig.json%0A)


pkg-pr-new[bot]: 
[Open in StackBlitz](https://pkg.pr.new/template/2411f9b5-79d6-4405-867c-82f5d43be15d)


```
npx https://pkg.pr.new/sveltejs/cli/sv@610
```


```
npx https://pkg.pr.new/sveltejs/cli/svelte-migrate@610
```


_commit: <a href="https://github.com/sveltejs/cli/runs/44736445046"><code>b2061d7</code></a>_


Patch:
diff --git a/.changeset/short-chicken-sell.md b/.changeset/short-chicken-sell.md
new file mode 100644
index 0000000..9dabbae
--- /dev/null
+++ b/.changeset/short-chicken-sell.md
@@ -0,0 +1,5 @@
+---
+"sv": patch
+---
+
+fix: preserve comments when parsing JS AST
diff --git a/documentation/docs/30-add-ons/03-devtools-json.md b/documentation/docs/30-add-ons/03-devtools-json.md
new file mode 100644
index 0000000..49b01e0
--- /dev/null
+++ b/documentation/docs/30-add-ons/03-devtools-json.md
@@ -0,0 +1,39 @@
+---
+title: devtools-json
+---
+
+The `devtools-json` add-on installs [`vite-plugin-devtools-json`](https://github.com/ChromeDevTools/vite-plugin-devtools-json/), which is a Vite plugin for generating a Chromium DevTools project settings file on-the-fly in the development server. This file is served from `/.well-known/appspecific/com.chrome.devtools.json` and tells Chromium browsers where your project's source code lives so that you can use [the workspaces feature](https://developer.chrome.com/docs/devtools/workspaces) to edit source files in the browser.
+
+> [!NOTE]
+> Installing the plugin enables the feature for all users connecting to the dev server with a Chromium browser, and allows the browser to read and write all files within the directory. If using Chrome's AI Assistance feature, this may also result in data being sent to Google.
+
+## Alternatives
+
+If you'd prefer not to install the plugin, but still want to avoid seeing a message about the missing file, you have a couple of options.
+
+Firstly, you can prevent the request from being issued on your machine by disabling the feature in your browser. You can do this in Chrome by visiting `chrome://flags` and disabling the "DevTools Project Settings". You may also be interested in disabling "DevTools Automatic Workspace Folders" since it’s closely related.
+
+You can also prevent the web server from issuing a notice regarding the incoming request for all developers of your application by handling the request yourself. For example, you can create a file named `.well-known/appspecific/com.chrome.devtools.json` with the contents `"Go away, Chrome DevTools!"` or you can add logic to respond to the request in your [`handle`](https://svelte.dev/docs/kit/hooks#Server-hooks-handle) hook:
+
+```js
+/// file: src/hooks.server.js
+import { dev } from '$app/environment';
+
+export function handle({ event, resolve }) {
+	if (dev && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
+		return new Response(undefined, { status: 404 });
+	}
+
+	return resolve(event);
+}
+```
+
+## Usage
+
+```bash
+npx sv add devtools-json
+```
+
+## What you get
+
+- `vite-plugin-devtools-json` added to your Vite plugin options
diff --git a/documentation/docs/30-add-ons/60-devtools-json.md b/documentation/docs/30-add-ons/60-devtools-json.md
deleted file mode 100644
index 6fabf64..0000000
--- a/documentation/docs/30-add-ons/60-devtools-json.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: devtools-json
----
-
-`devtools-json` is essentially a vite plugin [vite-plugin-devtools-json](https://github.com/ChromeDevTools/vite-plugin-devtools-json/) for generating the Chrome DevTools project settings file on-the-fly in the devserver.
-
-It will prevent this server log:
-
-```sh
-Not found: /.well-known/appspecific/com.chrome.devtools.json
-```
-
-## Usage
-
-```bash
-npx sv add devtools-json
-```
-
-## What you get
-
-- the `vite` plugin added to your vite plugin options.
diff --git a/eslint.config.js b/eslint.config.js
index 1d15f97..8beb189 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -12,8 +12,7 @@ export default [
 	{
 		languageOptions: {
 			parserOptions: {
-				// use the nearest tsconfig from the source or fallback to the root
-				project: ['packages/**/tsconfig.json', 'tsconfig.json']
+				projectService: true
 			}
 		},
 		rules: {
diff --git a/packages/addons/devtools-json/index.ts b/packages/addons/devtools-json/index.ts
index 254a798..a0962d4 100644
--- a/packages/addons/devtools-json/index.ts
+++ b/packages/addons/devtools-json/index.ts
@@ -8,13 +8,6 @@ export default defineAddon({
 	homepage: 'https://github.com/ChromeDevTools/vite-plugin-devtools-json',
 	options: {},
 
-	setup: ({ defaultSelection }) => {
-		defaultSelection({
-			create: true,
-			add: false
-		});
-	},
-
 	run: ({ sv, typescript }) => {
 		const ext = typescript ? 'ts' : 'js';
 
diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md
index 75acc83..193f816 100644
--- a/packages/cli/CHANGELOG.md
+++ b/packages/cli/CHANGELOG.md
@@ -1,5 +1,11 @@
 # sv
 
+## 0.8.13
+### Patch Changes
+
+
+- chore: don't select `devtools-json` by default ([#598](https://github.com/sveltejs/cli/pull/598))
+
 ## 0.8.12
 ### Patch Changes
 
diff --git a/packages/cli/commands/add/index.ts b/packages/cli/commands/add/index.ts
index f8b4604..fedc665 100644
--- a/packages/cli/commands/add/index.ts
+++ b/packages/cli/commands/add/index.ts
@@ -201,7 +201,7 @@ export const add = new Command('add')
 
 		common.runCommand(async () => {
 			const selectedAddonIds = selectedAddons.map(({ id }) => id);
-			const { nextSteps } = await runAddCommand(options, selectedAddonIds, 'add');
+			const { nextSteps } = await runAddCommand(options, selectedAddonIds);
 			if (nextSteps) p.note(nextSteps, 'Next steps', { format: (line: string) => line });
 		});
 	});
@@ -209,8 +209,7 @@ export const add = new Command('add')
 type SelectedAddon = { type: 'official' | 'community'; addon: AddonWithoutExplicitArgs };
 export async function runAddCommand(
 	options: Options,
-	selectedAddonIds: string[],
-	from: 'create' | 'add'
+	selectedAddonIds: string[]
 ): Promise<{ nextSteps?: string; packageManager?: AgentName | null }> {
 	const selectedAddons: SelectedAddon[] = selectedAddonIds.map((id) => ({
 		type: 'official',
@@ -391,11 +390,6 @@ export async function runAddCommand(
 	const setups = selectedAddons.length ? selectedAddons.map(({ addon }) => addon) : officialAddons;
 	const addonSetupResults = setupAddons(setups, workspace);
 
-	// get all addons that have been marked to be preselected
-	const initialValues = Object.entries(addonSetupResults)
-		.filter(([_, value]) => value.defaultSelection[from] === true)
-		.map(([key]) => key);
-
 	// prompt which addons to apply
 	if (selectedAddons.length === 0) {
 		const addonOptions = officialAddons
@@ -410,8 +404,7 @@ export async function runAddCommand(
 		const selected = await p.multiselect({
 			message: `What would you like to add to your project? ${pc.dim('(use arrow keys / space bar)')}`,
 			options: addonOptions,
-			required: false,
-			initialValues
+			required: false
 		});
 		if (p.isCancel(selected)) {
 			p.cancel('Operation cancelled.');
diff --git a/packages/cli/commands/create.ts b/packages/cli/commands/create.ts
index b7ffcaa..5d259c3 100644
--- a/packages/cli/commands/create.ts
+++ b/packages/cli/commands/create.ts
@@ -184,8 +184,7 @@ async function createProject(cwd: ProjectPath, options: Options) {
 				community: [],
 				addons: {}
 			},
-			[],
-			'create'
+			[]
 		);
 		packageManager = pm;
 		addOnNextSteps = nextSteps;
diff --git a/packages/cli/lib/install.ts b/packages/cli/lib/install.ts
index 1ae3d87..86bef82 100644
--- a/packages/cli/lib/install.ts
+++ b/packages/cli/lib/install.ts
@@ -90,8 +90,7 @@ export function setupAddons(
 		const setupResult: AddonSetupResult = {
 			unsupported: [],
 			dependsOn: [],
-			runsAfter: [],
-			defaultSelection: { create: false, add: false }
+			runsAfter: []
 		};
 		addon.setup?.({
 			...workspace,
@@ -100,10 +99,7 @@ export function setupAddons(
 				setupResult.runsAfter.push(name);
 			},
 			unsupported: (reason) => setupResult.unsupported.push(reason),
-			runsAfter: (name) => setupResult.runsAfter.push(name),
-			defaultSelection: (defaultSelection) => {
-				setupResult.defaultSelection = defaultSelection;
-			}
+			runsAfter: (name) => setupResult.runsAfter.push(name)
 		});
 		addonSetupResults[addon.id] = setupResult;
 	}
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 5e2beb6..ecd2fa6 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "sv",
-	"version": "0.8.12",
+	"version": "0.8.13",
 	"type": "module",
 	"description": "A CLI for creating and updating SvelteKit projects",
 	"license": "MIT",
diff --git a/packages/core/addon/config.ts b/packages/core/addon/config.ts
index dd9daf0..fbce377 100644
--- a/packages/core/addon/config.ts
+++ b/packages/core/addon/config.ts
@@ -38,7 +38,6 @@ export type Addon<Args extends OptionDefinition> = {
 			dependsOn: (name: string) => void;
 			unsupported: (reason: string) => void;
 			runsAfter: (addonName: string) => void;
-			defaultSelection: (args: { create: boolean; add: boolean }) => void;
 		}
 	) => MaybePromise<void>;
 	run: (workspace: Workspace<Args> & { sv: SvApi }) => MaybePromise<void>;
@@ -61,12 +60,7 @@ export function defineAddon<Args extends OptionDefinition>(config: Addon<Args>):
 	return config;
 }
 
-export type AddonSetupResult = {
-	dependsOn: string[];
-	unsupported: string[];
-	runsAfter: string[];
-	defaultSelection: { create: boolean; add: boolean };
-};
+export type AddonSetupResult = { dependsOn: string[]; unsupported: string[]; runsAfter: string[] };
 
 export type AddonWithoutExplicitArgs = Addon<Record<string, Question>>;
 export type AddonConfigWithoutExplicitArgs = Addon<Record<string, Question>>;
diff --git a/packages/core/tooling/index.ts b/packages/core/tooling/index.ts
index 27e41cb..ac42aa4 100644
--- a/packages/core/tooling/index.ts
+++ b/packages/core/tooling/index.ts
@@ -77,22 +77,20 @@ export function parseScript(content: string): TsEstree.Program {
 
 	Walker.walk(ast as TsEstree.Node, null, {
 		_(commentNode, { next }) {
-			let comment = comments.shift();
+			let comment: TsEstree.Comment;
 
-			while (comment && comment.start! < commentNode.start!) {
-				commentNode.leadingComments ??= [];
-				commentNode.leadingComments.push(comment);
-				comment = comments.shift();
+			while (comments[0] && commentNode.start && comments[0].start! < commentNode.start) {
+				comment = comments.shift()!;
+				(commentNode.leadingComments ??= []).push(comment);
 			}
 
 			next();
 
-			comment = comments.shift();
-			if (comment) {
-				const slice = content.slice(commentNode.end, comment.start);
+			if (comments[0]) {
+				const slice = content.slice(commentNode.end, comments[0].start);
 
 				if (/^[,) \t]*$/.test(slice)) {
-					commentNode.trailingComments = [comment];
+					commentNode.trailingComments = [comments.shift()!];
 				}
 			}
 		}
diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json
index 9f06a6b..df37bca 100644
--- a/packages/core/tsconfig.json
+++ b/packages/core/tsconfig.json
@@ -5,5 +5,6 @@
 		"isolatedDeclarations": true,
 		"declaration": true
 	},
-	"include": ["index.ts"]
+	"include": ["*.ts", "tooling", "tests", "addon"],
+	"exclude": ["vitest.config.ts", "tests/**/input.ts", "tests/**/output.ts"]
 }


Test patch:
diff --git a/packages/core/tests/utils.ts b/packages/core/tests/utils.ts
index a2a4405..37979d0 100644
--- a/packages/core/tests/utils.ts
+++ b/packages/core/tests/utils.ts
@@ -170,3 +170,16 @@ test('integration - simple 2', () => {
 		}"
 	`);
 });
+
+test('integration - preserves comments', () => {
+	const code = dedent`
+	  /** @type {string} */
+    let foo = 'bar';
+    `;
+	const ast = parseScript(code);
+
+	expect(serializeScript(ast, code)).toMatchInlineSnapshot(`
+		"/** @type {string} */
+		let foo = 'bar';"
+	`);
+});