diff --git a/.changeset/early-kiwis-drum.md b/.changeset/early-kiwis-drum.md new file mode 100644 index 000000000..807173989 --- /dev/null +++ b/.changeset/early-kiwis-drum.md @@ -0,0 +1,5 @@ +--- +"sv": patch +--- + +fix(sv): set `engineStrict` in `pnpm-workspace.yaml` for pnpm projects, `engine-strict` in `.npmrc` otherwise diff --git a/packages/sv-utils/src/tests/transforms.ts b/packages/sv-utils/src/tests/transforms.ts index ad0620f7a..ebaadfe19 100644 --- a/packages/sv-utils/src/tests/transforms.ts +++ b/packages/sv-utils/src/tests/transforms.ts @@ -165,7 +165,7 @@ describe('transforms', () => { expect(result).toContain('name: new'); }); - it('abort: returns fals if transform is cacelled', () => { + it('abort: returns false if transform is cancelled', () => { const input = 'name: old\n'; expect(transforms.yaml(() => false)(input)).toBe(false); }); @@ -180,7 +180,7 @@ describe('transforms', () => { expect(result).toContain('name = "new"'); }); - it('abort: returns fals if transform is cacelled', () => { + it('abort: returns false if transform is cancelled', () => { const input = 'name = "old"\n'; expect(transforms.toml(() => false)(input)).toBe(false); }); diff --git a/packages/sv/src/cli/create.ts b/packages/sv/src/cli/create.ts index 4c666336a..b7b6b0841 100644 --- a/packages/sv/src/cli/create.ts +++ b/packages/sv/src/cli/create.ts @@ -17,6 +17,7 @@ import { formatFiles } from '../core/formatFiles.ts'; import { AGENT_NAMES, addAllowBuildsIfPnpm, + addEngineStrict, detectPackageManager, installDependencies, installOption, @@ -416,6 +417,7 @@ export async function createProject(cwd: ProjectPath, options: Options) { const addOnNextSteps = getNextSteps(addOnSuccessfulAddons, workspace, answers, addonSetupResults); + addEngineStrict({ cwd: projectPath, packageManager }); addAllowBuildsIfPnpm({ cwd: projectPath, packageManager, packages: ['esbuild'] }); let depsInstalled = false; diff --git a/packages/sv/src/create/templates/demo/.npmrc b/packages/sv/src/cli/tests/snapshots/@my-org/sv/.npmrc similarity index 100% rename from packages/sv/src/create/templates/demo/.npmrc rename to packages/sv/src/cli/tests/snapshots/@my-org/sv/.npmrc diff --git a/packages/sv/src/core/package-manager.ts b/packages/sv/src/core/package-manager.ts index 6c81cdafe..b2c56b5e2 100644 --- a/packages/sv/src/core/package-manager.ts +++ b/packages/sv/src/core/package-manager.ts @@ -9,7 +9,9 @@ import { color, detect, pnpm, - resolveCommand + resolveCommand, + transforms, + type TransformFn } from '@sveltejs/sv-utils'; import { Option } from 'commander'; import * as find from 'empathic/find'; @@ -132,17 +134,45 @@ function isInstalled(agent: AgentName): boolean { * `sv.file`, but the CLI itself runs outside that pipeline, so it locates (or creates) * `pnpm-workspace.yaml` by hand. */ -export function addAllowBuildsIfPnpm(options: { - cwd: string; - packageManager: AgentName | null | undefined; - packages: string[]; -}): void { +export function addAllowBuildsIfPnpm(options: ProjectOptions & { packages: string[] }): void { const { cwd, packageManager, packages } = options; if (packageManager !== 'pnpm') return; - const found = find.up('pnpm-workspace.yaml', { cwd }); - const filePath = found ?? path.join(cwd, 'pnpm-workspace.yaml'); - const content = found ? fs.readFileSync(found, 'utf-8') : ''; - const newContent = pnpm.allowBuilds({ cwd, packages })(content); + const filePath = find.up('pnpm-workspace.yaml', { cwd }) ?? path.join(cwd, 'pnpm-workspace.yaml'); + transformFile(filePath, pnpm.allowBuilds({ cwd, packages })); +} + +type ProjectOptions = { + cwd: string; + packageManager: AgentName | null | undefined; +}; + +/** pnpm reads its settings from `pnpm-workspace.yaml`, others from `.npmrc`. */ +export function addEngineStrict(options: ProjectOptions): void { + if (options.packageManager === 'pnpm') addEngineStrictForPnpm(options.cwd); + else addEngineStrictForNpm(options.cwd); +} + +function addEngineStrictForPnpm(cwd: string): void { + transformFile( + path.join(cwd, 'pnpm-workspace.yaml'), + transforms.yaml(({ data }) => { + if (data.get('engineStrict') !== undefined) return false; + data.set('engineStrict', true); + }) + ); +} + +function addEngineStrictForNpm(cwd: string): void { + transformFile( + path.join(cwd, '.npmrc'), + transforms.text(({ content, text }) => text.upsert(content, 'engine-strict', { value: 'true' })) + ); +} + +/** Missing file is treated as empty, so the transform can create it. */ +function transformFile(filePath: string, transform: TransformFn): void { + const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : ''; + const newContent = transform(content); if (newContent && newContent !== content) fs.writeFileSync(filePath, newContent, 'utf-8'); } diff --git a/packages/sv/src/create/templates/library/.npmrc b/packages/sv/src/create/templates/library/.npmrc deleted file mode 100644 index b6f27f135..000000000 --- a/packages/sv/src/create/templates/library/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/packages/sv/src/create/templates/minimal/.npmrc b/packages/sv/src/create/templates/minimal/.npmrc deleted file mode 100644 index b6f27f135..000000000 --- a/packages/sv/src/create/templates/minimal/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true