@temir.ra/create-ts-lib 0.2.7-pre.1 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # Version 0
2
2
 
3
- ## 0.2.7-pre.1
3
+ ## 0.3.0
4
+
5
+ 1. Removed AI Assistant Context files to be generated by the user with the provided prompts in the README.
6
+
7
+ ## 0.2.8 (unreleased)
8
+
9
+ 1. CLI now copies root `README.md` into the generated project as `README-template.md`.
10
+ 2. Added `README-template.md` to `template/gitignore`.
11
+ 3. Added `# AI Assistant Context` section to root `README.md` and `template/README.md` with prompts for generating AI coding assistant context files.
12
+ 4. Revised Change Management step 6 in root `README.md` and `template/README.md`.
13
+ 5. `.gitignore`'ing `bun.lock`.
14
+
15
+ ## 0.2.8-pre.2
16
+
17
+ 1. Removed `sideEffects` property from `package.json` as it is not a standard field.
18
+ 2. Added references to npmjs and typescriptlang documentation for `package.json` and `tsconfig.json` in the README.
19
+
20
+ ## 0.2.7
4
21
 
5
22
  1. Changed `filter` property in `cdnRewritePlugin` in `scripts/build-lib-bundle.ts` to take import identifiers into account that do not have file extensions.
23
+ 2. Changed `buildinfo.txt` generation in `scripts/buildinfo.ts` to read the version from `package.json` instead of relying on the `npm_package_version` environment variable. Enables correct version capture in monorepo setups.
6
24
 
7
25
  ## 0.2.6
8
26
 
package/README.md CHANGED
@@ -5,7 +5,8 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
5
5
  ## Table of Contents
6
6
 
7
7
  1. [Quick Start](#quick-start)
8
- 2. [Documentation](#documentation)
8
+ 2. [AI Assistant Context](#ai-assistant-context)
9
+ 3. [Documentation](#documentation)
9
10
  1. [`tsconfig.json` and `tsconfig.build.json`](#tsconfigjson-and-tsconfigbuildjson)
10
11
  2. [`package.json`](#packagejson)
11
12
  3. [Script `scripts/buildinfo.ts`](#script-scriptsbuildinfots)
@@ -21,8 +22,7 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
21
22
  3. [README statement for library consumers](#readme-statement-for-library-consumers)
22
23
  4. [When the library is bundled by the consumer](#when-the-library-is-bundled-by-the-consumer)
23
24
  8. [`src/dev.ts`](#srcdevts)
24
- 9. [`CLAUDE.md` / `AGENTS.md`](#claudemd--agentsmd)
25
- 3. [DevOps](#devops)
25
+ 4. [DevOps](#devops)
26
26
  1. [Change Management](#change-management)
27
27
  2. [Publish](#publish)
28
28
  1. [npmjs.org](#npmjsorg)
@@ -54,12 +54,20 @@ cd <NEW_PACKAGE>
54
54
  bun install
55
55
  ```
56
56
 
57
+ # AI Assistant Context
58
+
59
+ To generate an AI coding assistant context file for this project:
60
+
61
+ > Generate an AI coding assistant context file. Analyze the project structure and source files, using this README as the primary reference for architecture and conventions. Give particular attention to: the dual tsconfig setup and the import constraints it imposes, the `#src/*.js` alias and where it may and may not be used, the custom `entrypoint` export condition, and the asset resolution contract.
62
+
57
63
  # Documentation
58
64
 
59
65
  The following sections explain the configurations and conventions baked into the generated package. Useful when adapting the generated package to fit a specific library's needs.
60
66
 
61
67
  ## `tsconfig.json` and `tsconfig.build.json`
62
68
 
69
+ See the typescriptlang documentation on [tsconfig.json](https://www.typescriptlang.org/tsconfig) for detailed explanations of all options.
70
+
63
71
  ```json
64
72
  {
65
73
 
@@ -184,6 +192,8 @@ The following sections explain the configurations and conventions baked into the
184
192
 
185
193
  ## `package.json`
186
194
 
195
+ See npmjs documentation on [package.json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for detailed explanations of all fields.
196
+
187
197
  ```json
188
198
  {
189
199
  "name": "",
@@ -203,10 +213,6 @@ The following sections explain the configurations and conventions baked into the
203
213
  // treats all .js files as ES modules; use .cjs extension for CommonJS files
204
214
  "type": "module",
205
215
 
206
- // no module has side effects; enables full tree-shaking by bundlers
207
- // set to an array of file paths if some modules do have side effects, e.g. ["./src/polyfill.ts"]
208
- "sideEffects": false,
209
-
210
216
  // package entry points by consumer type
211
217
  // "entrypoint" - custom condition; used by the bundle script to locate the source entry point
212
218
  // "types" - TypeScript consumers; resolves to the declaration files; must precede "import" so TypeScript matches it before the JS condition
@@ -418,13 +424,6 @@ From the bundle's perspective `assets/@scope/lib-name/` is at the same directory
418
424
 
419
425
  Development scratchpad - not published, excluded from `tsconfig.build.json`. Run with `bun run dev` in watch mode. Use it to manually test and explore library code during development.
420
426
 
421
- ## `CLAUDE.md` / `AGENTS.md`
422
-
423
- AI assistant context files. Provide project layout, commands, and architecture notes. `AGENTS.md` references `CLAUDE.md`. The template ships two pairs:
424
-
425
- - Root pair - describes the template package itself (scaffolding tool, CLI, how `template/` maps to generated projects)
426
- - `template/` pair - describes the generated library project; update to reflect the specific library being developed
427
-
428
427
  # DevOps
429
428
 
430
429
  ```bash
@@ -451,7 +450,7 @@ bun run dist/cli.bundle.js -- example
451
450
  3. Bump the version in [`package.json`](package.json).
452
451
  4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
453
452
  5. Pull request the branch.
454
- 6. After merge, run `bun run build`.
453
+ 6. After merge, run `bun run build` - ensures artifacts are current before publish.
455
454
  7. Publish.
456
455
 
457
456
  ## Publish
package/buildinfo.txt CHANGED
@@ -1 +1 @@
1
- 0.2.7-pre.1+1fa806e
1
+ 0.3.0+e1e7c7f
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{cpSync as n,readFileSync as c,renameSync as p,writeFileSync as l}from"fs";import{resolve as t,basename as m}from"path";import{fileURLToPath as g}from"url";var f=new URL("../",import.meta.url),r=t(g(f)),d=t(r,"template/"),h=t(r,"CHANGELOG.md"),u=t(r,"buildinfo.txt");try{let a=process.argv[2];if(!a)throw Error("Destination path is required. Usage: `bun/npm create <template> <destination>`");let e=t(process.cwd(),a),o=m(e);n(d,e,{recursive:!0}),n(h,t(e,"CHANGELOG-template.md")),n(u,t(e,"buildinfo-template.txt"));let s=t(e,"package.json"),i=JSON.parse(c(s,"utf-8"));i.name=o,l(s,JSON.stringify(i,null,2)),p(t(e,"gitignore"),t(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${o}'.`)}catch(a){let e=a instanceof Error?a:Error(String(a));console.error("Error:",e.message),process.exit(1)}
2
+ import{cpSync as n,readFileSync as c,renameSync as m,writeFileSync as p}from"fs";import{resolve as e,basename as l}from"path";import{fileURLToPath as g}from"url";var d=new URL("../",import.meta.url),r=e(g(d)),f=e(r,"template/"),h=e(r,"CHANGELOG.md"),u=e(r,"buildinfo.txt"),E=e(r,"README.md");try{let a=process.argv[2];if(!a)throw Error("Destination path is required. Usage: `bun/npm create <template> <destination>`");let t=e(process.cwd(),a),o=l(t);n(f,t,{recursive:!0}),n(h,e(t,"CHANGELOG-template.md")),n(u,e(t,"buildinfo-template.txt")),n(E,e(t,"README-template.md"));let s=e(t,"package.json"),i=JSON.parse(c(s,"utf-8"));i.name=o,p(s,JSON.stringify(i,null,2)),m(e(t,"gitignore"),e(t,".gitignore")),console.log(`Template has been successfully instantiated at '${t}' with package name '${o}'.`)}catch(a){let t=a instanceof Error?a:Error(String(a));console.error("Error:",t.message),process.exit(1)}
3
3
 
4
- //# debugId=27529CB64FC389F464756E2164756E21
4
+ //# debugId=969CCBE42ED5C5D964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["..\\src\\cli.ts"],
4
4
  "sourcesContent": [
5
- "#!/usr/bin/env node\r\n\r\nimport { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';\r\nimport { resolve, basename } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\n\r\nconst packageUrl = new URL('../', import.meta.url);\r\nconst packagePath = resolve(fileURLToPath(packageUrl));\r\n\r\nconst templatePath = resolve(packagePath, 'template/');\r\n\r\nconst changelogPath = resolve(packagePath, 'CHANGELOG.md');\r\nconst buildinfoPath = resolve(packagePath, 'buildinfo.txt');\r\n\r\n\r\ntry {\r\n\r\n const dest = process.argv[2];\r\n if (!dest) throw new Error('Destination path is required. Usage: `bun/npm create <template> <destination>`');\r\n\r\n const destinationPath = resolve(process.cwd(), dest);\r\n const packageName = basename(destinationPath);\r\n\r\n cpSync(templatePath, destinationPath, { recursive: true });\r\n cpSync(changelogPath, resolve(destinationPath, 'CHANGELOG-template.md'));\r\n cpSync(buildinfoPath, resolve(destinationPath, 'buildinfo-template.txt'));\r\n\r\n const packageManifestPath = resolve(destinationPath, 'package.json');\r\n const packageManifest = JSON.parse(readFileSync(packageManifestPath, 'utf-8'));\r\n packageManifest.name = packageName;\r\n writeFileSync(packageManifestPath, JSON.stringify(packageManifest, null, 2));\r\n\r\n renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));\r\n\r\n console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);\r\n\r\n}\r\ncatch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n console.error('Error:', err.message);\r\n process.exit(1);\r\n}\r\n"
5
+ "#!/usr/bin/env node\r\n\r\nimport { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';\r\nimport { resolve, basename } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\n\r\nconst packageUrl = new URL('../', import.meta.url);\r\nconst packagePath = resolve(fileURLToPath(packageUrl));\r\n\r\nconst templatePath = resolve(packagePath, 'template/');\r\n\r\nconst changelogPath = resolve(packagePath, 'CHANGELOG.md');\r\nconst buildinfoPath = resolve(packagePath, 'buildinfo.txt');\r\nconst readmePath = resolve(packagePath, 'README.md');\r\n\r\n\r\ntry {\r\n\r\n const dest = process.argv[2];\r\n if (!dest) throw new Error('Destination path is required. Usage: `bun/npm create <template> <destination>`');\r\n\r\n const destinationPath = resolve(process.cwd(), dest);\r\n const packageName = basename(destinationPath);\r\n\r\n cpSync(templatePath, destinationPath, { recursive: true });\r\n cpSync(changelogPath, resolve(destinationPath, 'CHANGELOG-template.md'));\r\n cpSync(buildinfoPath, resolve(destinationPath, 'buildinfo-template.txt'));\r\n cpSync(readmePath, resolve(destinationPath, 'README-template.md'));\r\n\r\n const packageManifestPath = resolve(destinationPath, 'package.json');\r\n const packageManifest = JSON.parse(readFileSync(packageManifestPath, 'utf-8'));\r\n packageManifest.name = packageName;\r\n writeFileSync(packageManifestPath, JSON.stringify(packageManifest, null, 2));\r\n\r\n renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));\r\n\r\n console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);\r\n\r\n}\r\ncatch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n console.error('Error:', err.message);\r\n process.exit(1);\r\n}\r\n"
6
6
  ],
7
- "mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,cAAS,aAClB,wBAAS,YAGT,IAAM,EAAa,IAAI,IAAI,MAAO,YAAY,GAAG,EAC3C,EAAc,EAAQ,EAAc,CAAU,CAAC,EAE/C,EAAe,EAAQ,EAAa,WAAW,EAE/C,EAAgB,EAAQ,EAAa,cAAc,EACnD,EAAgB,EAAQ,EAAa,eAAe,EAG1D,GAAI,CAEA,IAAM,EAAO,QAAQ,KAAK,GAC1B,GAAI,CAAC,EAAM,MAAU,MAAM,gFAAgF,EAE3G,IAAM,EAAkB,EAAQ,QAAQ,IAAI,EAAG,CAAI,EAC7C,EAAc,EAAS,CAAe,EAE5C,EAAO,EAAc,EAAiB,CAAE,UAAW,EAAK,CAAC,EACzD,EAAO,EAAe,EAAQ,EAAiB,uBAAuB,CAAC,EACvE,EAAO,EAAe,EAAQ,EAAiB,wBAAwB,CAAC,EAExE,IAAM,EAAsB,EAAQ,EAAiB,cAAc,EAC7D,EAAkB,KAAK,MAAM,EAAa,EAAqB,OAAO,CAAC,EAC7E,EAAgB,KAAO,EACvB,EAAc,EAAqB,KAAK,UAAU,EAAiB,KAAM,CAAC,CAAC,EAE3E,EAAW,EAAQ,EAAiB,WAAW,EAAG,EAAQ,EAAiB,YAAY,CAAC,EAExF,QAAQ,IAAI,mDAAmD,yBAAuC,KAAe,EAGzH,MAAO,EAAO,CACV,IAAM,EAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,EACpE,QAAQ,MAAM,SAAU,EAAI,OAAO,EACnC,QAAQ,KAAK,CAAC",
8
- "debugId": "27529CB64FC389F464756E2164756E21",
7
+ "mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,cAAS,aAClB,wBAAS,YAGT,IAAM,EAAa,IAAI,IAAI,MAAO,YAAY,GAAG,EAC3C,EAAc,EAAQ,EAAc,CAAU,CAAC,EAE/C,EAAe,EAAQ,EAAa,WAAW,EAE/C,EAAgB,EAAQ,EAAa,cAAc,EACnD,EAAgB,EAAQ,EAAa,eAAe,EACpD,EAAa,EAAQ,EAAa,WAAW,EAGnD,GAAI,CAEA,IAAM,EAAO,QAAQ,KAAK,GAC1B,GAAI,CAAC,EAAM,MAAU,MAAM,gFAAgF,EAE3G,IAAM,EAAkB,EAAQ,QAAQ,IAAI,EAAG,CAAI,EAC7C,EAAc,EAAS,CAAe,EAE5C,EAAO,EAAc,EAAiB,CAAE,UAAW,EAAK,CAAC,EACzD,EAAO,EAAe,EAAQ,EAAiB,uBAAuB,CAAC,EACvE,EAAO,EAAe,EAAQ,EAAiB,wBAAwB,CAAC,EACxE,EAAO,EAAY,EAAQ,EAAiB,oBAAoB,CAAC,EAEjE,IAAM,EAAsB,EAAQ,EAAiB,cAAc,EAC7D,EAAkB,KAAK,MAAM,EAAa,EAAqB,OAAO,CAAC,EAC7E,EAAgB,KAAO,EACvB,EAAc,EAAqB,KAAK,UAAU,EAAiB,KAAM,CAAC,CAAC,EAE3E,EAAW,EAAQ,EAAiB,WAAW,EAAG,EAAQ,EAAiB,YAAY,CAAC,EAExF,QAAQ,IAAI,mDAAmD,yBAAuC,KAAe,EAGzH,MAAO,EAAO,CACV,IAAM,EAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,EACpE,QAAQ,MAAM,SAAU,EAAI,OAAO,EACnC,QAAQ,KAAK,CAAC",
8
+ "debugId": "969CCBE42ED5C5D964756E2164756E21",
9
9
  "names": []
10
10
  }
package/dist/cli.js CHANGED
@@ -7,6 +7,7 @@ const packagePath = resolve(fileURLToPath(packageUrl));
7
7
  const templatePath = resolve(packagePath, 'template/');
8
8
  const changelogPath = resolve(packagePath, 'CHANGELOG.md');
9
9
  const buildinfoPath = resolve(packagePath, 'buildinfo.txt');
10
+ const readmePath = resolve(packagePath, 'README.md');
10
11
  try {
11
12
  const dest = process.argv[2];
12
13
  if (!dest)
@@ -16,6 +17,7 @@ try {
16
17
  cpSync(templatePath, destinationPath, { recursive: true });
17
18
  cpSync(changelogPath, resolve(destinationPath, 'CHANGELOG-template.md'));
18
19
  cpSync(buildinfoPath, resolve(destinationPath, 'buildinfo-template.txt'));
20
+ cpSync(readmePath, resolve(destinationPath, 'README-template.md'));
19
21
  const packageManifestPath = resolve(destinationPath, 'package.json');
20
22
  const packageManifest = JSON.parse(readFileSync(packageManifestPath, 'utf-8'));
21
23
  packageManifest.name = packageName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temir.ra/create-ts-lib",
3
- "version": "0.2.7-pre.1",
3
+ "version": "0.3.0",
4
4
  "description": "Typescript library template",
5
5
  "author": "temir.ra",
6
6
  "license": "MIT",
@@ -15,7 +15,6 @@
15
15
  "url": "https://git.chimps.quest/trs/create-ts-lib.git"
16
16
  },
17
17
  "type": "module",
18
- "sideEffects": false,
19
18
  "imports": {
20
19
  "#src/*.js": "./src/*.ts"
21
20
  },
@@ -5,8 +5,9 @@
5
5
  ## Table of Contents
6
6
 
7
7
  1. [Quick Start](#quick-start)
8
- 2. [Documentation](#documentation)
9
- 3. [DevOps](#devops)
8
+ 2. [AI Assistant Context](#ai-assistant-context)
9
+ 3. [Documentation](#documentation)
10
+ 4. [DevOps](#devops)
10
11
  1. [Change Management](#change-management)
11
12
  2. [Publish](#publish)
12
13
  1. [npmjs.org](#npmjsorg)
@@ -36,6 +37,12 @@ bun run dev
36
37
 
37
38
  **Publish** - see [Publish](#publish).
38
39
 
40
+ # AI Assistant Context
41
+
42
+ To generate an AI coding assistant context file for this project:
43
+
44
+ > Generate an AI coding assistant context file. `README-template.md` is available now and documents the architectural conventions of this package — use it as your primary source. The generated context file must be self-contained: `README-template.md` will be deleted after context generation, so do not reference it in the output. Give particular attention to: the dual tsconfig setup and the import constraints it imposes, the `#src/*.js` alias and where it may and may not be used, the custom `entrypoint` export condition, and the asset resolution contract.
45
+
39
46
  # Documentation
40
47
 
41
48
  *&lt;DOCUMENTATION&gt;*
@@ -46,11 +53,11 @@ bun run dev
46
53
 
47
54
  Assets are placed under `assets/@scope/lib-name/` (scoped to the package name to prevent collisions). They are resolved at runtime via `import.meta.url` and loaded with `fetch()` (browser) or `readFile` (Node). `assets/` must be listed in `files` in `package.json`.
48
55
 
49
- `import.meta.url` is reliable when the library is loaded as a discrete module (from CDN or `node_modules/`). When the consumer bundles the library, they must copy the assets see below.
56
+ `import.meta.url` is reliable when the library is loaded as a discrete module (from CDN or `node_modules/`). When the consumer bundles the library, they must copy the assets - see below.
50
57
 
51
58
  ### For consumers bundling this library
52
59
 
53
- Copy `node_modules/@scope/lib-name/assets/` into your build output alongside the bundle, preserving the relative path. No code configuration is required only the file copy.
60
+ Copy `node_modules/@scope/lib-name/assets/` into your build output alongside the bundle, preserving the relative path. No code configuration is required - only the file copy.
54
61
 
55
62
  # DevOps
56
63
 
@@ -61,7 +68,7 @@ Copy `node_modules/@scope/lib-name/assets/` into your build output alongside the
61
68
  3. Bump the version in [`package.json`](package.json).
62
69
  4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
63
70
  5. Pull request the branch.
64
- 6. After merge, run `bun run build`.
71
+ 6. After merge, run `bun run build` - ensures artifacts are current before publish.
65
72
  7. Publish.
66
73
 
67
74
  ## Publish
@@ -4,3 +4,4 @@ buildinfo.txt
4
4
  *.tsbuildinfo
5
5
  buildinfo-template.txt
6
6
  CHANGELOG-template.md
7
+ README-template.md
@@ -12,7 +12,6 @@
12
12
  "url": ""
13
13
  },
14
14
  "type": "module",
15
- "sideEffects": false,
16
15
  "exports": {
17
16
  ".": {
18
17
  "entrypoint": "./src/index.ts",
@@ -1,11 +1,11 @@
1
1
  import { execSync } from 'child_process';
2
- import { writeFileSync } from 'fs';
2
+ import { readFileSync, writeFileSync } from 'fs';
3
3
 
4
4
 
5
5
  const BUILD_INFO_FILE = 'buildinfo.txt';
6
6
  const GIT_COMMAND = 'git rev-parse --short HEAD';
7
7
 
8
- const version = process.env.npm_package_version ?? '0.0.0';
8
+ const { version } = JSON.parse(readFileSync('package.json', 'utf-8'));
9
9
 
10
10
  let gitHash = '';
11
11
  try {
@@ -1 +0,0 @@
1
- See [CLAUDE.md](CLAUDE.md).
@@ -1,216 +0,0 @@
1
- # <package-name>
2
-
3
- A Bun TypeScript library.
4
-
5
- ## Project Layout
6
-
7
- ```
8
- <package-name>/
9
- ├── src/
10
- │ ├── index.ts # Library entry point (public API)
11
- │ └── dev.ts # Development scratchpad — run with `bun run dev`
12
- ├── scripts/
13
- │ ├── buildinfo.ts # Writes version + git hash to buildinfo.txt
14
- │ ├── build-lib-bundle.ts # Bundles the library for ESM + CDN distribution
15
- │ └── cdn-rewrite-map.json # CDN import rewrite rules (empty by default)
16
- ├── tests/ # Unit tests (Bun test runner)
17
- ├── dist/ # Build output (gitignored)
18
- ├── buildinfo.txt # Written during build; included in published package
19
- ├── CHANGELOG.md # Version history
20
- ├── CLAUDE.md # This file — AI context for the library project
21
- └── AGENTS.md # References CLAUDE.md
22
- ```
23
-
24
- ## Commands
25
-
26
- ```bash
27
- bun install # Install dependencies
28
- bun run build # Compile + bundle the library
29
- bun run tests # Run unit tests
30
- bun run typecheck # Type-check without emitting
31
- bun run dev # Run src/dev.ts in watch mode
32
- bun run clean # Remove dist/ and tsconfig.build.tsbuildinfo
33
- bun run clean:dist # Remove dist/ only
34
- bun run clean:tsbuildinfo # Remove tsconfig.build.tsbuildinfo only
35
- ```
36
-
37
- ## Writing Code
38
-
39
- ### Where things go
40
-
41
- | Path | Purpose |
42
- |------|---------|
43
- | `src/index.ts` | Public API — the only entry point consumers see; export everything public from here |
44
- | `src/*.ts` | Library source modules — add new modules here, re-export from `index.ts` |
45
- | `src/dev.ts` | Development scratchpad — excluded from build, never published; use for manual testing |
46
- | `tests/*.test.ts` | Unit tests — Bun test runner |
47
-
48
- ### Imports within `src/`
49
-
50
- `tsconfig.build.json` uses `moduleResolution: nodenext`, so imports between library source files must use explicit `.js` extensions:
51
-
52
- ```ts
53
- import { helper } from "./helper.js" // ✓
54
- import { helper } from "./helper" // ✗ — fails under nodenext
55
- ```
56
-
57
- The `#src/*.js` package alias is available in `dev.ts`, `tests/`, and `scripts/`, but **not** in library source files — tsc emits the specifier verbatim and it would break in published unbundled output.
58
-
59
- ### Explicit return types (`isolatedDeclarations`)
60
-
61
- All exported declarations require explicit type annotations so tsc can emit `.d.ts` files without cross-file inference:
62
-
63
- ```ts
64
- export function greet(name: string): string { ... } // ✓
65
- export function greet(name: string) { ... } // ✗ — implicit return type
66
- ```
67
-
68
- ### Type-only imports (`verbatimModuleSyntax`)
69
-
70
- Use `import type` for imports that are only used as types:
71
-
72
- ```ts
73
- import type { Foo } from "./foo.js" // ✓ — type-only import
74
- import { type Foo, bar } from "./foo.js" // ✓ — mixed
75
- import { Foo } from "./foo.js" // ✗ — if Foo is only used as a type
76
- ```
77
-
78
- ### Asset Resolution (if the library has runtime assets)
79
-
80
- The key question: **does your library retain its own URL at runtime?** Everything else follows from it.
81
-
82
- - **Externalized** (loaded from CDN or `node_modules/`): `import.meta.url` is reliable as-is — no consumer action needed.
83
- - **Bundled** (absorbed into the consumer's output): `import.meta.url` points to the consumer's bundle, not the library's file. The path relationship can be preserved by convention — if the consumer copies the library's assets into their build output at the same relative path, resolution continues to work correctly.
84
-
85
- #### Contract
86
-
87
- **The library must:**
88
- 1. Place assets in a scoped directory — `assets/@scope/lib-name/` (mirrors the package name, prevents collisions when multiple libraries share a consumer bundle).
89
- 2. Access assets via `import.meta.url` — see code below.
90
- 3. Document the bundled case in the library's README — see [README statement](#readme-statement-for-consumers) below.
91
-
92
- **The consumer must,**
93
- - **when loading the library externalized:** do nothing.
94
- - **when bundling the library:** copy `node_modules/@scope/lib-name/assets/` into their build output alongside the bundle, and ensure the assets are served.
95
-
96
- #### Scoped assets directory
97
-
98
- ```
99
- assets/
100
- └── @scope/
101
- └── lib-name/
102
- └── <ASSETS>
103
- ```
104
-
105
- Add `assets/` to `files` in `package.json` so it is included in the published package:
106
-
107
- ```json
108
- "files": ["dist", "CHANGELOG.md", "buildinfo.txt", "assets"]
109
- ```
110
-
111
- #### Accessing assets
112
-
113
- Resolve asset URLs inline from `import.meta.url` — no shared helper file:
114
-
115
- ```typescript
116
- const packageUrl = new URL('../', import.meta.url);
117
- const assetsUrl = new URL('assets/@scope/lib-name/', packageUrl);
118
-
119
- // for --target browser
120
- const data = await fetch(new URL('data.json', assetsUrl)).then(r => r.json());
121
-
122
- // for --target node
123
- import { readFile } from 'node:fs/promises';
124
- import { fileURLToPath } from 'url';
125
- const raw = await readFile(fileURLToPath(new URL('data.json', assetsUrl)), 'utf-8');
126
- ```
127
-
128
- #### When the library is bundled by the consumer
129
-
130
- The consumer must copy assets into their build output at the same relative path:
131
-
132
- ```
133
- consumer output/
134
- ├── bundle.js ← import.meta.url points here
135
- └── assets/
136
- └── @scope/
137
- └── lib-name/
138
- └── <ASSETS> ← copied; relative path preserved
139
- ```
140
-
141
- No code configuration needed — only the file copy.
142
-
143
- #### README statement for consumers
144
-
145
- Copy the following into the library's README (replace `<SCOPE>` and `<LIB_NAME>`):
146
-
147
- ```markdown
148
- ## Asset resolution
149
-
150
- This library resolves assets at runtime using `import.meta.url`. If you bundle this library into your application, copy `node_modules/<SCOPE>/<LIB_NAME>/assets/<SCOPE>/<LIB_NAME>/` into your build output directory alongside your bundle.
151
- ```
152
-
153
- ### Tests
154
-
155
- Tests live in `tests/` and use Bun's built-in runner:
156
-
157
- ```ts
158
- import { describe, test, expect } from "bun:test"
159
-
160
- describe("greet", () => {
161
- test("returns greeting", () => {
162
- expect(greet("world")).toBe("hello, world")
163
- })
164
- })
165
- ```
166
-
167
- Run with `bun run tests`.
168
-
169
- ## TypeScript Configuration
170
-
171
- Two tsconfig files serve different purposes:
172
-
173
- | File | Purpose |
174
- |------|---------|
175
- | `tsconfig.json` | Development — no emit, includes `src/`, `tests/`, `scripts/` |
176
- | `tsconfig.build.json` | Build — emits JS + `.d.ts`, `src/` only (excludes `dev.ts`, tests, scripts) |
177
-
178
- `bun run build:lib` uses `tsconfig.build.json`. During development the runtime handles TypeScript directly so no compilation step is needed.
179
-
180
- Both configs enable an extended strict type-safety profile beyond `strict`: `verbatimModuleSyntax`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, `isolatedDeclarations`.
181
-
182
- ## Build Outputs
183
-
184
- `bun run build` runs two steps in sequence:
185
-
186
- 1. **`build:lib`** — `tsc --project tsconfig.build.json` → `dist/*.js` + `dist/*.d.ts`
187
- 2. **`build:lib-bundle`** — `scripts/build-lib-bundle.ts` → `dist/index.bundle.js` (ESM, minified) + `dist/index.iife.js` (IIFE, minified)
188
-
189
- The `exports` field in `package.json` maps consumers to the right file:
190
-
191
- | Condition | File |
192
- |-----------|------|
193
- | `types` | `dist/index.d.ts` |
194
- | `browser` | `dist/index.bundle.js` |
195
- | `import` | `dist/index.js` |
196
-
197
- ## Package Configuration
198
-
199
- Key `package.json` fields:
200
-
201
- - `"sideEffects": false` — enables full tree-shaking by bundlers
202
- - `"imports": { "#src/*.js": "./src/*.ts" }` — package-internal alias for `src/`; use as `import { foo } from "#src/module.js"`. **Only for `dev.ts`, `tests/`, and `scripts/`** — not for library source files compiled by `tsconfig.build.json`, as tsc emits the specifier verbatim and it would break in published unbundled output.
203
-
204
- ## Change Management
205
-
206
- 1. Branch off main.
207
- 2. Make the changes and commit.
208
- 3. Bump the version in [`package.json`](package.json).
209
- 4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
210
- 5. Pull request the branch.
211
- 6. After merge, run `bun run build`. ← must happen after merge so `buildinfo.txt` captures the correct git hash, and before publish so the artifacts are up to date.
212
- 7. Publish.
213
-
214
- ## Publishing
215
-
216
- See [README.md](README.md) for registry setup and publish commands.