@temir.ra/create-ts-lib 0.1.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 +5 -0
- package/LICENSE +21 -0
- package/README.md +358 -0
- package/buildinfo.txt +1 -0
- package/dist/cli.bundle.js +4 -0
- package/dist/cli.bundle.js.map +11 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +27 -0
- package/dist/urls.d.ts +5 -0
- package/dist/urls.d.ts.map +1 -0
- package/dist/urls.js +4 -0
- package/package.json +45 -0
- package/template/AGENTS.md +1 -0
- package/template/CHANGELOG.md +5 -0
- package/template/CLAUDE.md +132 -0
- package/template/README.md +81 -0
- package/template/gitignore +4 -0
- package/template/package.json +48 -0
- package/template/scripts/build-lib-bundle.ts +156 -0
- package/template/scripts/buildinfo.ts +21 -0
- package/template/scripts/cdn-rewrite-map.json +1 -0
- package/template/src/dev.ts +15 -0
- package/template/src/index.ts +0 -0
- package/template/src/urls.ts +3 -0
- package/template/tests/buildinfo.test.ts +28 -0
- package/template/tsconfig.build.json +19 -0
- package/template/tsconfig.json +37 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Temir Ra
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
A template for TypeScript libraries distributed via npm-compatible registries. Provides TypeScript configuration, build tooling for ESM and bundled outputs, and build metadata generation.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Quick Start](#quick-start)
|
|
8
|
+
2. [Documentation](#documentation)
|
|
9
|
+
1. [`tsconfig.json` and `tsconfig.build.json`](#tsconfigjson-and-tsconfigbuildjson)
|
|
10
|
+
2. [`package.json`](#packagejson)
|
|
11
|
+
3. [Script `scripts/buildinfo.ts`](#script-scriptsbuildinfots)
|
|
12
|
+
4. [Script `scripts/build-lib-bundle.ts`](#script-scriptsbuild-lib-bundlets)
|
|
13
|
+
5. [CDN Map `scripts/cdn-rewrite-map.json`](#cdn-map-scriptscdn-rewrite-mapjson)
|
|
14
|
+
6. [`src/urls.ts`](#srcurlsts)
|
|
15
|
+
7. [`src/dev.ts`](#srcdevts)
|
|
16
|
+
8. [`CLAUDE.md` / `AGENTS.md`](#claudemd--agentsmd)
|
|
17
|
+
3. [DevOps](#devops)
|
|
18
|
+
1. [Build](#build)
|
|
19
|
+
2. [Change Management](#change-management)
|
|
20
|
+
3. [Publish](#publish)
|
|
21
|
+
1. [npmjs.org](#npmjsorg)
|
|
22
|
+
2. [Custom registry](#custom-registry)
|
|
23
|
+
|
|
24
|
+
# Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# placeholder:
|
|
28
|
+
# <PACKAGE: <PACKAGE>
|
|
29
|
+
|
|
30
|
+
bun create --no-install --no-git "@temir.ra/ts-lib" <PACKAGE>
|
|
31
|
+
cd <PACKAGE>
|
|
32
|
+
bun install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
# Documentation
|
|
36
|
+
|
|
37
|
+
## `tsconfig.json` and `tsconfig.build.json`
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
|
|
42
|
+
"compilerOptions": {
|
|
43
|
+
|
|
44
|
+
// ECMAScript version of emitted output
|
|
45
|
+
"target": "ES2022",
|
|
46
|
+
|
|
47
|
+
// output module format; ESNext passes ES module syntax through unchanged
|
|
48
|
+
"module": "ESNext",
|
|
49
|
+
|
|
50
|
+
// type definitions for built-in APIs
|
|
51
|
+
"lib": [
|
|
52
|
+
"ES2022", // standard JavaScript runtime APIs
|
|
53
|
+
"DOM" // browser globals for bundled output
|
|
54
|
+
],
|
|
55
|
+
|
|
56
|
+
// module resolution strategy; bundler mode allows omitting file extensions in imports
|
|
57
|
+
// tsconfig.build.json overrides this to nodenext for strict ESM compliance
|
|
58
|
+
"moduleResolution": "bundler",
|
|
59
|
+
|
|
60
|
+
// enables all strict type-checking options
|
|
61
|
+
"strict": true,
|
|
62
|
+
|
|
63
|
+
// enforces import type for type-only imports; emitted module syntax matches source exactly
|
|
64
|
+
"verbatimModuleSyntax": true,
|
|
65
|
+
|
|
66
|
+
// array indexing and index signature access returns T | undefined instead of T
|
|
67
|
+
"noUncheckedIndexedAccess": true,
|
|
68
|
+
|
|
69
|
+
// distinguishes absent optional properties from those explicitly set to undefined
|
|
70
|
+
"exactOptionalPropertyTypes": true,
|
|
71
|
+
|
|
72
|
+
// requires explicit override keyword when overriding base class methods
|
|
73
|
+
"noImplicitOverride": true,
|
|
74
|
+
|
|
75
|
+
// requires explicit types on all exported declarations; enables parallel .d.ts generation by external tools
|
|
76
|
+
"isolatedDeclarations": true,
|
|
77
|
+
|
|
78
|
+
// allows default imports from CommonJS modules
|
|
79
|
+
"esModuleInterop": true,
|
|
80
|
+
|
|
81
|
+
// enables project references and incremental builds via *.tsbuildinfo
|
|
82
|
+
"composite": true,
|
|
83
|
+
|
|
84
|
+
// do not type-check `.d.ts` files in `node_modules/`
|
|
85
|
+
"skipLibCheck": true,
|
|
86
|
+
|
|
87
|
+
// enforce consistent casing across import statements
|
|
88
|
+
"forceConsistentCasingInFileNames": true,
|
|
89
|
+
|
|
90
|
+
// allows importing JSON files as typed modules
|
|
91
|
+
"resolveJsonModule": true,
|
|
92
|
+
|
|
93
|
+
// emit .d.ts declaration files
|
|
94
|
+
"declaration": true,
|
|
95
|
+
// emit .d.ts.map files mapping declarations back to source
|
|
96
|
+
"declarationMap": true,
|
|
97
|
+
|
|
98
|
+
// emit only .d.ts files, no JavaScript; overridden in tsconfig.build.json
|
|
99
|
+
"emitDeclarationOnly": true,
|
|
100
|
+
|
|
101
|
+
// output directory for emitted files
|
|
102
|
+
"outDir": "./dist",
|
|
103
|
+
|
|
104
|
+
// root directory mirrored into outDir; set to project root during development, overridden to src/ in tsconfig.build.json
|
|
105
|
+
"rootDir": ".",
|
|
106
|
+
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// includes src/, tests/, and scripts/ for type-checking and IDE support; overridden in tsconfig.build.json
|
|
110
|
+
"include": [
|
|
111
|
+
"src/**/*.ts",
|
|
112
|
+
"tests/**/*.ts",
|
|
113
|
+
"scripts/**/*.ts",
|
|
114
|
+
"scripts/**/*.json"
|
|
115
|
+
],
|
|
116
|
+
"exclude": [
|
|
117
|
+
"node_modules",
|
|
118
|
+
"dist"
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`tsconfig.json` is the development configuration. `tsconfig.build.json` extends it, narrowing scope to `src/` and enabling JavaScript output for distribution.
|
|
125
|
+
|
|
126
|
+
`declarationMap: true` enables go-to-definition for npm/bun consumers. For this to work, the original `.ts` source files must be accessible to the consumer. Consider adding `src/` to the `files` field in `package.json`.
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
|
|
131
|
+
"extends": "./tsconfig.json",
|
|
132
|
+
|
|
133
|
+
"compilerOptions": {
|
|
134
|
+
|
|
135
|
+
// narrows root to src/ for distribution output
|
|
136
|
+
"rootDir": "./src",
|
|
137
|
+
|
|
138
|
+
// nodenext enforces strict ESM compliance; imports must use explicit .js file extensions
|
|
139
|
+
"module": "nodenext",
|
|
140
|
+
"moduleResolution": "nodenext",
|
|
141
|
+
|
|
142
|
+
// emit both JavaScript files and declaration files for distribution
|
|
143
|
+
"emitDeclarationOnly": false,
|
|
144
|
+
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
"include": [
|
|
148
|
+
"src/**/*.ts"
|
|
149
|
+
],
|
|
150
|
+
"exclude": [
|
|
151
|
+
"src/dev.ts",
|
|
152
|
+
"node_modules",
|
|
153
|
+
"dist",
|
|
154
|
+
"tests",
|
|
155
|
+
"scripts"
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## `package.json`
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"name": "",
|
|
166
|
+
"version": "0.0.0",
|
|
167
|
+
|
|
168
|
+
"description": "",
|
|
169
|
+
"author": "",
|
|
170
|
+
"license": "",
|
|
171
|
+
|
|
172
|
+
"keywords": ["typescript"],
|
|
173
|
+
|
|
174
|
+
"repository": {
|
|
175
|
+
"type": "git",
|
|
176
|
+
"url": ""
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// treats all .js files as ES modules; use .cjs extension for CommonJS files
|
|
180
|
+
"type": "module",
|
|
181
|
+
|
|
182
|
+
// no module has side effects; enables full tree-shaking by bundlers
|
|
183
|
+
// set to an array of file paths if some modules do have side effects, e.g. ["./src/polyfill.ts"]
|
|
184
|
+
"sideEffects": false,
|
|
185
|
+
|
|
186
|
+
// package entry points by consumer type
|
|
187
|
+
// "entrypoint" — custom condition; used by the bundle script to locate the source entry point
|
|
188
|
+
// "types" — TypeScript consumers; resolves to the declaration files; must precede "import" so TypeScript matches it before the JS condition
|
|
189
|
+
// "browser" — browser bundler consumers; resolves to the bundled output
|
|
190
|
+
// "import" — ESM consumers; resolves to the compiled module output
|
|
191
|
+
"exports": {
|
|
192
|
+
".": {
|
|
193
|
+
"entrypoint": "./src/index.ts",
|
|
194
|
+
"types": "./dist/index.d.ts",
|
|
195
|
+
"browser": "./dist/index.bundle.js",
|
|
196
|
+
"import": "./dist/index.js"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// package-internal import alias resolved natively by Node.js and Bun at runtime; key must start with #
|
|
201
|
+
// for use in dev.ts, tests/, and scripts/ only — NOT in library source files compiled by tsconfig.build.json
|
|
202
|
+
// the .js extension is required in import statements (nodenext compliance);
|
|
203
|
+
// the runtime maps it to the actual .ts source file via this field
|
|
204
|
+
"imports": {
|
|
205
|
+
"#src/*.js": "./src/*.ts"
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// CLI entry point; omit if the package is not a CLI tool
|
|
209
|
+
"bin": "./dist/cli.bundle.js",
|
|
210
|
+
|
|
211
|
+
// files to include in the published package
|
|
212
|
+
"files": [
|
|
213
|
+
"dist",
|
|
214
|
+
"CHANGELOG.md",
|
|
215
|
+
"buildinfo.txt"
|
|
216
|
+
],
|
|
217
|
+
|
|
218
|
+
"scripts": {
|
|
219
|
+
|
|
220
|
+
"clean:dist": "rm -rf dist/",
|
|
221
|
+
"clean:tsbuildinfo": "rm -f tsconfig.build.tsbuildinfo",
|
|
222
|
+
"clean": "bun run clean:dist && bun run clean:tsbuildinfo",
|
|
223
|
+
|
|
224
|
+
// lifecycle hook; runs automatically before "build"; generates buildinfo.txt
|
|
225
|
+
"prebuild": "bun run scripts/buildinfo.ts",
|
|
226
|
+
|
|
227
|
+
"tests": "bun test",
|
|
228
|
+
|
|
229
|
+
"build": "bun run build:lib && bun run build:lib-bundle",
|
|
230
|
+
|
|
231
|
+
"build:lib": "tsc --project tsconfig.build.json",
|
|
232
|
+
// bundles the library into ESM and IIFE formats for distribution
|
|
233
|
+
"build:lib-bundle": "bun run scripts/build-lib-bundle.ts",
|
|
234
|
+
|
|
235
|
+
"build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external",
|
|
236
|
+
|
|
237
|
+
"typecheck": "tsc --noEmit",
|
|
238
|
+
|
|
239
|
+
// runs src/dev.ts in watch mode
|
|
240
|
+
"dev": "bun run --watch src/dev.ts"
|
|
241
|
+
|
|
242
|
+
},
|
|
243
|
+
"devDependencies": {
|
|
244
|
+
"@types/bun": "latest",
|
|
245
|
+
"typescript": "^5.9.3"
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Script `scripts/buildinfo.ts`
|
|
251
|
+
|
|
252
|
+
Generates `buildinfo.txt` containing the version from `package.json` and the git commit hash (if available). Included in the published package for build traceability.
|
|
253
|
+
|
|
254
|
+
## Script `scripts/build-lib-bundle.ts`
|
|
255
|
+
|
|
256
|
+
Bundles the library to ESM and IIFE formats. Entry points are resolved from the `entrypoint` condition in the `exports` field of `package.json`. Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
|
|
257
|
+
|
|
258
|
+
## CDN Map `scripts/cdn-rewrite-map.json`
|
|
259
|
+
|
|
260
|
+
Maps import specifiers to CDN URLs. During bundling, matching specifiers in source files are rewritten to their CDN equivalents. `<VERSION>` in a URL is replaced with the version of the matching package from `package.json`.
|
|
261
|
+
|
|
262
|
+
```json
|
|
263
|
+
{
|
|
264
|
+
"import-specifier": "https://cdn.jsdelivr.net/npm/package-name@<VERSION>/dist/index.bundle.js"
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## `"bin"` field in `package.json`
|
|
269
|
+
|
|
270
|
+
For CLI packages, add the following to `package.json`:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"exports": ...,
|
|
275
|
+
"bin": "./dist/cli.bundle.js",
|
|
276
|
+
"files": ...,
|
|
277
|
+
"scripts": {
|
|
278
|
+
...,
|
|
279
|
+
"build": "... && bun run build:cli-bundle",
|
|
280
|
+
...,
|
|
281
|
+
"build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external",
|
|
282
|
+
...,
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## `src/urls.ts`
|
|
288
|
+
|
|
289
|
+
Resolves `CHANGELOG.md` and `buildinfo.txt` relative to `dist/` at runtime using `import.meta.url`. Provides stable references to published package assets regardless of install location.
|
|
290
|
+
|
|
291
|
+
## `src/dev.ts`
|
|
292
|
+
|
|
293
|
+
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.
|
|
294
|
+
|
|
295
|
+
## `CLAUDE.md` / `AGENTS.md`
|
|
296
|
+
|
|
297
|
+
AI assistant context files. Provide project layout, commands, and architecture notes. `AGENTS.md` references `CLAUDE.md`. The template ships two pairs:
|
|
298
|
+
|
|
299
|
+
- Root pair — describes the template package itself (scaffolding tool, CLI, how `template/` maps to generated projects)
|
|
300
|
+
- `template/` pair — describes the generated library project; update to reflect the specific library being developed
|
|
301
|
+
|
|
302
|
+
# DevOps
|
|
303
|
+
|
|
304
|
+
## Build
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# remove dist/ and tsconfig.build.tsbuildinfo
|
|
308
|
+
bun run clean
|
|
309
|
+
|
|
310
|
+
# remove dist/ only
|
|
311
|
+
bun run clean:dist
|
|
312
|
+
|
|
313
|
+
# remove tsconfig.build.tsbuildinfo only
|
|
314
|
+
bun run clean:tsbuildinfo
|
|
315
|
+
|
|
316
|
+
# compile + bundle
|
|
317
|
+
bun run build
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Change Management
|
|
321
|
+
|
|
322
|
+
1. Create a new branch for the change.
|
|
323
|
+
2. Make the changes and commit.
|
|
324
|
+
3. Bump the version in [`package.json`](package.json).
|
|
325
|
+
4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
|
|
326
|
+
5. Run `bun run build`.
|
|
327
|
+
6. Pull request the branch and publish.
|
|
328
|
+
|
|
329
|
+
## Publish
|
|
330
|
+
|
|
331
|
+
### `npmjs.org`
|
|
332
|
+
|
|
333
|
+
⚠️ Authenticate first: run `npm login` or configure `~/.npmrc` or `bunfig.toml` with an auth token.
|
|
334
|
+
|
|
335
|
+
```powershell
|
|
336
|
+
bun publish --registry https://registry.npmjs.org/ --access public
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Custom registry
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# placeholder:
|
|
343
|
+
# <SCOPE_WITHOUT_AT: <SCOPE_WITHOUT_AT>
|
|
344
|
+
# <REGISTRY_URL: <REGISTRY_URL>
|
|
345
|
+
# <BUN_PUBLISH_AUTH_TOKEN: <BUN_PUBLISH_AUTH_TOKEN>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`bunfig.toml`:
|
|
349
|
+
|
|
350
|
+
```toml
|
|
351
|
+
[install.scopes]
|
|
352
|
+
<SCOPE_WITHOUT_AT> = { url = "<REGISTRY_URL>", token = "$BUN_PUBLISH_AUTH_TOKEN" }
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
```powershell
|
|
356
|
+
$env:BUN_PUBLISH_AUTH_TOKEN = "<BUN_PUBLISH_AUTH_TOKEN>"
|
|
357
|
+
bun publish
|
|
358
|
+
```
|
package/buildinfo.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0+d78d3df
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{cpSync as o,readFileSync as U,renameSync as f,writeFileSync as d}from"fs";import{resolve as t,basename as u}from"path";import{fileURLToPath as a}from"url";var n=new URL(".",import.meta.url),l=new URL("../CHANGELOG.md",n),p=new URL("../buildinfo.txt",n),m=new URL("../template",n);try{let r=process.argv[2];if(!r)throw Error("Destination path is required. Usage: `bun/npm create <template> <destination>`");let e=t(process.cwd(),r),i=u(e),g=t(a(m));o(g,e,{recursive:!0}),o(t(a(l)),t(e,"CHANGELOG-template.md")),o(t(a(p)),t(e,"buildinfo-template.txt"));let s=t(e,"package.json"),c=JSON.parse(U(s,"utf-8"));c.name=i,d(s,JSON.stringify(c,null,2)),f(t(e,"gitignore"),t(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${i}'.`)}catch(r){let e=r instanceof Error?r:Error(String(r));console.error("Error:",e.message),process.exit(1)}
|
|
3
|
+
|
|
4
|
+
//# debugId=683E20367A2ED95764756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["..\\src\\cli.ts", "..\\src\\urls.ts"],
|
|
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\nimport { buildinfoUrl, changelogUrl, templateUrl } from '#src/urls.js';\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 const templatePath = resolve(fileURLToPath(templateUrl));\r\n\r\n cpSync(templatePath, destinationPath, { recursive: true });\r\n cpSync(resolve(fileURLToPath(changelogUrl)), resolve(destinationPath, 'CHANGELOG-template.md'));\r\n cpSync(resolve(fileURLToPath(buildinfoUrl)), 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",
|
|
6
|
+
"export const distUrl: URL = new URL('.', import.meta.url);\r\nexport const changelogUrl: URL = new URL('../CHANGELOG.md', distUrl);\r\nexport const buildinfoUrl: URL = new URL('../buildinfo.txt', distUrl);\r\nexport const templateUrl: URL = new URL('../template', distUrl);\r\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,cAAS,aAClB,wBAAS,YCJF,IAAM,EAAe,IAAI,IAAI,IAAK,YAAY,GAAG,EAC3C,EAAoB,IAAI,IAAI,kBAAmB,CAAO,EACtD,EAAoB,IAAI,IAAI,mBAAoB,CAAO,EACvD,EAAmB,IAAI,IAAI,cAAe,CAAO,EDK9D,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,EAEtC,EAAe,EAAQ,EAAc,CAAW,CAAC,EAEvD,EAAO,EAAc,EAAiB,CAAE,UAAW,EAAK,CAAC,EACzD,EAAO,EAAQ,EAAc,CAAY,CAAC,EAAG,EAAQ,EAAiB,uBAAuB,CAAC,EAC9F,EAAO,EAAQ,EAAc,CAAY,CAAC,EAAG,EAAQ,EAAiB,wBAAwB,CAAC,EAE/F,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",
|
|
9
|
+
"debugId": "683E20367A2ED95764756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';
|
|
3
|
+
import { resolve, basename } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { buildinfoUrl, changelogUrl, templateUrl } from '#src/urls.js';
|
|
6
|
+
try {
|
|
7
|
+
const dest = process.argv[2];
|
|
8
|
+
if (!dest)
|
|
9
|
+
throw new Error('Destination path is required. Usage: `bun/npm create <template> <destination>`');
|
|
10
|
+
const destinationPath = resolve(process.cwd(), dest);
|
|
11
|
+
const packageName = basename(destinationPath);
|
|
12
|
+
const templatePath = resolve(fileURLToPath(templateUrl));
|
|
13
|
+
cpSync(templatePath, destinationPath, { recursive: true });
|
|
14
|
+
cpSync(resolve(fileURLToPath(changelogUrl)), resolve(destinationPath, 'CHANGELOG-template.md'));
|
|
15
|
+
cpSync(resolve(fileURLToPath(buildinfoUrl)), resolve(destinationPath, 'buildinfo-template.txt'));
|
|
16
|
+
const packageManifestPath = resolve(destinationPath, 'package.json');
|
|
17
|
+
const packageManifest = JSON.parse(readFileSync(packageManifestPath, 'utf-8'));
|
|
18
|
+
packageManifest.name = packageName;
|
|
19
|
+
writeFileSync(packageManifestPath, JSON.stringify(packageManifest, null, 2));
|
|
20
|
+
renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));
|
|
21
|
+
console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
25
|
+
console.error('Error:', err.message);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
package/dist/urls.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../src/urls.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,EAAE,GAAmC,CAAC;AAC1D,eAAO,MAAM,YAAY,EAAE,GAAyC,CAAC;AACrE,eAAO,MAAM,YAAY,EAAE,GAA0C,CAAC;AACtE,eAAO,MAAM,WAAW,EAAE,GAAqC,CAAC"}
|
package/dist/urls.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@temir.ra/create-ts-lib",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typescript library template",
|
|
5
|
+
"author": "temir.ra",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"typescript",
|
|
9
|
+
"template",
|
|
10
|
+
"library",
|
|
11
|
+
"bun"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://git.temirs.cloud/trs/create-ts-lib.git"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"imports": {
|
|
20
|
+
"#src/*.js": "./src/*.ts"
|
|
21
|
+
},
|
|
22
|
+
"bin": "./dist/cli.bundle.js",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"buildinfo.txt",
|
|
27
|
+
"template"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"clean:dist": "rm -rf dist/",
|
|
31
|
+
"clean:tsbuildinfo": "rm -f tsconfig.build.tsbuildinfo",
|
|
32
|
+
"clean": "bun run clean:dist && bun run clean:tsbuildinfo",
|
|
33
|
+
"prebuild": "bun run scripts/buildinfo.ts",
|
|
34
|
+
"tests": "bun test",
|
|
35
|
+
"build": "bun run build:lib && bun run build:cli-bundle",
|
|
36
|
+
"build:lib": "tsc --project tsconfig.build.json",
|
|
37
|
+
"build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"dev": "bun run --watch src/dev.ts"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/bun": "latest",
|
|
43
|
+
"typescript": "^5.9.3"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
See [CLAUDE.md](CLAUDE.md).
|
|
@@ -0,0 +1,132 @@
|
|
|
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
|
+
│ └── urls.ts # URL helpers (changelog, buildinfo)
|
|
13
|
+
├── scripts/
|
|
14
|
+
│ ├── buildinfo.ts # Writes version + git hash to buildinfo.txt
|
|
15
|
+
│ ├── build-lib-bundle.ts # Bundles the library for ESM + CDN distribution
|
|
16
|
+
│ └── cdn-rewrite-map.json # CDN import rewrite rules (empty by default)
|
|
17
|
+
├── tests/ # Unit tests (Bun test runner)
|
|
18
|
+
├── dist/ # Build output (gitignored)
|
|
19
|
+
├── buildinfo.txt # Written during build; included in published package
|
|
20
|
+
├── CHANGELOG.md # Version history
|
|
21
|
+
├── CLAUDE.md # This file — AI context for the library project
|
|
22
|
+
└── AGENTS.md # References CLAUDE.md
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun install # Install dependencies
|
|
29
|
+
bun run build # Compile + bundle the library
|
|
30
|
+
bun run tests # Run unit tests
|
|
31
|
+
bun run typecheck # Type-check without emitting
|
|
32
|
+
bun run dev # Run src/dev.ts in watch mode
|
|
33
|
+
bun run clean # Remove dist/ and tsconfig.build.tsbuildinfo
|
|
34
|
+
bun run clean:dist # Remove dist/ only
|
|
35
|
+
bun run clean:tsbuildinfo # Remove tsconfig.build.tsbuildinfo only
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Writing Code
|
|
39
|
+
|
|
40
|
+
### Where things go
|
|
41
|
+
|
|
42
|
+
| Path | Purpose |
|
|
43
|
+
|------|---------|
|
|
44
|
+
| `src/index.ts` | Public API — the only entry point consumers see; export everything public from here |
|
|
45
|
+
| `src/*.ts` | Library source modules — add new modules here, re-export from `index.ts` |
|
|
46
|
+
| `src/dev.ts` | Development scratchpad — excluded from build, never published; use for manual testing |
|
|
47
|
+
| `tests/*.test.ts` | Unit tests — Bun test runner |
|
|
48
|
+
|
|
49
|
+
### Imports within `src/`
|
|
50
|
+
|
|
51
|
+
`tsconfig.build.json` uses `moduleResolution: nodenext`, so imports between library source files must use explicit `.js` extensions:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { helper } from "./helper.js" // ✓
|
|
55
|
+
import { helper } from "./helper" // ✗ — fails under nodenext
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
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.
|
|
59
|
+
|
|
60
|
+
### Explicit return types (`isolatedDeclarations`)
|
|
61
|
+
|
|
62
|
+
All exported declarations require explicit type annotations so tsc can emit `.d.ts` files without cross-file inference:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
export function greet(name: string): string { ... } // ✓
|
|
66
|
+
export function greet(name: string) { ... } // ✗ — implicit return type
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Type-only imports (`verbatimModuleSyntax`)
|
|
70
|
+
|
|
71
|
+
Use `import type` for imports that are only used as types:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import type { Foo } from "./foo.js" // ✓ — type-only import
|
|
75
|
+
import { type Foo, bar } from "./foo.js" // ✓ — mixed
|
|
76
|
+
import { Foo } from "./foo.js" // ✗ — if Foo is only used as a type
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Tests
|
|
80
|
+
|
|
81
|
+
Tests live in `tests/` and use Bun's built-in runner:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { describe, test, expect } from "bun:test"
|
|
85
|
+
|
|
86
|
+
describe("greet", () => {
|
|
87
|
+
test("returns greeting", () => {
|
|
88
|
+
expect(greet("world")).toBe("hello, world")
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Run with `bun run tests`.
|
|
94
|
+
|
|
95
|
+
## TypeScript Configuration
|
|
96
|
+
|
|
97
|
+
Two tsconfig files serve different purposes:
|
|
98
|
+
|
|
99
|
+
| File | Purpose |
|
|
100
|
+
|------|---------|
|
|
101
|
+
| `tsconfig.json` | Development — no emit, includes `src/`, `tests/`, `scripts/` |
|
|
102
|
+
| `tsconfig.build.json` | Build — emits JS + `.d.ts`, `src/` only (excludes `dev.ts`, tests, scripts) |
|
|
103
|
+
|
|
104
|
+
`bun run build:lib` uses `tsconfig.build.json`. During development the runtime handles TypeScript directly so no compilation step is needed.
|
|
105
|
+
|
|
106
|
+
Both configs enable an extended strict type-safety profile beyond `strict`: `verbatimModuleSyntax`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, `isolatedDeclarations`.
|
|
107
|
+
|
|
108
|
+
## Build Outputs
|
|
109
|
+
|
|
110
|
+
`bun run build` runs two steps in sequence:
|
|
111
|
+
|
|
112
|
+
1. **`build:lib`** — `tsc --project tsconfig.build.json` → `dist/*.js` + `dist/*.d.ts`
|
|
113
|
+
2. **`build:lib-bundle`** — `scripts/build-lib-bundle.ts` → `dist/index.bundle.js` (ESM, minified) + `dist/index.iife.js` (IIFE, minified)
|
|
114
|
+
|
|
115
|
+
The `exports` field in `package.json` maps consumers to the right file:
|
|
116
|
+
|
|
117
|
+
| Condition | File |
|
|
118
|
+
|-----------|------|
|
|
119
|
+
| `types` | `dist/index.d.ts` |
|
|
120
|
+
| `browser` | `dist/index.bundle.js` |
|
|
121
|
+
| `import` | `dist/index.js` |
|
|
122
|
+
|
|
123
|
+
## Package Configuration
|
|
124
|
+
|
|
125
|
+
Key `package.json` fields:
|
|
126
|
+
|
|
127
|
+
- `"sideEffects": false` — enables full tree-shaking by bundlers
|
|
128
|
+
- `"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.
|
|
129
|
+
|
|
130
|
+
## Publishing
|
|
131
|
+
|
|
132
|
+
See [README.md](README.md) for registry setup and publish commands.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
*<INTRO TEXT>*
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Quick Start](#quick-start)
|
|
8
|
+
2. [Documentation](#documentation)
|
|
9
|
+
3. [DevOps](#devops)
|
|
10
|
+
1. [Change Management](#change-management)
|
|
11
|
+
2. [Publish](#publish)
|
|
12
|
+
|
|
13
|
+
# Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# remove dist/ and tsconfig.build.tsbuildinfo
|
|
17
|
+
bun run clean
|
|
18
|
+
|
|
19
|
+
# remove dist/ only
|
|
20
|
+
bun run clean:dist
|
|
21
|
+
|
|
22
|
+
# remove tsconfig.build.tsbuildinfo only
|
|
23
|
+
bun run clean:tsbuildinfo
|
|
24
|
+
|
|
25
|
+
# compile + bundle
|
|
26
|
+
bun run build
|
|
27
|
+
|
|
28
|
+
# run tests
|
|
29
|
+
bun run tests
|
|
30
|
+
|
|
31
|
+
# run src/dev.ts in watch mode
|
|
32
|
+
bun run dev
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Publish** — see [Publish](#publish).
|
|
36
|
+
|
|
37
|
+
# Documentation
|
|
38
|
+
|
|
39
|
+
*<DOCUMENTATION>*
|
|
40
|
+
|
|
41
|
+
# DevOps
|
|
42
|
+
|
|
43
|
+
## Change Management
|
|
44
|
+
|
|
45
|
+
1. Create a new branch for the change.
|
|
46
|
+
2. Make the changes and commit.
|
|
47
|
+
3. Bump the version in [`package.json`](package.json).
|
|
48
|
+
4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
|
|
49
|
+
5. Run `bun run build`.
|
|
50
|
+
6. Pull request the branch and publish.
|
|
51
|
+
|
|
52
|
+
## Publish
|
|
53
|
+
|
|
54
|
+
### `npmjs.org`
|
|
55
|
+
|
|
56
|
+
⚠️ Authenticate first: run `npm login` or configure `~/.npmrc` or `bunfig.toml` with an auth token.
|
|
57
|
+
|
|
58
|
+
```powershell
|
|
59
|
+
bun publish --registry https://registry.npmjs.org/ --access public
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Custom registry
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# placeholder:
|
|
66
|
+
# <SCOPE_WITHOUT_AT: <SCOPE_WITHOUT_AT>
|
|
67
|
+
# <REGISTRY_URL: <REGISTRY_URL>
|
|
68
|
+
# <BUN_PUBLISH_AUTH_TOKEN: <BUN_PUBLISH_AUTH_TOKEN>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`bunfig.toml`:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
[install.scopes]
|
|
75
|
+
<SCOPE_WITHOUT_AT> = { url = "<REGISTRY_URL>", token = "$BUN_PUBLISH_AUTH_TOKEN" }
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```powershell
|
|
79
|
+
$env:BUN_PUBLISH_AUTH_TOKEN = "<BUN_PUBLISH_AUTH_TOKEN>"
|
|
80
|
+
bun publish
|
|
81
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"author": "",
|
|
6
|
+
"license": "",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"typescript"
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": ""
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"entrypoint": "./src/index.ts",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"browser": "./dist/index.bundle.js",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"imports": {
|
|
25
|
+
"#src/*.js": "./src/*.ts"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"CHANGELOG.md",
|
|
30
|
+
"buildinfo.txt"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"clean:dist": "rm -rf dist/",
|
|
34
|
+
"clean:tsbuildinfo": "rm -f tsconfig.build.tsbuildinfo",
|
|
35
|
+
"clean": "bun run clean:dist && bun run clean:tsbuildinfo",
|
|
36
|
+
"prebuild": "bun run scripts/buildinfo.ts",
|
|
37
|
+
"tests": "bun test",
|
|
38
|
+
"build": "bun run build:lib && bun run build:lib-bundle",
|
|
39
|
+
"build:lib": "tsc --project tsconfig.build.json",
|
|
40
|
+
"build:lib-bundle": "bun run scripts/build-lib-bundle.ts",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"dev": "bun run --watch src/dev.ts"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/bun": "latest",
|
|
46
|
+
"typescript": "^5.9.3"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import CDN_REWRITE_MAP from './cdn-rewrite-map.json';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
interface ExportConditions {
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
import?: string;
|
|
9
|
+
types?: string;
|
|
10
|
+
browser?: string;
|
|
11
|
+
entrypoint?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface DependencyMap {
|
|
15
|
+
[packageName: string]: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PackageManifest {
|
|
19
|
+
version: string;
|
|
20
|
+
exports?: Record<string, ExportConditions>;
|
|
21
|
+
dependencies?: DependencyMap;
|
|
22
|
+
devDependencies?: DependencyMap;
|
|
23
|
+
peerDependencies?: DependencyMap;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getManifest(packageIdentifier?: string): PackageManifest {
|
|
27
|
+
|
|
28
|
+
const manifestPath = packageIdentifier
|
|
29
|
+
? join('node_modules', packageIdentifier, 'package.json')
|
|
30
|
+
: 'package.json';
|
|
31
|
+
|
|
32
|
+
let manifest: PackageManifest;
|
|
33
|
+
try {
|
|
34
|
+
manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
|
35
|
+
} catch {
|
|
36
|
+
if (packageIdentifier)
|
|
37
|
+
throw new Error("[scripts/build-lib-bundle.ts] Could not read manifest for '" + packageIdentifier + "' at '" + manifestPath + "'. Is it installed?");
|
|
38
|
+
else
|
|
39
|
+
throw new Error("[scripts/build-lib-bundle.ts] Could not read package manifest at '" + manifestPath + "'.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return manifest;
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getManifestEntrypoints(packageManifest: PackageManifest): string[] {
|
|
47
|
+
|
|
48
|
+
const exports = packageManifest.exports;
|
|
49
|
+
if (!exports) throw new Error('[scripts/build-lib-bundle.ts] No exports field found in package.json.');
|
|
50
|
+
|
|
51
|
+
const entrypoints = Object.entries(exports)
|
|
52
|
+
.map(([key, conditions]) => {
|
|
53
|
+
if (!conditions.entrypoint) throw new Error(`[scripts/build-lib-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
|
|
54
|
+
return conditions.entrypoint;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return entrypoints;
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string): string {
|
|
62
|
+
|
|
63
|
+
let version: string | undefined;
|
|
64
|
+
if (packageIdentifier) {
|
|
65
|
+
|
|
66
|
+
const dependencies = {
|
|
67
|
+
...manifest.dependencies,
|
|
68
|
+
...manifest.devDependencies,
|
|
69
|
+
...manifest.peerDependencies,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
version = dependencies[packageIdentifier];
|
|
73
|
+
if (!version) throw new Error(`[scripts/build-lib-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
if (!manifest.version) throw new Error('[scripts/build-lib-bundle.ts] Package manifest does not contain a version field.');
|
|
78
|
+
version = manifest.version;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return version;
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function resolveCdnUrl(importSpecifier: string, urlTemplate: string): string {
|
|
86
|
+
const manifest = getManifest();
|
|
87
|
+
const version = getPackageVersion(manifest, importSpecifier);
|
|
88
|
+
return urlTemplate.replace('<VERSION>', version);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const cdnRewritePlugin = {
|
|
92
|
+
name: 'cdn-rewrite',
|
|
93
|
+
setup(build: any) {
|
|
94
|
+
|
|
95
|
+
const resolved = new Map<string, string>();
|
|
96
|
+
for (const [importSpecifier, urlTemplate] of Object.entries(CDN_REWRITE_MAP) as [string, string][]) {
|
|
97
|
+
const url = resolveCdnUrl(importSpecifier, urlTemplate);
|
|
98
|
+
resolved.set(importSpecifier, url);
|
|
99
|
+
console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
build.onResolve({ filter: /.*/ }, (args: any) => {
|
|
103
|
+
const url = resolved.get(args.path);
|
|
104
|
+
if (url) return { path: url, external: true };
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
const entrypoints = getManifestEntrypoints(getManifest());
|
|
112
|
+
console.log('[scripts/build-lib-bundle.ts] Entrypoints:', entrypoints);
|
|
113
|
+
|
|
114
|
+
let buildResult;
|
|
115
|
+
|
|
116
|
+
console.log('[scripts/build-lib-bundle.ts] Starting ESM bundle build...');
|
|
117
|
+
buildResult = await Bun.build({
|
|
118
|
+
entrypoints,
|
|
119
|
+
outdir: 'dist',
|
|
120
|
+
naming: '[dir]/[name].bundle.[ext]',
|
|
121
|
+
target: 'browser',
|
|
122
|
+
format: 'esm',
|
|
123
|
+
minify: true,
|
|
124
|
+
sourcemap: 'external',
|
|
125
|
+
plugins: [cdnRewritePlugin],
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (!buildResult.success) {
|
|
129
|
+
console.error('[scripts/build-lib-bundle.ts] Build failed:');
|
|
130
|
+
for (const message of buildResult.logs) {
|
|
131
|
+
console.error(message);
|
|
132
|
+
}
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
console.log('[scripts/build-lib-bundle.ts] ESM bundle build completed successfully.');
|
|
136
|
+
|
|
137
|
+
console.log('[scripts/build-lib-bundle.ts] Starting IIFE bundle build...');
|
|
138
|
+
buildResult = await Bun.build({
|
|
139
|
+
entrypoints,
|
|
140
|
+
outdir: 'dist',
|
|
141
|
+
naming: '[dir]/[name].iife.[ext]',
|
|
142
|
+
target: 'browser',
|
|
143
|
+
format: 'iife',
|
|
144
|
+
minify: true,
|
|
145
|
+
sourcemap: 'external',
|
|
146
|
+
plugins: [cdnRewritePlugin],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (!buildResult.success) {
|
|
150
|
+
console.error('[scripts/build-lib-bundle.ts] Build failed:');
|
|
151
|
+
for (const message of buildResult.logs) {
|
|
152
|
+
console.error(message);
|
|
153
|
+
}
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log('[scripts/build-lib-bundle.ts] IIFE bundle build completed successfully.');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { writeFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const BUILD_INFO_FILE = 'buildinfo.txt';
|
|
6
|
+
const GIT_COMMAND = 'git rev-parse --short HEAD';
|
|
7
|
+
|
|
8
|
+
const version = process.env.npm_package_version ?? '0.0.0';
|
|
9
|
+
|
|
10
|
+
let gitHash = '';
|
|
11
|
+
try {
|
|
12
|
+
gitHash = execSync(GIT_COMMAND, { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
13
|
+
.toString()
|
|
14
|
+
.trim();
|
|
15
|
+
} catch { }
|
|
16
|
+
|
|
17
|
+
const buildinfo = gitHash ? `${version}+${gitHash}` : version;
|
|
18
|
+
|
|
19
|
+
writeFileSync(BUILD_INFO_FILE, buildinfo);
|
|
20
|
+
|
|
21
|
+
console.log(`'${BUILD_INFO_FILE}' has been updated with build info: ${buildinfo}`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { buildinfoUrl, changelogUrl, distUrl } from '#src/urls.js';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const start: number = performance.now();
|
|
6
|
+
|
|
7
|
+
console.log(`'distPath':`, fileURLToPath(distUrl));
|
|
8
|
+
console.log(`'buildinfoPath':`, fileURLToPath(buildinfoUrl));
|
|
9
|
+
console.log(`'changelogPath':`, fileURLToPath(changelogUrl));
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// dev code
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
console.log(`${(performance.now() - start).toFixed(3)}ms`);
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, it, expect } from 'bun:test';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { buildinfoUrl } from '#src/urls.js';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
describe('buildInfo', () => {
|
|
8
|
+
|
|
9
|
+
it('should follow semantic versioning format with optional commit hash', () => {
|
|
10
|
+
const buildinfoPath = fileURLToPath(buildinfoUrl);
|
|
11
|
+
const buildinfo = readFileSync(buildinfoPath, 'utf-8').trim();
|
|
12
|
+
expect(buildinfo).toMatch(/^\d+\.\d+\.\d+(\+[0-9a-f]+)?$/);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should not contain whitespace', () => {
|
|
16
|
+
const buildinfoPath = fileURLToPath(buildinfoUrl);
|
|
17
|
+
const buildinfo = readFileSync(buildinfoPath, 'utf-8').trim();
|
|
18
|
+
expect(buildinfo).not.toMatch(/\s/);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should not be empty or dash', () => {
|
|
22
|
+
const buildinfoPath = fileURLToPath(buildinfoUrl);
|
|
23
|
+
const buildinfo = readFileSync(buildinfoPath, 'utf-8').trim();
|
|
24
|
+
expect(buildinfo.length).toBeGreaterThan(0);
|
|
25
|
+
expect(buildinfo).not.toBe('-');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "./src",
|
|
5
|
+
"module": "nodenext",
|
|
6
|
+
"moduleResolution": "nodenext",
|
|
7
|
+
"emitDeclarationOnly": false,
|
|
8
|
+
},
|
|
9
|
+
"include": [
|
|
10
|
+
"src/**/*.ts"
|
|
11
|
+
],
|
|
12
|
+
"exclude": [
|
|
13
|
+
"src/dev.ts",
|
|
14
|
+
"node_modules",
|
|
15
|
+
"dist",
|
|
16
|
+
"tests",
|
|
17
|
+
"scripts"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2022",
|
|
7
|
+
"DOM"
|
|
8
|
+
],
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"verbatimModuleSyntax": true,
|
|
12
|
+
"noUncheckedIndexedAccess": true,
|
|
13
|
+
"exactOptionalPropertyTypes": true,
|
|
14
|
+
"noImplicitOverride": true,
|
|
15
|
+
"isolatedDeclarations": true,
|
|
16
|
+
"esModuleInterop": true,
|
|
17
|
+
"composite": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"declarationMap": true,
|
|
23
|
+
"emitDeclarationOnly": true,
|
|
24
|
+
"outDir": "./dist",
|
|
25
|
+
"rootDir": ".",
|
|
26
|
+
},
|
|
27
|
+
"include": [
|
|
28
|
+
"src/**/*.ts",
|
|
29
|
+
"tests/**/*.ts",
|
|
30
|
+
"scripts/**/*.ts",
|
|
31
|
+
"scripts/**/*.json"
|
|
32
|
+
],
|
|
33
|
+
"exclude": [
|
|
34
|
+
"node_modules",
|
|
35
|
+
"dist"
|
|
36
|
+
]
|
|
37
|
+
}
|