create-soda 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-soda",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Create a Soda project: bun create soda my-app",
5
5
  "keywords": [
6
6
  "soda",
@@ -25,13 +25,15 @@
25
25
  },
26
26
  "files": [
27
27
  "dist",
28
- "template",
29
- "core-version.json"
28
+ "templates"
30
29
  ],
31
30
  "engines": {
32
31
  "node": ">=20"
33
32
  },
34
33
  "scripts": {
35
- "build": "rm -rf dist && tsc -p tsconfig.build.json && bun scripts/write-core-version.ts"
34
+ "build": "rm -rf dist && bun build src/index.ts --target node --outfile dist/index.js"
35
+ },
36
+ "devDependencies": {
37
+ "@clack/prompts": "^1.9.0"
36
38
  }
37
39
  }
@@ -0,0 +1,14 @@
1
+ # Soda app
2
+
3
+ Created with `create-soda`. Requires [Bun](https://bun.sh).
4
+
5
+ ```bash
6
+ bun install
7
+ bun dev # bun --hot: reloads on change
8
+ bun test
9
+ bun typecheck
10
+ ```
11
+
12
+ - `src/main.ts`: creates the application and starts listening.
13
+ - `src/app.module.ts`: the root module.
14
+ - `src/app.controller.ts`, `src/app.service.ts`: `GET /` answers `Hello Soda!`.
@@ -0,0 +1,11 @@
1
+ node_modules
2
+ dist
3
+ *.tgz
4
+ coverage
5
+
6
+ .env
7
+ .env.local
8
+ .env.*.local
9
+
10
+ .DS_Store
11
+ .idea
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "soda-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "bun --hot src/main.ts",
8
+ "start": "bun src/main.ts",
9
+ "test": "bun test",
10
+ "typecheck": "bun check"
11
+ },
12
+ "dependencies": {
13
+ "@getsoda/core": "workspace"
14
+ },
15
+ "devDependencies": {
16
+ "@types/bun": "latest",
17
+ "typescript": "^7.0.2"
18
+ }
19
+ }
@@ -0,0 +1,12 @@
1
+ import { Controller, Get, inject } from '@getsoda/core'
2
+ import { AppService } from './app.service.ts'
3
+
4
+ @Controller()
5
+ export class AppController {
6
+ readonly #app = inject(AppService)
7
+
8
+ @Get()
9
+ getHello(): string {
10
+ return this.#app.getHello()
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ import { Module } from '@getsoda/core'
2
+ import { AppController } from './app.controller.ts'
3
+ import { AppService } from './app.service.ts'
4
+
5
+ @Module({ providers: [AppService], controllers: [AppController] })
6
+ export class AppModule {}
@@ -0,0 +1,5 @@
1
+ export class AppService {
2
+ getHello(): string {
3
+ return 'Hello Soda!'
4
+ }
5
+ }
@@ -0,0 +1,15 @@
1
+ import { afterAll, expect, test } from 'bun:test'
2
+ import { createApp } from '@getsoda/core'
3
+ import { AppModule } from './app.module.ts'
4
+
5
+ const app = await createApp(AppModule, { logger: false })
6
+ const server = await app.listen(0)
7
+
8
+ afterAll(() => app.close())
9
+
10
+ test('GET / says hello', async () => {
11
+ const response = await fetch(server.url)
12
+
13
+ expect(response.status).toBe(200)
14
+ expect(await response.text()).toBe('Hello Soda!')
15
+ })
@@ -0,0 +1,7 @@
1
+ import { createApp } from '@getsoda/core'
2
+ import { AppModule } from './app.module.ts'
3
+
4
+ const app = await createApp(AppModule)
5
+
6
+ app.enableShutdownSignals()
7
+ await app.listen(Number(process.env.PORT ?? 3000))
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["ESNext"],
4
+ "target": "ESNext",
5
+ "module": "Preserve",
6
+ "moduleDetection": "force",
7
+ "moduleResolution": "bundler",
8
+ "allowImportingTsExtensions": true,
9
+ "verbatimModuleSyntax": true,
10
+ "noEmit": true,
11
+ "types": ["bun"],
12
+
13
+ "strict": true,
14
+ "skipLibCheck": true,
15
+ "noFallthroughCasesInSwitch": true,
16
+ "noUncheckedIndexedAccess": true,
17
+ "noImplicitOverride": true
18
+ }
19
+ }
package/core-version.json DELETED
@@ -1 +0,0 @@
1
- {"version":"0.1.1"}
package/dist/project.js DELETED
@@ -1,68 +0,0 @@
1
- /**
2
- * @module
3
- * Creating a project from the template: names, target directory, files.
4
- *
5
- * Rules from `create-vite`: the target directory is cleaned of characters
6
- * file systems refuse, a directory holding only `.git` counts as empty, the
7
- * package name is made valid for npm, and `.gitignore` is stored as
8
- * `_gitignore` because npm drops `.gitignore` files from published packages.
9
- */
10
- import { existsSync } from 'node:fs';
11
- import { cp, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
12
- import { basename, join, resolve } from 'node:path';
13
- /** Template files renamed when copied. */
14
- const RENAMED = { _gitignore: '.gitignore' };
15
- /** `' my-app/ '` → `'my-app'`. */
16
- export const formatTargetDir = (dir) => dir
17
- .trim()
18
- .replace(/[<>:"\\|?*]/g, '')
19
- .replace(/\/+$/, '');
20
- export const isValidPackageName = (name) => /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(name);
21
- /** `'My App'` → `'my-app'`. */
22
- export const toValidPackageName = (name) => name
23
- .trim()
24
- .toLowerCase()
25
- .replace(/\s+/g, '-')
26
- .replace(/^[._]/, '')
27
- .replace(/[^a-z\d\-~]+/g, '-');
28
- /** `true` for a missing directory, an empty one, or one holding only `.git`. */
29
- export const isEmptyDir = async (dir) => {
30
- if (!existsSync(dir)) {
31
- return true;
32
- }
33
- const entries = await readdir(dir);
34
- return entries.length === 0 || (entries.length === 1 && entries[0] === '.git');
35
- };
36
- /** Removes everything in `dir` but `.git`. */
37
- export const emptyDir = async (dir) => {
38
- for (const entry of await readdir(dir)) {
39
- if (entry !== '.git') {
40
- await rm(join(dir, entry), { recursive: true, force: true });
41
- }
42
- }
43
- };
44
- /**
45
- * Copies the template into `dir`, renames `_gitignore`, sets the package name and the core version.
46
- */
47
- export const createProject = async (options) => {
48
- const root = resolve(options.dir);
49
- await cp(options.template, root, { recursive: true });
50
- for (const [from, to] of Object.entries(RENAMED)) {
51
- if (existsSync(join(root, from))) {
52
- await rename(join(root, from), join(root, to));
53
- }
54
- }
55
- const manifestPath = join(root, 'package.json');
56
- const manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
57
- manifest.name = options.name ?? toValidPackageName(basename(root));
58
- manifest.dependencies['@getsoda/core'] = options.coreVersion;
59
- await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
60
- };
61
- /**
62
- * Package manager the command was run with, from `npm_config_user_agent`
63
- * (`bun/1.4.3 npm/? node/v24…` → `bun`). Defaults to `bun`.
64
- */
65
- export const detectPackageManager = (userAgent) => {
66
- const name = userAgent?.split(' ')[0]?.split('/')[0];
67
- return name === undefined || name === '' ? 'bun' : name;
68
- };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes