Skip to content
Open
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
22 changes: 22 additions & 0 deletions .changeset/coupling-sv-and-sv-utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'sv': minor
'@sveltejs/sv-utils': minor
---

feat: sv / sv-utils coupling, pnpm helpers, experimental add-ons, and API snapshots

**Highlights**

- Replace `sv.pnpmBuildDependency` with `sv.file` plus `pnpm.onlyBuiltDependencies` from `@sveltejs/sv-utils` and `file.findUp`.

**`@sveltejs/sv-utils`**

- Add `pnpm.onlyBuiltDependencies` to append packages to `onlyBuiltDependencies` in pnpm YAML via `transforms.yaml`.
- Type `YamlDocument` (`parse.yaml`) with `get` / `set` using `unknown` so consumers narrow explicitly; align YAML transforms with that contract.

**`sv`**

- Refactor workspace / engine / package-manager flows around file IO and package JSON loading (`loadFile`, `saveFile`, `loadPackageJson`), and trim workspace addon path handling; update addons accordingly.
- Reorganize the public `testing` entry for Vitest helpers and document the surface.
- Add generated `api-surface` markdown snapshots and a `scripts/generate-api-surface.js` helper (wired through the build) to track the public API.
- Remove deprecated `pnpmBuildDependency` usage and stop exporting internal pnpm-only-built helpers from the public `sv` surface.
5 changes: 5 additions & 0 deletions .changeset/lucky-dragons-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'sv': patch
---

chore: simplify `runes` option
6 changes: 0 additions & 6 deletions .changeset/remove-pnpm-build-dependency.md

This file was deleted.

6 changes: 0 additions & 6 deletions .changeset/some-rings-appear.md

This file was deleted.

2 changes: 1 addition & 1 deletion documentation/docs/50-api/20-sv-utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Return `false` from any transform callback to abort - the original content is re
import { transforms } from '@sveltejs/sv-utils';

sv.file(
file.eslintConfig,
'eslint.config.js',
transforms.script(({ ast, js }) => {
const { value: existing } = js.exports.createDefault(ast, { fallback: myConfig });
if (existing !== myConfig) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"scripts": {
"build": "tsdown",
"postbuild": "node scripts/generate-api-surface.js",
"changeset:publish": "changeset publish",
"check": "pnpm --parallel check",
"dev": "tsdown -w & pnpm --parallel check -w & wait",
Expand Down
6 changes: 6 additions & 0 deletions packages/sv-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @sveltejs/sv-utils

## 0.1.0
### Minor Changes


- feat: community add-ons are now **experimental** ([#1020](https://github.com/sveltejs/cli/pull/1020))

## 0.0.5
### Patch Changes

Expand Down
27 changes: 1 addition & 26 deletions packages/sv-utils/api-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,15 +742,6 @@ type Package = {
keywords?: string[];
workspaces?: string[];
};
declare const commonFilePaths: {
readonly packageJson: 'package.json';
readonly svelteConfig: 'svelte.config.js';
readonly svelteConfigTS: 'svelte.config.ts';
readonly jsconfig: 'jsconfig.json';
readonly tsconfig: 'tsconfig.json';
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;
Expand All @@ -761,18 +752,6 @@ declare function loadPackageJson(cwd: 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 @@ -810,15 +789,13 @@ export {
index_d_exports as Walker,
type YamlDocument,
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,
Expand All @@ -827,15 +804,13 @@ export {
loadPackageJson,
parse,
pnpm_d_exports as pnpm,
readFile,
resolveCommand,
resolveCommandArray,
sanitizeName,
saveFile,
splitVersion,
index_d_exports$4 as svelte,
text_d_exports as text,
transforms,
writeFile
transforms
};
```
2 changes: 1 addition & 1 deletion packages/sv-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sveltejs/sv-utils",
"version": "0.0.5",
"version": "0.1.0",
"type": "module",
"description": "Utility functions for sv",
"license": "MIT",
Expand Down
29 changes: 2 additions & 27 deletions packages/sv-utils/src/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ export type Package = {
workspaces?: string[];
};

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;

export function fileExists(cwd: string, filePath: string): boolean {
const fullFilePath = path.resolve(cwd, filePath);
return fs.existsSync(fullFilePath);
Expand Down Expand Up @@ -60,27 +50,12 @@ export function loadPackageJson(cwd: string): {
data: Package;
generateCode: () => string;
} {
const packageText = loadFile(cwd, commonFilePaths.packageJson);
const packageText = loadFile(cwd, 'package.json');
if (!packageText) {
const pkgPath = path.join(cwd, commonFilePaths.packageJson);
const pkgPath = path.join(cwd, 'package.json');
throw new Error(`Invalid workspace: missing '${pkgPath}'`);
}

const { data, generateCode } = parseJson(packageText);
return { source: packageText, data: data as Package, generateCode };
}

/**
* @deprecated Use {@link loadFile} instead. This alias will be removed in a future version.
*/
export const readFile: typeof loadFile = loadFile;

/**
* @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: 1 addition & 21 deletions packages/sv-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,7 @@ export { sanitizeName } from './sanitize.ts';
export { downloadJson } from './downloadJson.ts';

// File system helpers (sync, workspace-relative paths)
export {
commonFilePaths,
fileExists,
loadFile,
loadPackageJson,
saveFile,
type Package
} 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';
export { fileExists, loadFile, loadPackageJson, saveFile, type Package } from './files.ts';

// Terminal styling
export { color } from './color.ts';
Expand Down
4 changes: 3 additions & 1 deletion packages/sv-utils/src/pnpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { transforms, type TransformFn } from './tooling/transforms.ts';
*/
export function onlyBuiltDependencies(...packages: string[]): TransformFn {
return transforms.yaml(({ data }) => {
const existing = data.get('onlyBuiltDependencies');
const existing = data.get('onlyBuiltDependencies') as
| { items?: Array<{ value: string } | string> }
| undefined;
const items: Array<{ value: string } | string> = existing?.items ?? [];
for (const pkg of packages) {
if (items.includes(pkg)) continue;
Expand Down
12 changes: 12 additions & 0 deletions packages/sv/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# sv

## 0.14.0
### Minor Changes


- feat: community add-ons are now **experimental** ([#1020](https://github.com/sveltejs/cli/pull/1020))


### Patch Changes

- Updated dependencies [[`c0e5831`](https://github.com/sveltejs/cli/commit/c0e583126279afe7aff8cebb03c5b3928d73b521)]:
- @sveltejs/sv-utils@0.1.0

## 0.13.2
### Patch Changes

Expand Down
28 changes: 0 additions & 28 deletions packages/sv/api-surface-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,6 @@ type CreateProject = (options: {
variant: ProjectVariant;
clean?: boolean;
}) => string;
type SetupOptions = {
cwd: string;
variants: readonly ProjectVariant[];
clean?: boolean;
};
/** @deprecated Internal helper used by `createSetupTest` - will be removed from public API in a future version. */
declare function setup({ cwd, clean, variants }: SetupOptions): {
templatesDir: string;
};
type CreateOptions = {
cwd: string;
testName: string;
templatesDir: string;
};
/** @deprecated Internal helper used by `createSetupTest` - will be removed from public API in a future version. */
declare function createProject({ cwd, testName, templatesDir }: CreateOptions): CreateProject;
type PreviewOptions = {
cwd: string;
command?: string;
};
/** @deprecated Internal helper used by `prepareServer` - will be removed from public API in a future version. */
declare function startPreview({ cwd, command }: PreviewOptions): Promise<{
url: string;
close: () => Promise<void>;
}>;
declare module 'vitest' {
interface ProvidedContext {
testDir: string;
Expand Down Expand Up @@ -102,12 +77,9 @@ export {
ProjectVariant,
SetupTestOptions,
VitestContext,
createProject,
createSetupTest,
prepareServer,
setup,
setupGlobal,
startPreview,
variants
};
```
3 changes: 1 addition & 2 deletions packages/sv/api-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ type Options = {
template: TemplateType;
types: LanguageType;
};
declare function create(cwd: string, options: Omit<Options, 'cwd'>): void;
declare function create(options: Options): void;
declare function create({ cwd, ...options }: Options): void;
type FileEditor = Workspace & {
content: string;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/sv/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sv",
"version": "0.13.2",
"version": "0.14.0",
"type": "module",
"description": "A command line interface (CLI) for creating and maintaining Svelte applications",
"license": "MIT",
Expand Down
28 changes: 21 additions & 7 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, commonFilePaths, loadPackageJson, resolveCommandArray } from '@sveltejs/sv-utils';
import { color, loadPackageJson, resolveCommandArray } from '@sveltejs/sv-utils';
import { Command, Option } from 'commander';
import fs from 'node:fs';
import path from 'node:path';
Expand Down Expand Up @@ -258,14 +258,25 @@ async function createProject(cwd: ProjectPath, options: Options) {
const projectPath = path.resolve(directory);
const basename = path.basename(projectPath);
const parentDirName = path.basename(path.dirname(projectPath));
const projectName = parentDirName.startsWith('@') ? `${parentDirName}/${basename}` : basename;
let projectName = parentDirName.startsWith('@') ? `${parentDirName}/${basename}` : basename;

if (template === 'addon' && !projectName.startsWith('@')) {
// At this stage, we don't support un-scoped add-ons
// FYI: a demo exists for `npx sv add my-cool-addon`
common.errorAndExit(
`Community add-ons must be published under an npm org (e.g. ${color.command('@my-org/sv')}). Unscoped package names are not supported at this stage.`
);
const org = await p.text({
message: `Community add-ons must be published under an npm org. Enter the name of your npm org:`,
placeholder: ' @my-org',
validate: (value) => {
if (!value) return 'Organization name is required';
if (!value.startsWith('@')) return 'Must start with @';
if (value.includes('/')) return 'Just the org, not the full package name';
}
});
if (p.isCancel(org)) {
p.cancel('Operation cancelled.');
process.exit(0);
}
projectName = `${org}/${basename}`;
}

if (template === 'addon' && options.add.length > 0) {
Expand Down Expand Up @@ -468,8 +479,11 @@ export async function createVirtualWorkspace({
language: type === 'typescript' ? 'ts' : 'js',
file: {
...tentativeWorkspace.file,
viteConfig: type === 'typescript' ? commonFilePaths.viteConfigTS : commonFilePaths.viteConfig,
svelteConfig: commonFilePaths.svelteConfig // currently we always use js files, never typescript files
viteConfig:
type === 'typescript'
? common.commonFilePaths.viteConfigTS
: common.commonFilePaths.viteConfig,
svelteConfig: common.commonFilePaths.svelteConfig // currently we always use js files, never typescript files
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const browser = false;
const { test, prepareServer, testCases } = setupTest(
{ addon },
{
kinds: [{ type: 'default', options: { addon: { who: 'you' } } }],
kinds: [{ type: 'default', options: { [addon.id]: { who: 'you' } } }],
filter: (testCase) => testCase.variant.includes('kit'),
browser
}
Expand All @@ -21,15 +21,18 @@ test.concurrent.for(testCases)(
async (testCase, { page, ...ctx }) => {
const cwd = ctx.cwd(testCase);

const msg =
"This is a text file made by the Community Addon Template demo for the add-on: '@my-org/sv'!";
const msg = "Community Addon Template demo for the add-on: '@my-org/sv'!";

const contentPath = path.resolve(cwd, `src/lib/@my-org/sv/content.txt`);
const contentContent = fs.readFileSync(contentPath, 'utf8');

// Check if we have the imports
expect(contentContent).toContain(msg);

const helloPath = path.resolve(cwd, `src/lib/@my-org/sv/HelloComponent.svelte`);
const helloContent = fs.readFileSync(helloPath, 'utf8');
// Check if we have the imports
expect(helloContent).toContain('you');

// For browser testing
if (browser) {
const { close } = await prepareServer({ cwd, page });
Expand Down
Loading
Loading