diff --git a/packages/create-rstack/README.md b/packages/create-rstack/README.md index 34d9bbc7..6b2da8f1 100644 --- a/packages/create-rstack/README.md +++ b/packages/create-rstack/README.md @@ -23,6 +23,8 @@ npx create-rstack -d my-project -t app-ts - `app-js` - JavaScript application - `app-ts` - TypeScript application +- `lib-js` - JavaScript Node.js library +- `lib-ts` - TypeScript Node.js library ## Documentation diff --git a/packages/create-rstack/src/index.ts b/packages/create-rstack/src/index.ts index 6054a8cf..9f7b851e 100644 --- a/packages/create-rstack/src/index.ts +++ b/packages/create-rstack/src/index.ts @@ -14,6 +14,16 @@ const getTemplateName = async ({ template }: Argv): Promise => { return `${type}-${language}`; } + const projectType = checkCancel( + await select({ + message: 'Select project type', + options: [ + { value: 'app', label: 'Web Application' }, + { value: 'lib', label: 'Library' }, + ], + }), + ); + const language = checkCancel( await select({ message: 'Select language', @@ -24,7 +34,7 @@ const getTemplateName = async ({ template }: Argv): Promise => { }), ); - return `app-${language}`; + return `${projectType}-${language}`; }; const mapESLintTemplate = (templateName: string): ESLintTemplateName => @@ -36,7 +46,7 @@ const mapRslintTemplate = (templateName: string): RslintTemplateName => await create({ root: path.join(import.meta.dirname, '..'), name: 'rstack', - templates: ['app-js', 'app-ts'], + templates: ['app-js', 'app-ts', 'lib-js', 'lib-ts'], builtinTools: [], getTemplateName, mapESLintTemplate, diff --git a/packages/create-rstack/template-app-js/AGENTS.md b/packages/create-rstack/template-app-js/AGENTS.md new file mode 100644 index 00000000..fb378511 --- /dev/null +++ b/packages/create-rstack/template-app-js/AGENTS.md @@ -0,0 +1,12 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run dev` - Start the development server +- `{{ packageManager }} run build` - Build the app for production +- `{{ packageManager }} run preview` - Preview the production build locally + +## Docs + +- Rsbuild: https://rsbuild.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt diff --git a/packages/create-rstack/template-app-ts/AGENTS.md b/packages/create-rstack/template-app-ts/AGENTS.md new file mode 100644 index 00000000..fb378511 --- /dev/null +++ b/packages/create-rstack/template-app-ts/AGENTS.md @@ -0,0 +1,12 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run dev` - Start the development server +- `{{ packageManager }} run build` - Build the app for production +- `{{ packageManager }} run preview` - Preview the production build locally + +## Docs + +- Rsbuild: https://rsbuild.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt diff --git a/packages/create-rstack/template-common/AGENTS.md b/packages/create-rstack/template-common/AGENTS.md index 6c887e17..9f8558e0 100644 --- a/packages/create-rstack/template-common/AGENTS.md +++ b/packages/create-rstack/template-common/AGENTS.md @@ -1,15 +1,7 @@ # AGENTS.md -You are an expert in JavaScript, Rstack, and web application development. You write maintainable, performant, and accessible code. - ## Commands -- `{{ packageManager }} run dev` - Start the development server -- `{{ packageManager }} run build` - Build the app for production -- `{{ packageManager }} run preview` - Preview the production build locally - ## Docs - Rstack: https://rstack.rs/llms.txt -- Rsbuild: https://rsbuild.rs/llms.txt -- Rspack: https://rspack.rs/llms.txt diff --git a/packages/create-rstack/template-lib-js/AGENTS.md b/packages/create-rstack/template-lib-js/AGENTS.md new file mode 100644 index 00000000..234cc720 --- /dev/null +++ b/packages/create-rstack/template-lib-js/AGENTS.md @@ -0,0 +1,14 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run build` - Build the library for production +- `{{ packageManager }} run dev` - Rebuild the library when source files change +- `{{ packageManager }} run test` - Run tests +- `{{ packageManager }} run test:watch` - Run tests in watch mode + +## Docs + +- Rslib: https://rslib.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt +- Rstest: https://rstest.rs/llms.txt diff --git a/packages/create-rstack/template-lib-js/README.md b/packages/create-rstack/template-lib-js/README.md new file mode 100644 index 00000000..ab4b6927 --- /dev/null +++ b/packages/create-rstack/template-lib-js/README.md @@ -0,0 +1,40 @@ +# Rstack library + +## Setup + +Install the dependencies: + +```bash +{{ packageManager }} install +``` + +## Get started + +Build the library: + +```bash +{{ packageManager }} run build +``` + +Build the library in watch mode: + +```bash +{{ packageManager }} run dev +``` + +Run tests: + +```bash +{{ packageManager }} run test +``` + +Run tests in watch mode: + +```bash +{{ packageManager }} run test:watch +``` + +## Learn more + +- [Rstack documentation](https://rstack.rs) +- [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-js/package.json b/packages/create-rstack/template-lib-js/package.json new file mode 100644 index 00000000..a1008819 --- /dev/null +++ b/packages/create-rstack/template-lib-js/package.json @@ -0,0 +1,30 @@ +{ + "name": "rstack-lib-js", + "version": "0.0.0", + "sideEffects": false, + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "rs lib", + "dev": "rs lib --watch", + "test": "rs test", + "test:watch": "rs test --watch" + }, + "devDependencies": { + "rstack": "^0.3.5" + }, + "engines": { + "node": ">=22.12.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/create-rstack/template-lib-js/rstack.config.js b/packages/create-rstack/template-lib-js/rstack.config.js new file mode 100644 index 00000000..437a6bd3 --- /dev/null +++ b/packages/create-rstack/template-lib-js/rstack.config.js @@ -0,0 +1,7 @@ +// @ts-check +// Rstack configuration guide: https://rstack.rs/config +import { define } from 'rstack'; + +define.lib({ + syntax: ['node 22'], +}); diff --git a/packages/create-rstack/template-lib-js/src/index.js b/packages/create-rstack/template-lib-js/src/index.js new file mode 100644 index 00000000..f8beddf5 --- /dev/null +++ b/packages/create-rstack/template-lib-js/src/index.js @@ -0,0 +1 @@ +export const squared = (n) => n * n; diff --git a/packages/create-rstack/template-lib-js/tests/index.test.js b/packages/create-rstack/template-lib-js/tests/index.test.js new file mode 100644 index 00000000..912be5bc --- /dev/null +++ b/packages/create-rstack/template-lib-js/tests/index.test.js @@ -0,0 +1,7 @@ +import { expect, test } from 'rstack/test'; +import { squared } from '../src/index.js'; + +test('squared', () => { + expect(squared(2)).toBe(4); + expect(squared(12)).toBe(144); +}); diff --git a/packages/create-rstack/template-lib-ts/AGENTS.md b/packages/create-rstack/template-lib-ts/AGENTS.md new file mode 100644 index 00000000..234cc720 --- /dev/null +++ b/packages/create-rstack/template-lib-ts/AGENTS.md @@ -0,0 +1,14 @@ +# AGENTS.md + +## Commands + +- `{{ packageManager }} run build` - Build the library for production +- `{{ packageManager }} run dev` - Rebuild the library when source files change +- `{{ packageManager }} run test` - Run tests +- `{{ packageManager }} run test:watch` - Run tests in watch mode + +## Docs + +- Rslib: https://rslib.rs/llms.txt +- Rspack: https://rspack.rs/llms.txt +- Rstest: https://rstest.rs/llms.txt diff --git a/packages/create-rstack/template-lib-ts/README.md b/packages/create-rstack/template-lib-ts/README.md new file mode 100644 index 00000000..ab4b6927 --- /dev/null +++ b/packages/create-rstack/template-lib-ts/README.md @@ -0,0 +1,40 @@ +# Rstack library + +## Setup + +Install the dependencies: + +```bash +{{ packageManager }} install +``` + +## Get started + +Build the library: + +```bash +{{ packageManager }} run build +``` + +Build the library in watch mode: + +```bash +{{ packageManager }} run dev +``` + +Run tests: + +```bash +{{ packageManager }} run test +``` + +Run tests in watch mode: + +```bash +{{ packageManager }} run test:watch +``` + +## Learn more + +- [Rstack documentation](https://rstack.rs) +- [Rslib documentation](https://rslib.rs) diff --git a/packages/create-rstack/template-lib-ts/package.json b/packages/create-rstack/template-lib-ts/package.json new file mode 100644 index 00000000..7e2c33ee --- /dev/null +++ b/packages/create-rstack/template-lib-ts/package.json @@ -0,0 +1,34 @@ +{ + "name": "rstack-lib-ts", + "version": "0.0.0", + "sideEffects": false, + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "types": "./dist/index.d.ts", + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "rs lib", + "dev": "rs lib --watch", + "test": "rs test", + "test:watch": "rs test --watch" + }, + "devDependencies": { + "@types/node": "^24.13.3", + "rstack": "^0.3.5", + "typescript": "^7.0.2" + }, + "engines": { + "node": ">=22.12.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/create-rstack/template-lib-ts/rstack.config.ts b/packages/create-rstack/template-lib-ts/rstack.config.ts new file mode 100644 index 00000000..2cab1285 --- /dev/null +++ b/packages/create-rstack/template-lib-ts/rstack.config.ts @@ -0,0 +1,7 @@ +// Rstack configuration guide: https://rstack.rs/config +import { define } from 'rstack'; + +define.lib({ + syntax: ['node 22'], + dts: true, +}); diff --git a/packages/create-rstack/template-lib-ts/src/index.ts b/packages/create-rstack/template-lib-ts/src/index.ts new file mode 100644 index 00000000..fdf0e116 --- /dev/null +++ b/packages/create-rstack/template-lib-ts/src/index.ts @@ -0,0 +1 @@ +export const squared = (n: number): number => n * n; diff --git a/packages/create-rstack/template-lib-ts/tests/index.test.ts b/packages/create-rstack/template-lib-ts/tests/index.test.ts new file mode 100644 index 00000000..e7790bba --- /dev/null +++ b/packages/create-rstack/template-lib-ts/tests/index.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from 'rstack/test'; +import { squared } from '../src/index'; + +test('squared', () => { + expect(squared(2)).toBe(4); + expect(squared(12)).toBe(144); +}); diff --git a/packages/create-rstack/template-lib-ts/tsconfig.json b/packages/create-rstack/template-lib-ts/tsconfig.json new file mode 100644 index 00000000..b21bfaf4 --- /dev/null +++ b/packages/create-rstack/template-lib-ts/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ES2022"], + "target": "ES2022", + "noEmit": true, + "skipLibCheck": true, + "types": ["rstack/types", "node"], + "useDefineForClassFields": true, + + /* modules */ + "moduleDetection": "force", + "moduleResolution": "bundler", + "verbatimModuleSyntax": true, + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + + /* type checking */ + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "include": ["src"] +} diff --git a/packages/create-rstack/tests/create.test.ts b/packages/create-rstack/tests/create.test.ts index ad12c492..0d19f3d2 100644 --- a/packages/create-rstack/tests/create.test.ts +++ b/packages/create-rstack/tests/create.test.ts @@ -74,3 +74,32 @@ test.each([ await expect(access(tsconfigPath)).rejects.toThrow(); } }); + +test.each([ + { template: 'lib-js', extension: 'js', hasTypeScript: false }, + { template: 'lib-ts', extension: 'ts', hasTypeScript: true }, +])('creates the $template template', async ({ template, extension, hasTypeScript }) => { + const projectDirectory = await createProject(template); + const packageJson = JSON.parse( + await readFile(path.join(projectDirectory, 'package.json'), 'utf8'), + ); + + expect(packageJson.name).toBe('my-app'); + + await expect( + access(path.join(projectDirectory, `rstack.config.${extension}`)), + ).resolves.toBeUndefined(); + await expect( + access(path.join(projectDirectory, `src/index.${extension}`)), + ).resolves.toBeUndefined(); + await expect( + access(path.join(projectDirectory, `tests/index.test.${extension}`)), + ).resolves.toBeUndefined(); + + const tsconfigPath = path.join(projectDirectory, 'tsconfig.json'); + if (hasTypeScript) { + await expect(access(tsconfigPath)).resolves.toBeUndefined(); + } else { + await expect(access(tsconfigPath)).rejects.toThrow(); + } +});