Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions packages/sv-utils/api-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -1257,22 +1257,6 @@ type Package = {
keywords?: string[];
workspaces?: string[];
};
declare function getPackageJson(cwd: string): {
source: string;
data: Package;
generateCode: () => string;
};
declare function readFile(cwd: string, filePath: string): string;
declare function fileExists(cwd: string, filePath: string): boolean;
declare function writeFile(cwd: string, filePath: string, content: string): void;
/**
* @deprecated Internal to sv — merged into `package.json` by the add-on runner only. Will be removed from the public API in a future version.
*/
declare function installPackages(dependencies: Array<{
pkg: string;
version: string;
dev: boolean;
}>, cwd: string): string;
declare const commonFilePaths: {
readonly packageJson: "package.json";
readonly svelteConfig: "svelte.config.js";
Expand All @@ -1282,6 +1266,28 @@ declare const commonFilePaths: {
readonly viteConfig: "vite.config.js";
readonly viteConfigTS: "vite.config.ts";
};
declare function fileExists(cwd: string, filePath: string): boolean;

declare function loadFile(cwd: string, filePath: string): string;

declare function saveFile(cwd: string, filePath: string, content: string): void;
declare function loadPackageJson(cwd: string): {
source: string;
data: Package;
generateCode: () => string;
};
/**
* @deprecated Use {@link loadFile} instead. This alias will be removed in a future version.
*/
declare const readFile: typeof loadFile;
/**
* @deprecated Use {@link saveFile} instead. This alias will be removed in a future version.
*/
declare const writeFile: typeof saveFile;
/**
* @deprecated Use {@link loadPackageJson} instead. This alias will be removed in a future version.
*/
declare const getPackageJson: typeof loadPackageJson;
type ColorInput = string | string[];
declare const color: {
addon: (str: ColorInput) => string;
Expand Down Expand Up @@ -1309,5 +1315,5 @@ declare const parse: {
toml: typeof parseToml;
yaml: typeof parseYaml;
};
export { AGENTS, type AgentName, type estree as AstTypes, COMMANDS, type Comments, type Package, type SvelteAst, type TransformFn, index_d_exports as Walker, color, commonFilePaths, constructCommand, createPrinter, index_d_exports$1 as css, dedent, detect, downloadJson, fileExists, getPackageJson, index_d_exports$2 as html, installPackages, isVersionUnsupportedBelow, index_d_exports$3 as js, json_d_exports as json, parse, readFile, resolveCommand, resolveCommandArray, sanitizeName, splitVersion, index_d_exports$4 as svelte, text_d_exports as text, transforms, writeFile };
export { AGENTS, type AgentName, type estree as AstTypes, COMMANDS, type Comments, type Package, type SvelteAst, type TransformFn, index_d_exports as Walker, color, commonFilePaths, constructCommand, createPrinter, index_d_exports$1 as css, dedent, detect, downloadJson, fileExists, getPackageJson, index_d_exports$2 as html, isVersionUnsupportedBelow, index_d_exports$3 as js, json_d_exports as json, loadFile, loadPackageJson, parse, readFile, resolveCommand, resolveCommandArray, sanitizeName, saveFile, splitVersion, index_d_exports$4 as svelte, text_d_exports as text, transforms, writeFile };
```
98 changes: 40 additions & 58 deletions packages/sv-utils/src/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,23 @@ export type Package = {
workspaces?: string[];
};

export function getPackageJson(cwd: string): {
source: string;
data: Package;
generateCode: () => string;
} {
const packageText = readFile(cwd, commonFilePaths.packageJson);
if (!packageText) {
const pkgPath = path.join(cwd, commonFilePaths.packageJson);
throw new Error(`Invalid workspace: missing '${pkgPath}'`);
}
export const commonFilePaths = {
packageJson: 'package.json',
svelteConfig: 'svelte.config.js',
svelteConfigTS: 'svelte.config.ts',
jsconfig: 'jsconfig.json',
tsconfig: 'tsconfig.json',
viteConfig: 'vite.config.js',
viteConfigTS: 'vite.config.ts'
} as const;

const { data, generateCode } = parseJson(packageText);
return { source: packageText, data: data as Package, generateCode };
export function fileExists(cwd: string, filePath: string): boolean {
const fullFilePath = path.resolve(cwd, filePath);
return fs.existsSync(fullFilePath);
}

export function readFile(cwd: string, filePath: string): string {
/** Synchronous load of a workspace-relative file as UTF-8 text; missing files yield `''`. */
export function loadFile(cwd: string, filePath: string): string {
const fullFilePath = path.resolve(cwd, filePath);

if (!fileExists(cwd, filePath)) {
Expand All @@ -40,12 +41,8 @@ export function readFile(cwd: string, filePath: string): string {
return text;
}

export function fileExists(cwd: string, filePath: string): boolean {
const fullFilePath = path.resolve(cwd, filePath);
return fs.existsSync(fullFilePath);
}

export function writeFile(cwd: string, filePath: string, content: string): void {
/** Synchronous write of a workspace-relative file (creates parent dirs). */
export function saveFile(cwd: string, filePath: string, content: string): void {
const fullFilePath = path.resolve(cwd, filePath);
const fullDirectoryPath = path.dirname(fullFilePath);

Expand All @@ -58,47 +55,32 @@ export function writeFile(cwd: string, filePath: string, content: string): void
fs.writeFileSync(fullFilePath, content, 'utf8');
}

/**
* @deprecated Internal to sv — merged into `package.json` by the add-on runner only. Will be removed from the public API in a future version.
*/
export function installPackages(
dependencies: Array<{ pkg: string; version: string; dev: boolean }>,
cwd: string
): string {
const { data, generateCode } = getPackageJson(cwd);

for (const dependency of dependencies) {
if (dependency.dev) {
data.devDependencies ??= {};
data.devDependencies[dependency.pkg] = dependency.version;
} else {
data.dependencies ??= {};
data.dependencies[dependency.pkg] = dependency.version;
}
export function loadPackageJson(cwd: string): {
source: string;
data: Package;
generateCode: () => string;
} {
const packageText = loadFile(cwd, commonFilePaths.packageJson);
if (!packageText) {
const pkgPath = path.join(cwd, commonFilePaths.packageJson);
throw new Error(`Invalid workspace: missing '${pkgPath}'`);
}

if (data.dependencies) data.dependencies = alphabetizeProperties(data.dependencies);
if (data.devDependencies) data.devDependencies = alphabetizeProperties(data.devDependencies);

writeFile(cwd, commonFilePaths.packageJson, generateCode());
return commonFilePaths.packageJson;
const { data, generateCode } = parseJson(packageText);
return { source: packageText, data: data as Package, generateCode };
}

function alphabetizeProperties(obj: Record<string, string>) {
const orderedObj: Record<string, string> = {};
const sortedEntries = Object.entries(obj).sort(([a], [b]) => a.localeCompare(b));
for (const [key, value] of sortedEntries) {
orderedObj[key] = value;
}
return orderedObj;
}
/**
* @deprecated Use {@link loadFile} instead. This alias will be removed in a future version.
*/
export const readFile: typeof loadFile = loadFile;

export const commonFilePaths = {
packageJson: 'package.json',
svelteConfig: 'svelte.config.js',
svelteConfigTS: 'svelte.config.ts',
jsconfig: 'jsconfig.json',
tsconfig: 'tsconfig.json',
viteConfig: 'vite.config.js',
viteConfigTS: 'vite.config.ts'
} as const;
/**
* @deprecated Use {@link saveFile} instead. This alias will be removed in a future version.
*/
export const writeFile: typeof saveFile = saveFile;

/**
* @deprecated Use {@link loadPackageJson} instead. This alias will be removed in a future version.
*/
export const getPackageJson: typeof loadPackageJson = loadPackageJson;
22 changes: 16 additions & 6 deletions packages/sv-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,28 @@ export { createPrinter } from './utils.ts';
export { sanitizeName } from './sanitize.ts';
export { downloadJson } from './downloadJson.ts';

// File system helpers
// File system helpers (sync, workspace-relative paths)
export {
commonFilePaths,
fileExists,
getPackageJson,
readFile,
writeFile,
loadFile,
loadPackageJson,
saveFile,
type Package
} from './files.ts';

/** @deprecated Internal to sv — will be removed from the public API in a future version. */
export { installPackages } from './files.ts';
/**
* @deprecated Use {@link loadFile} instead. This alias will be removed in a future version.
*/
export { readFile } from './files.ts';
/**
* @deprecated Use {@link saveFile} instead. This alias will be removed in a future version.
*/
export { writeFile } from './files.ts';
/**
* @deprecated Use {@link loadPackageJson} instead. This alias will be removed in a future version.
*/
export { getPackageJson } from './files.ts';

// Terminal styling
export { color } from './color.ts';
Expand Down
3 changes: 0 additions & 3 deletions packages/sv/api-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ type Options = {
template: TemplateType;
types: LanguageType;
};
/** @deprecated Use `create({ cwd, name, template, types })` instead. */
declare function create(cwd: string, options: Omit<Options, "cwd">): void;
declare function create(options: Options): void;
/** @deprecated Unused type, will be removed in a future version. */
type FileEditor = Workspace & {
content: string;
};
/** @deprecated Unused type, will be removed in a future version. */
type FileType = {
name: (options: Workspace) => string;
condition?: ConditionDefinition;
Expand Down
2 changes: 1 addition & 1 deletion packages/sv/src/addons/drizzle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export default defineAddon({
const hasPrettier = Boolean(dependencyVersion('prettier'));
if (hasPrettier) {
sv.file(
file.prettierignore,
'.prettierignore',
transforms.text(({ content, text }) => text.upsert(content, '/drizzle/'))
);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/sv/src/addons/eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default defineAddon({
);

sv.file(
file.eslintConfig,
'eslint.config.js',
transforms.script(({ ast, comments, js }) => {
const eslintConfigs: Array<AstTypes.Expression | AstTypes.SpreadElement> = [];
js.imports.addDefault(ast, { from: './svelte.config.js', as: 'svelteConfig' });
Expand Down Expand Up @@ -156,14 +156,14 @@ export default defineAddon({
);

sv.file(
file.vscodeExtensions,
'.vscode/extensions.json',
transforms.json(({ data, json }) => {
json.arrayUpsert(data, 'recommendations', 'dbaeumer.vscode-eslint');
})
);

if (prettierInstalled) {
sv.file(file.eslintConfig, addEslintConfigPrettier);
sv.file('eslint.config.js', addEslintConfigPrettier);
}
}
});
8 changes: 4 additions & 4 deletions packages/sv/src/addons/prettier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default defineAddon({
sv.devDependency('prettier-plugin-svelte', '^3.4.1');

sv.file(
file.prettierignore,
'.prettierignore',
transforms.text(({ content }) => {
if (content) return false;
return dedent`
Expand All @@ -34,7 +34,7 @@ export default defineAddon({
);

sv.file(
file.prettierrc,
'.prettierrc',
transforms.json(
({ data, json }) => {
if (Object.keys(data).length === 0) {
Expand Down Expand Up @@ -82,7 +82,7 @@ export default defineAddon({
);

sv.file(
file.vscodeExtensions,
'.vscode/extensions.json',
transforms.json(({ data, json }) => {
json.arrayUpsert(data, 'recommendations', 'esbenp.prettier-vscode');
})
Expand All @@ -98,7 +98,7 @@ export default defineAddon({

if (eslintInstalled) {
sv.devDependency('eslint-config-prettier', '^10.1.8');
sv.file(file.eslintConfig, addEslintConfigPrettier);
sv.file('eslint.config.js', addEslintConfigPrettier);
}
}
});
Expand Down
4 changes: 2 additions & 2 deletions packages/sv/src/addons/sveltekit-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
text,
transforms,
fileExists,
getPackageJson,
loadPackageJson,
sanitizeName
} from '@sveltejs/sv-utils';
import { defineAddon, defineAddonOptions } from '../core/config.ts';
Expand Down Expand Up @@ -140,7 +140,7 @@ export default defineAddon({
}

if (!data.name) {
const pkg = getPackageJson(cwd);
const pkg = loadPackageJson(cwd);
data.name = sanitizeName(pkg.data.name, 'wrangler');
}

Expand Down
6 changes: 3 additions & 3 deletions packages/sv/src/addons/tailwindcss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,23 @@ export default defineAddon({
}

sv.file(
file.vscodeSettings,
'.vscode/settings.json',
transforms.json(({ data }) => {
data['files.associations'] ??= {};
data['files.associations']['*.css'] = 'tailwindcss';
})
);

sv.file(
file.vscodeExtensions,
'.vscode/extensions.json',
transforms.json(({ data, json }) => {
json.arrayUpsert(data, 'recommendations', 'bradlc.vscode-tailwindcss');
})
);

if (prettierInstalled) {
sv.file(
file.prettierrc,
'.prettierrc',
transforms.json(({ data, json }) => {
json.arrayUpsert(data, 'plugins', 'prettier-plugin-tailwindcss');
data.tailwindStylesheet ??= file.getRelative({ to: file.stylesheet });
Expand Down
4 changes: 2 additions & 2 deletions packages/sv/src/cli/create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as p from '@clack/prompts';
import { color, resolveCommandArray, commonFilePaths, getPackageJson } from '@sveltejs/sv-utils';
import { color, resolveCommandArray, commonFilePaths, loadPackageJson } from '@sveltejs/sv-utils';
import { Command, Option } from 'commander';
import fs from 'node:fs';
import path from 'node:path';
Expand Down Expand Up @@ -465,7 +465,7 @@ export async function createVirtualWorkspace({

// Let's read the package.json of the template we will use and add the dependencies to the override
const templatePackageJsonPath = dist(`templates/${template}`);
const { data: packageJson } = getPackageJson(templatePackageJsonPath);
const { data: packageJson } = loadPackageJson(templatePackageJsonPath);
override.dependencies = {
...packageJson.devDependencies,
...packageJson.dependencies,
Expand Down
Loading
Loading