Skip to content

Commit 7cf5b27

Browse files
committed
some updates!
1 parent 6662269 commit 7cf5b27

File tree

28 files changed

+699
-58
lines changed

28 files changed

+699
-58
lines changed

packages/sv/lib/cli/add/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -848,11 +848,12 @@ async function resolveCommunityAddons(cwd: string, community: string[]) {
848848
});
849849
p.log.message(packageInfos.join('\n'));
850850

851-
const confirm = await p.confirm({ message: 'Would you like to continue?' });
852-
if (confirm !== true) {
853-
p.cancel('Operation cancelled.');
854-
process.exit(1);
855-
}
851+
// TODO JYC: remove for testing for now
852+
// const confirm = await p.confirm({ message: 'Would you like to continue?' });
853+
// if (confirm !== true) {
854+
// p.cancel('Operation cancelled.');
855+
// process.exit(1);
856+
// }
856857

857858
start('Downloading community add-on packages');
858859
const details = await Promise.all(pkgs.map(async (opts) => downloadPackage(opts)));

packages/sv/lib/cli/create.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,10 @@ async function createProject(cwd: ProjectPath, options: Options) {
219219
const workspace = await createVirtualWorkspace({
220220
cwd: projectPath,
221221
template,
222-
type: language
222+
type: language as LanguageType
223223
});
224224

225-
if ((options.addOns || options.add.length > 0) && options.template !== 'addon') {
225+
if (options.template !== 'addon' && (options.addOns || options.add.length > 0)) {
226226
const addons = options.add.reduce(addonArgsHandler, []);
227227
sanitizedAddonsMap = sanitizeAddons(addons).reduce<Record<string, string[] | undefined>>(
228228
(acc, curr) => {
@@ -252,7 +252,7 @@ async function createProject(cwd: ProjectPath, options: Options) {
252252
createKit(projectPath, {
253253
name: projectName,
254254
template,
255-
types: language
255+
types: language as LanguageType
256256
});
257257

258258
if (options.fromPlayground) {
@@ -264,7 +264,7 @@ async function createProject(cwd: ProjectPath, options: Options) {
264264
let addOnNextSteps: string[] = [];
265265
let argsFormattedAddons: string[] = [];
266266
let addOnFilesToFormat: string[] = [];
267-
if (options.addOns || options.add.length > 0) {
267+
if (options.template !== 'addon' && (options.addOns || options.add.length > 0)) {
268268
const {
269269
nextSteps,
270270
argsFormattedAddons: argsFormatted,

packages/sv/lib/cli/tests/cli.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import fs from 'node:fs';
66
import { parseJson } from '../../core/tooling/index.ts';
77

88
const monoRepoPath = path.resolve(__dirname, '..', '..', '..', '..', '..');
9+
const svBinPath = path.resolve(monoRepoPath, 'packages', 'sv', 'dist', 'bin.mjs');
910

1011
beforeAll(() => {
1112
const testOutputCliPath = path.resolve(monoRepoPath, '.test-output', 'cli');
@@ -36,15 +37,20 @@ describe('cli', () => {
3637
'mcp=ide:claude-code,cursor,gemini,opencode,vscode,other+setup:local'
3738
// 'storybook' // No storybook addon during tests!
3839
]
40+
},
41+
{
42+
projectName: 'create-addon',
43+
template: 'addon',
44+
types: 'jsdoc',
45+
args: ['--no-add-ons']
3946
}
4047
];
4148

4249
it.for(testCases)(
4350
'should create a new project with name $projectName',
4451
{ timeout: 10_000 },
4552
async (testCase) => {
46-
const { projectName, args } = testCase;
47-
const svBinPath = path.resolve(monoRepoPath, 'packages', 'sv', 'dist', 'bin.mjs');
53+
const { projectName, args, template = 'minimal', types = 'ts' } = testCase;
4854
const testOutputPath = path.resolve(monoRepoPath, '.test-output', 'cli', projectName);
4955

5056
const result = await exec(
@@ -54,9 +60,9 @@ describe('cli', () => {
5460
'create',
5561
testOutputPath,
5662
'--template',
57-
'minimal',
63+
template,
5864
'--types',
59-
'ts',
65+
types,
6066
'--no-install',
6167
...args
6268
],
@@ -105,6 +111,22 @@ describe('cli', () => {
105111
`file "${relativeFile}" does not match snapshot`
106112
);
107113
}
114+
115+
if (template === 'addon') {
116+
const cmds = [
117+
['i'],
118+
['run', 'demo-create'],
119+
['run', 'demo-add'],
120+
// TODO JYC: check is failing because it's requesting kit! :o
121+
['run', 'check']
122+
];
123+
for (const cmd of cmds) {
124+
const res = await exec('npm', cmd, {
125+
nodeOptions: { stdio: 'pipe', cwd: testOutputPath }
126+
});
127+
expect(res.exitCode, `Error with cmd: '${cmd}' -> ${res.stderr}`).toBe(0);
128+
}
129+
}
108130
}
109131
);
110132
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
node_modules
2+
demo/
3+
4+
# Output
5+
.output
6+
.vercel
7+
.netlify
8+
.wrangler
9+
/.svelte-kit
10+
/build
11+
/dist
12+
13+
# OS
14+
.DS_Store
15+
Thumbs.db
16+
17+
# Env
18+
.env
19+
.env.*
20+
!.env.example
21+
!.env.test
22+
23+
# Vite
24+
vite.config.js.timestamp-*
25+
vite.config.ts.timestamp-*
26+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# sv community addon: create-addon
2+
3+
> [!IMPORTANT]
4+
> Community add-ons are currently not supported. Please see [#184](https://github.com/sveltejs/cli/issues/184) for details.
5+
6+
> [!IMPORTANT]
7+
> This template's dependencies may not be up-to-date; be sure to update them to the latest!
8+
9+
> If you get stuck, check out the [implementations of official add-ons](https://github.com/sveltejs/cli/tree/main/packages/addons).
10+
11+
created with [`sv`](https://svelte.dev/docs/cli/sv-create#Options-template-name).
12+
13+
## Using the add-on
14+
15+
To run the add-on, we'll first need a project to apply it to.
16+
17+
Create the project with the following script:
18+
19+
```shell
20+
npm run demo-create
21+
```
22+
23+
This will create a SvelteKit project in the `demo` directory.
24+
25+
To execute the add-on, run:
26+
27+
```shell
28+
npm run demo-add
29+
```
30+
31+
## Sharing your add-on
32+
33+
When you're ready to publish your add-on to npm, run:
34+
35+
```shell
36+
npm publish
37+
```
38+
39+
Your published add-on can now be used by anyone!
40+
41+
To execute the newly published package with `sv`, run:
42+
43+
```shell
44+
npx sv add npm:create-addon
45+
```
46+
47+
## Things to be aware of
48+
49+
Community add-ons are **not permitted** to have any external dependencies outside of `sv`. If the use of a dependency is absolutely necessary, then they can be bundled using a bundler of your choosing (e.g. Rollup, Rolldown, tsup, etc.).
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"extends": "./.svelte-kit/tsconfig.json",
3+
"compilerOptions": {
4+
"allowJs": true,
5+
"checkJs": true,
6+
"esModuleInterop": true,
7+
"forceConsistentCasingInFileNames": true,
8+
"resolveJsonModule": true,
9+
"skipLibCheck": true,
10+
"sourceMap": true,
11+
"strict": true,
12+
"moduleResolution": "bundler"
13+
}
14+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
15+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
16+
//
17+
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
18+
// from the referenced tsconfig.json - TypeScript does not merge them in
19+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "create-addon",
3+
"version": "0.0.0",
4+
"type": "module",
5+
"license": "MIT",
6+
"scripts": {
7+
"demo-create": "sv create demo --types ts --template minimal --no-add-ons --no-install",
8+
"demo-add": "sv add -C demo --community file:../ --no-git-check --no-install",
9+
"test": "vitest run",
10+
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
11+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
12+
},
13+
"files": [
14+
"src",
15+
"!src/**/*.test.*"
16+
],
17+
"exports": "./src/index.js",
18+
"dependencies": {
19+
"sv": "file:../../packages/sv"
20+
},
21+
"devDependencies": {
22+
"@playwright/test": "^1.56.1",
23+
"svelte-check": "^4.3.4",
24+
"typescript": "^5.9.3",
25+
"vitest": "4.0.7"
26+
},
27+
"keywords": [
28+
"svelte-add-on",
29+
"sv",
30+
"sv-add-on"
31+
]
32+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { js, parseSvelte, defineAddon, defineAddonOptions, svelte } from 'sv/core';
2+
3+
export const options = defineAddonOptions()
4+
// .add('demo', {
5+
// question: 'Do you want to use a demo?',
6+
// type: 'boolean',
7+
// default: false
8+
// })
9+
.build();
10+
11+
export default defineAddon({
12+
id: 'create-addon',
13+
options,
14+
setup: ({ kit, unsupported }) => {
15+
if (!kit) unsupported('Requires SvelteKit');
16+
},
17+
run: ({ sv, options, typescript }) => {
18+
sv.file(`src/lib/create-addon/addon-template-demo.txt`, (content) => {
19+
// if (!options.demo) return content;
20+
return `This is a text file made by the Community Addon Template demo! with your add-on: create-addon!`;
21+
});
22+
23+
sv.file(`src/lib/create-addon/DemoComponent.svelte`, (content) => {
24+
// if (!options.demo) return content;
25+
const { ast, generateCode } = parseSvelte(content);
26+
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });
27+
28+
js.imports.addDefault(scriptAst, { from: './addon-template-demo.txt?raw', as: 'demo' });
29+
30+
return generateCode();
31+
});
32+
33+
sv.file('src/routes/+page.svelte', (content) => {
34+
// if (!options.demo) return content;
35+
const { ast, generateCode } = parseSvelte(content);
36+
const scriptAst = svelte.ensureScript(ast, { langTs: typescript });
37+
38+
js.imports.addDefault(scriptAst, {
39+
from: `$lib/create-addon/DemoComponent.svelte`,
40+
as: 'DemoComponent'
41+
});
42+
43+
ast.fragment.nodes.push(...svelte.toFragment('<DemoComponent />'));
44+
45+
return generateCode();
46+
});
47+
}
48+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import adapter from '@sveltejs/adapter-auto';
2+
3+
/** @type {import('@sveltejs/kit').Config} */
4+
const config = {
5+
kit: {
6+
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
7+
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
8+
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
9+
adapter: adapter()
10+
}
11+
};
12+
13+
export default config;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import path from 'node:path';
2+
import { expect } from '@playwright/test';
3+
import { fixture, setupTest } from './setup/suite.js';
4+
import addon from '../src/index.js';
5+
6+
const id = addon.id;
7+
const { test, variants, prepareServer } = setupTest({ [id]: addon });
8+
9+
test.concurrent.for(variants)('demo - %s', async (variant, { page, ...ctx }) => {
10+
const cwd = await ctx.run(variant, { [id]: { demo: true } });
11+
12+
// ...add files
13+
if (variant.startsWith('kit')) {
14+
const target = path.resolve(cwd, 'src', 'routes', '+page.svelte');
15+
fixture({ name: '+page.svelte', target });
16+
} else {
17+
const target = path.resolve(cwd, 'src', 'App.svelte');
18+
fixture({ name: 'App.svelte', target });
19+
}
20+
21+
const { close } = await prepareServer({ cwd, page });
22+
// kill server process when we're done
23+
ctx.onTestFinished(async () => await close());
24+
25+
// expectations
26+
const textContent = await page.getByTestId('demo').textContent();
27+
expect(textContent).toContain('This is a text file made by the Community Addon Template demo!');
28+
});

0 commit comments

Comments
 (0)