@temir.ra/create-ts-lib 0.6.1 → 0.7.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,5 +1,28 @@
1
1
  # Version 0
2
2
 
3
+ ## 0.7.0
4
+
5
+ 1. Updated `.gitignore`: added `bun.lock`, `buildinfo-template.txt`, `CHANGELOG-template.md`, `README-template.md`; replaced nested `template/.gitignore` with `template/gitignore` to prevent template files from being excluded during distribution.
6
+ 2. Removed `CLAUDE.md`, `AGENTS.md`, and `src/dev.ts` from root and template.
7
+ 3. Overhauled the generated `package.json`: added `private: false`; removed `sideEffects: false`; added build scripts to published `files`; updated `clean:tsbuildinfo` to `rm -f *.tsbuildinfo || true`; renamed `build:lib-bundle` to `build:bundle`; removed `build:lib` and `dev` scripts; added `reinstall` script; bumped typescript to `^6.0.2`.
8
+ 4. Updated the generated `tsconfig.json`: changed `target` to `ESNext`; removed `DOM` from `lib`; added `types: ["bun"]`.
9
+ 5. Removed generated `tsconfig.build.json`; TSC compilation is now opt-in and documented in `README.md`.
10
+ 6. Renamed `scripts/build-lib-bundle.ts` to `scripts/build-bundle.ts` in root and template; updated to produce ESM and IIFE browser bundles; added to published `files`; updated CDN rewrite plugin filter.
11
+ 7. Extracted path constants from `src/cli.ts` to `src/constants.ts`; CLI now copies `README.md` as `README-template.md` to generated projects; improved error message for missing package name argument; moved `template/src/dev.ts` to `template/scripts/dev.ts`.
12
+ 8. Updated `scripts/buildinfo.ts` in root and template: reads version from `package.json` instead of `npm_package_version` env var; handles pre-existing `+` in version string.
13
+ 9. Refactored `template/tests/buildinfo.test.ts` to use a proper semver regex.
14
+ 10. Overhauled `README.md`: new documentation structure with build strategies overview, `package.json` and `tsconfig.json` sections referencing `create-workspace`, opt-in TSC Compilation section, `bin` field documentation, `scripts/dev.ts` section; removed `CLAUDE.md`/`AGENTS.md` section.
15
+ 11. Updated from `@temir.ra/template@0.1.3` template.
16
+
17
+ ## 0.6.3
18
+
19
+ 1. Cleaned up dormant package scripts.
20
+ 2. Cleaned up minor `README.md` inconsistencies.
21
+
22
+ ## 0.6.2
23
+
24
+ 1. Updated `clean:tsbuildinfo` script to remove both `tsconfig.tsbuildinfo` and `tsconfig.build.tsbuildinfo`.
25
+
3
26
  ## 0.6.1
4
27
 
5
28
  1. Cleaned up dormant imports.
package/README.md CHANGED
@@ -6,12 +6,15 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
6
6
 
7
7
  1. [Quick Start](#quick-start)
8
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. [`"bin"` field in `package.json`](#bin-field-in-packagejson)
9
+ 1. [`package.json`](#packagejson)
10
+ 2. [`"bin"` field in `package.json`](#bin-field-in-packagejson)
11
+ 3. [`scripts/dev.ts`](#scriptsdevts)
12
+ 4. [`tsconfig.json`](#tsconfigjson)
13
+ 5. [TSC Compilation](#tsc-compilation)
14
+ 1. [`tsconfig.build.json`](#tsconfigbuildjson)
15
+ 2. [`package.json`](#packagejson-1)
16
+ 6. [Script `scripts/build-bundle.ts`](#script-scriptsbuild-bundlets)
17
+ 1. [CDN Map `scripts/cdn-rewrite-map.json`](#cdn-map-scriptscdn-rewrite-mapjson)
15
18
  7. [Asset Resolution](#asset-resolution)
16
19
  1. [Externalized - loaded from CDN or `node_modules/`](#externalized---loaded-from-cdn-or-node_modules)
17
20
  2. [Bundled - absorbed into the consumer's output](#bundled---absorbed-into-the-consumers-output)
@@ -20,108 +23,178 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
20
23
  2. [Accessing assets](#accessing-assets)
21
24
  3. [README statement for library consumers](#readme-statement-for-library-consumers)
22
25
  4. [When the library is bundled by the consumer](#when-the-library-is-bundled-by-the-consumer)
23
- 8. [`src/dev.ts`](#srcdevts)
24
26
  3. [DevOps](#devops)
25
27
  1. [Change Management](#change-management)
26
28
  2. [Publish](#publish)
27
- 1. [npmjs.org](#npmjsorg)
28
- 2. [Custom registry](#custom-registry)
29
29
 
30
30
  # Quick Start
31
31
 
32
- *`bun create` caches the template package - a newer published version will not be picked up automatically. Pin the version or clear the cache to use the latest.*
33
-
34
32
  ```bash
35
33
  # placeholder:
34
+ # <TEMPLATE_PACKAGE: @temir.ra/create-ts-lib
35
+ # <TEMPLATE_NAME: @temir.ra/ts-lib
36
36
  # <NEW_PACKAGE: <NEW_PACKAGE>
37
+ # is used as:
38
+ # - the path where the package is created
39
+ # - the "name" field in the generated package.json
37
40
  # <@_VERSION: <@_VERSION>
38
41
 
39
- # identify the latest version of the template package as <@_VERSION.
42
+ # pinned version
40
43
  bun info "@temir.ra/create-ts-lib" version
41
- # create a new library from the template version
42
44
  bun create --no-install --no-git "@temir.ra/ts-lib<@_VERSION>" <NEW_PACKAGE>
43
45
 
44
- # or
45
-
46
- # clear package manager cache to ensure the latest template version is used
46
+ # latest
47
+ # clear the cache to pick up the latest version
47
48
  bun pm cache rm
48
- # create a new library from the latest template version
49
49
  bun create --no-install --no-git "@temir.ra/ts-lib" <NEW_PACKAGE>
50
50
 
51
- # dependencies must be installed manually
51
+ # templates only copy files, run install and any setup scripts manually
52
52
  cd <NEW_PACKAGE>
53
53
  bun install
54
54
  ```
55
55
 
56
56
  # Documentation
57
57
 
58
- 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.
58
+ The following sections explain the configurations and conventions baked into the generated package. Useful when adapting it to fit specific needs.
59
+
60
+ The central addition over [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace) is a build pipeline for distributing the library. Two build strategies are supported:
61
+
62
+ - **Bundling** (`scripts/build-bundle.ts`) - generated by default; bundles the library to ESM and IIFE formats.
63
+ - **TSC compilation** (`tsconfig.build.json` + `build:tsc`) - optional, not generated by default; compiles source files one-for-one to ESM JavaScript and declaration files.
64
+
65
+ Both strategies can be combined.
66
+
67
+ ## `package.json`
68
+
69
+ Selected fields are documented in the [`create-workspace` README](https://www.npmjs.com/package/@temir.ra/create-workspace#packagejson).
70
+
71
+ See npmjs documentation on [package.json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for detailed explanations of all fields.
59
72
 
60
- ## `tsconfig.json` and `tsconfig.build.json`
73
+ The following lists the additions and overrides relative to [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace#packagejson).
61
74
 
62
- See the typescriptlang documentation on [tsconfig.json](https://www.typescriptlang.org/tsconfig) for detailed explanations of all options.
75
+ The generated package is pre-configured with `build:bundle` only. See [TSC Compilation](#tsc-compilation) and [`"bin"` field](#bin-field-in-packagejson) for extending it.
63
76
 
64
77
  ```json
65
78
  {
66
79
 
67
- "compilerOptions": {
80
+ // ... ,
81
+
82
+ // the package is anticipated to be published
83
+ "private": false,
84
+
85
+ // treats all .js files as ES modules; use .cjs extension for CommonJS files
86
+ "type": "module",
87
+
88
+ // package entry points
89
+ //
90
+ // scripts/build-bundle.ts (non-standard) export condition:
91
+ // "entrypoint" - locates the source entry point for bundling
92
+ //
93
+ // standard export conditions:
94
+ // "types" - TypeScript consumers; resolves to the declaration files;
95
+ // "browser" - browser bundler consumers; resolves to the bundled output
96
+ // "import" - ESM consumers; resolves to the compiled module output
97
+ "exports": {
98
+ ".": {
99
+ "entrypoint": "./src/index.ts",
100
+ "types": "./dist/index.d.ts",
101
+ "browser": "./dist/index.bundle.js",
102
+ "import": "./dist/index.js"
103
+ }
104
+ },
105
+
106
+ // convenience alias for source-execution only - does NOT survive transpilation or bundling
107
+ // NOT for use in source files compiled by tsconfig.build.json
108
+ // the .js extension is required in import statements (nodenext compliance)
109
+ "imports": {
110
+ "#src/*.js": "./src/*.ts"
111
+ },
112
+
113
+ // CLI entry point
114
+ "bin": "./dist/cli.bundle.js",
115
+
116
+ // files to include in the published package
117
+ "files": [
118
+ "scripts/buildinfo.ts",
119
+ "scripts/build-bundle.ts",
120
+ "scripts/cdn-rewrite-map.json",
121
+ "dist",
122
+ "CHANGELOG.md",
123
+ "buildinfo.txt"
124
+ ],
125
+
126
+ "scripts": {
127
+
128
+ // ... ,
129
+
130
+ // executed before build; generates buildinfo.txt
131
+ "prebuild": "bun run buildinfo",
132
+
133
+ // convenience script to run the build steps in sequence
134
+ "build": "bun run build:tsc && bun run build:bundle && bun run build:cli-bundle",
135
+
136
+ // compiles the library to declaration files and ESM JavaScript in dist/
137
+ "build:tsc": "tsc --project tsconfig.build.json",
68
138
 
69
- // ECMAScript version of emitted output; ESNext targets the latest JS version supported by the TypeScript compiler
70
- // if the package must support older runtimes or browsers, pin to a specific year (e.g. "ES2022", "ES2024")
71
- "target": "ESNext",
139
+ // bundles the library into ESM and IIFE formats for distribution
140
+ "build:bundle": "bun run scripts/build-bundle.ts",
141
+
142
+ // bundles the CLI into a single file for distribution; requires the "bin" field to be set to the bundled output
143
+ "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
72
144
 
73
- // output module format; ESNext passes ES module syntax through unchanged
74
- // ES module syntax: import/export statements (as opposed to CommonJS require()/module.exports)
75
- "module": "ESNext",
145
+ }
76
146
 
77
- // type definitions for built-in APIs
78
- "lib": [
79
- "ESNext", // standard JavaScript runtime APIs
80
- "DOM" // browser globals for bundled output
81
- ],
147
+ }
148
+ ```
149
+
150
+ ## `"bin"` field in `package.json`
151
+
152
+ For CLI packages, add the following to `package.json`:
82
153
 
83
- // module resolution strategy; bundler mode allows omitting file extensions in imports
84
- // tsconfig.build.json overrides this to nodenext for strict ESM compliance
85
- "moduleResolution": "bundler",
154
+ ```json
155
+ {
156
+ // ... ,
157
+ "bin": "./dist/cli.bundle.js",
158
+ // ... ,
159
+ "scripts": {
160
+ // ... ,
161
+ "build": "... && bun run build:cli-bundle",
162
+ // ... ,
163
+ "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
164
+ }
165
+ }
166
+ ```
86
167
 
87
- // enables all strict type-checking options
88
- "strict": true,
168
+ `src/cli.ts` must begin with a hashbang so the OS knows which interpreter to invoke when the binary is executed directly. Bun preserves it in the bundled output.
89
169
 
90
- // enforces import type for type-only imports; emitted module syntax matches source exactly
91
- "verbatimModuleSyntax": true,
170
+ ```typescript
171
+ #!/usr/bin/env node
172
+ ```
92
173
 
93
- // array indexing and index signature access returns T | undefined instead of T
94
- "noUncheckedIndexedAccess": true,
174
+ If the package exports a CLI only and is not intended to be imported in other packages, the `exports` field can be omitted.
95
175
 
96
- // distinguishes absent optional properties from those explicitly set to undefined
97
- "exactOptionalPropertyTypes": true,
176
+ ## `scripts/dev.ts`
98
177
 
99
- // requires explicit override keyword when overriding base class methods
100
- "noImplicitOverride": true,
178
+ Development scratchpad. Execute it manually with `bun run --watch scripts/dev.ts`. Useful to test and explore library code during development.
101
179
 
102
- // requires explicit types on all exported declarations; enables parallel .d.ts generation by external tools
103
- "isolatedDeclarations": true,
180
+ ## `tsconfig.json`
104
181
 
105
- // allows default imports from CommonJS modules
106
- "esModuleInterop": true,
182
+ Selected fields are documented in the [`create-workspace` README](https://www.npmjs.com/package/@temir.ra/create-workspace#tsconfigjson).
107
183
 
108
- // enables project references and incremental builds via *.tsbuildinfo
109
- "composite": true,
184
+ See the TypeScript documentation on [tsconfig.json](https://www.typescriptlang.org/tsconfig) for detailed explanations of all options.
110
185
 
111
- // do not type-check `.d.ts` files in `node_modules/`
112
- "skipLibCheck": true,
186
+ The following lists the additions and overrides relative to [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace#tsconfigjson).
113
187
 
114
- // TS6 defaults types to [] — @types/* packages must be listed explicitly
115
- "types": ["bun"],
188
+ ```json
189
+ {
116
190
 
117
- // enforce consistent casing across import statements
118
- "forceConsistentCasingInFileNames": true,
191
+ "compilerOptions": {
119
192
 
120
- // allows importing JSON files as typed modules
121
- "resolveJsonModule": true,
193
+ // ... ,
122
194
 
123
195
  // emit .d.ts declaration files
124
196
  "declaration": true,
197
+
125
198
  // emit .d.ts.map files mapping declarations back to source
126
199
  "declarationMap": true,
127
200
 
@@ -129,32 +202,40 @@ See the typescriptlang documentation on [tsconfig.json](https://www.typescriptla
129
202
  "emitDeclarationOnly": true,
130
203
 
131
204
  // output directory for emitted files
132
- "outDir": "./dist",
133
-
134
- // root directory mirrored into outDir; set to project root during development, overridden to src/ in tsconfig.build.json (TS6 default — not set in actual config)
135
- "rootDir": ".",
205
+ "outDir": "./dist"
136
206
 
137
207
  },
138
208
 
139
- // includes src/, tests/, and scripts/ for type-checking and IDE support; overridden in tsconfig.build.json
140
209
  "include": [
141
- "src/**/*.ts",
142
- "tests/**/*.ts",
143
- "scripts/**/*.ts",
144
- "scripts/**/*.json"
210
+ // ... ,
211
+ // include `scripts/**/*.json` for script configuration files
212
+ "scripts/**/*.json",
213
+ // include `src/**/*.ts` for source files
214
+ "src/**/*.ts"
145
215
  ],
146
216
  "exclude": [
147
- "node_modules",
217
+ // ... ,
218
+ // exclude `dist/`
148
219
  "dist"
149
220
  ]
150
221
 
151
222
  }
152
223
  ```
153
224
 
154
- `tsconfig.json` is the development configuration. `tsconfig.build.json` extends it, narrowing scope to `src/` and enabling JavaScript output for distribution.
155
-
156
225
  `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`.
157
226
 
227
+ ## TSC Compilation
228
+
229
+ Not generated by default. Enables file-for-file tsc compilation of `src/` to ESM JavaScript and declaration files alongside bundling.
230
+
231
+ ### `tsconfig.build.json`
232
+
233
+ Extends `tsconfig.json`, narrowing scope to `src/` only and switching to `nodenext` module resolution for strict ESM compliance.
234
+
235
+ Enables JavaScript output alongside declaration files for distribution.
236
+
237
+ Development files (`dev.ts`, `tests/`, `scripts/`) are excluded.
238
+
158
239
  ```json
159
240
  {
160
241
 
@@ -174,11 +255,12 @@ See the typescriptlang documentation on [tsconfig.json](https://www.typescriptla
174
255
 
175
256
  },
176
257
 
258
+ // include only src/ files for distribution
177
259
  "include": [
178
260
  "src/**/*.ts"
179
261
  ],
262
+ // exclude development files and directories from distribution
180
263
  "exclude": [
181
- "src/dev.ts",
182
264
  "node_modules",
183
265
  "dist",
184
266
  "tests",
@@ -188,102 +270,30 @@ See the typescriptlang documentation on [tsconfig.json](https://www.typescriptla
188
270
  }
189
271
  ```
190
272
 
191
- ## `package.json`
192
-
193
- See npmjs documentation on [package.json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for detailed explanations of all fields.
273
+ ### `package.json`
194
274
 
195
275
  ```json
196
276
  {
197
- "name": "",
198
- "version": "0.0.0",
199
-
200
- "description": "",
201
- "author": "",
202
- "license": "",
203
-
204
- "keywords": ["typescript"],
205
-
206
- "repository": {
207
- "type": "git",
208
- "url": ""
209
- },
210
-
211
- // treats all .js files as ES modules; use .cjs extension for CommonJS files
212
- "type": "module",
213
-
214
- // package entry points by consumer type
215
- // "entrypoint" - custom condition; used by the bundle script to locate the source entry point
216
- // "types" - TypeScript consumers; resolves to the declaration files; must precede "import" so TypeScript matches it before the JS condition
217
- // "browser" - browser bundler consumers; resolves to the bundled output
218
- // "import" - ESM consumers; resolves to the compiled module output
219
- "exports": {
220
- ".": {
221
- "entrypoint": "./src/index.ts",
222
- "types": "./dist/index.d.ts",
223
- "browser": "./dist/index.bundle.js",
224
- "import": "./dist/index.js"
225
- }
226
- },
227
-
228
- // package-internal import alias resolved natively by Node.js and Bun at runtime; key must start with #
229
- // for use in dev.ts, tests/, and scripts/ only - NOT in library source files compiled by tsconfig.build.json
230
- // the .js extension is required in import statements (nodenext compliance);
231
- // the runtime maps it to the actual .ts source file via this field
232
- "imports": {
233
- "#src/*.js": "./src/*.ts"
234
- },
235
-
236
- // CLI entry point; omit if the package is not a CLI tool
237
- "bin": "./dist/cli.bundle.js",
238
-
239
- // files to include in the published package
240
- "files": [
241
- "dist",
242
- "CHANGELOG.md",
243
- "buildinfo.txt"
244
- ],
245
-
277
+ // ... ,
246
278
  "scripts": {
247
-
248
- "clean:dist": "rm -rf dist/",
249
- "clean:tsbuildinfo": "rm -f tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
250
- "clean": "bun run clean:dist && bun run clean:tsbuildinfo",
251
-
252
- // lifecycle hook; runs automatically before "build"; generates buildinfo.txt
253
- "prebuild": "bun run scripts/buildinfo.ts",
254
-
255
- "tests": "bun test",
256
-
257
- "build": "bun run build:lib && bun run build:lib-bundle",
258
-
259
- "build:lib": "tsc --project tsconfig.build.json",
260
- // bundles the library into ESM and IIFE formats for distribution
261
- "build:lib-bundle": "bun run scripts/build-lib-bundle.ts",
262
-
263
- "typecheck": "tsc --noEmit",
264
-
265
- // runs src/dev.ts in watch mode
266
- "dev": "bun run --watch src/dev.ts"
267
-
268
- },
269
- "devDependencies": {
270
- "@types/bun": "latest",
271
- "typescript": "^6.0.2"
279
+ // ... ,
280
+ "build": "bun run build:tsc && bun run build:bundle",
281
+ "build:tsc": "tsc --project tsconfig.build.json"
272
282
  }
273
283
  }
274
284
  ```
275
285
 
276
- ## Script `scripts/buildinfo.ts`
286
+ ## Script `scripts/build-bundle.ts`
277
287
 
278
- Generates `buildinfo.txt` containing the version from `package.json` and the git commit hash (if available). Included in the published package for build traceability.
288
+ Bundles the library to ESM and IIFE formats. Entry points are resolved from the `entrypoint` condition in the `exports` field of `package.json`. Note, the `entrypoint` condition is a custom, non-standard export condition used solely for build tooling.
279
289
 
280
- ## Script `scripts/build-lib-bundle.ts`
290
+ Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
281
291
 
282
- 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`.
292
+ ### CDN Map `scripts/cdn-rewrite-map.json`
283
293
 
284
- ## CDN Map `scripts/cdn-rewrite-map.json`
294
+ Maps import specifiers to CDN URLs. During bundling, matching specifiers in source files are rewritten to their CDN equivalents.
285
295
 
286
- 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`.
296
+ `<VERSION>` in a URL is replaced with the version of the matching package from `package.json`.
287
297
 
288
298
  ```json
289
299
  {
@@ -291,25 +301,6 @@ Maps import specifiers to CDN URLs. During bundling, matching specifiers in sour
291
301
  }
292
302
  ```
293
303
 
294
- ## `"bin"` field in `package.json`
295
-
296
- For CLI packages, add the following to `package.json`:
297
-
298
- ```json
299
- {
300
- "exports": ...,
301
- "bin": "./dist/cli.bundle.js",
302
- "files": ...,
303
- "scripts": {
304
- ...,
305
- "build": "... && bun run build:cli-bundle",
306
- ...,
307
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external",
308
- ...,
309
- }
310
- }
311
- ```
312
-
313
304
  ## Asset Resolution
314
305
 
315
306
  The key question to ask is: **does my library retain its own URL at runtime?** Everything else follows from it.
@@ -395,7 +386,7 @@ import { fileURLToPath } from 'url';
395
386
  const asset = JSON.parse(await readFile(fileURLToPath(new URL('<ASSET>', assetsUrl)), 'utf-8'));
396
387
  ```
397
388
 
398
- ### README statement for library consumers
389
+ #### README statement for library consumers
399
390
 
400
391
  ```markdown
401
392
  ## Asset resolution
@@ -418,27 +409,18 @@ consumer output/
418
409
 
419
410
  From the bundle's perspective `assets/<@SCOPE>/<LIB_NAME>/` is at the same directory level as `bundle.js`, so `new URL('assets/<@SCOPE>/<LIB_NAME>/...', import.meta.url)` resolves correctly. No code configuration is needed - only the file copy.
420
411
 
421
- ## `src/dev.ts`
422
-
423
- 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.
424
-
425
412
  # DevOps
426
413
 
427
414
  ```bash
428
- # remove dist/ and tsconfig.tsbuildinfo and tsconfig.build.tsbuildinfo
429
- bun run clean
430
-
431
- # remove dist/ only
432
- bun run clean:dist
433
-
434
- # remove tsconfig.tsbuildinfo and tsconfig.build.tsbuildinfo only
435
- bun run clean:tsbuildinfo
415
+ bun install
436
416
 
437
- # compile + bundle
417
+ bun run clean
438
418
  bun run build
419
+ bun run tests
420
+
421
+ bun run dev
439
422
 
440
- # create a new test library in example/
441
- bun run dist/cli.bundle.js -- example
423
+ # see publish section for publish instructions
442
424
  ```
443
425
 
444
426
  ## Change Management
@@ -448,7 +430,7 @@ bun run dist/cli.bundle.js -- example
448
430
  3. Bump the version in [`package.json`](package.json).
449
431
  4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
450
432
  5. Pull request the branch.
451
- 6. After merge, run `bun run build` - ensures artifacts are current before publish.
433
+ 6. Ensure package artifacts are current.
452
434
  7. Publish.
453
435
 
454
436
  ## Publish
package/buildinfo.txt CHANGED
@@ -1 +1 @@
1
- 0.6.1+f14d02f
1
+ 0.7.0+b45e7d0
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{cpSync as s,readFileSync as f,renameSync as u,writeFileSync as P}from"fs";import{resolve as t}from"path";import{resolve as o}from"path";import{fileURLToPath as h}from"url";var d=new URL("../",import.meta.url),n=o(h(d)),m=o(n,"template/"),p=o(n,"CHANGELOG.md"),g=o(n,"buildinfo.txt"),l=o(n,"README.md");try{let r=process.argv[2];if(!r)throw Error("Package name argument is required. Usage: `create-ts-lib <package-name>`");let a=r.replace(/\\/g,"/"),e=t(process.cwd(),a);s(m,e,{recursive:!0}),s(p,t(e,"CHANGELOG-template.md")),s(g,t(e,"buildinfo-template.txt")),s(l,t(e,"README-template.md"));let c=t(e,"package.json"),i=JSON.parse(f(c,"utf-8"));i.name=a,P(c,JSON.stringify(i,null,2)),u(t(e,"gitignore"),t(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${a}'.`)}catch(r){let a=r instanceof Error?r:Error(String(r));console.error("Error:",a.message),process.exit(1)}
2
+ import{cpSync as s,readFileSync as f,renameSync as u,writeFileSync as P}from"fs";import{resolve as t}from"path";import{resolve as o}from"path";import{fileURLToPath as h}from"url";var d=new URL("../",import.meta.url),n=o(h(d)),m=o(n,"template/"),p=o(n,"CHANGELOG.md"),g=o(n,"buildinfo.txt"),l=o(n,"README.md");try{let r=process.argv[2];if(!r)throw Error('First argument must be the package name (e.g. "my-package" or "@my-scope/my-package").');let a=r.replace(/\\/g,"/"),e=t(process.cwd(),a);s(m,e,{recursive:!0}),s(p,t(e,"CHANGELOG-template.md")),s(g,t(e,"buildinfo-template.txt")),s(l,t(e,"README-template.md"));let c=t(e,"package.json"),i=JSON.parse(f(c,"utf-8"));i.name=a,P(c,JSON.stringify(i,null,2)),u(t(e,"gitignore"),t(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${a}'.`)}catch(r){let a=r instanceof Error?r:Error(String(r));console.error("Error:",a.message),process.exit(1)}
3
3
 
4
- //# debugId=05227D46E6CAAF7464756E2164756E21
4
+ //# debugId=C4A0E6EEF1219B4364756E2164756E21
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["..\\src\\cli.ts", "..\\src\\constants.ts"],
4
4
  "sourcesContent": [
5
- "#!/usr/bin/env node\r\n\r\nimport { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';\r\nimport { resolve } from 'path';\r\nimport {\r\n templatePath,\r\n changelogPath,\r\n buildinfoPath,\r\n readmePath\r\n} from './constants.js';\r\n\r\n\r\ntry {\r\n\r\n const packageNameArgument = process.argv[2];\r\n if (!packageNameArgument) throw new Error('Package name argument is required. Usage: `create-ts-lib <package-name>`');\r\n const packageName = packageNameArgument.replace(/\\\\/g, '/');\r\n\r\n const destinationPath = resolve(process.cwd(), packageName);\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 packageJsonPath = resolve(destinationPath, 'package.json');\r\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\r\n packageJson.name = packageName;\r\n writeFileSync(packageJsonPath, JSON.stringify(packageJson, 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 } from 'path';\r\nimport {\r\n templatePath,\r\n changelogPath,\r\n buildinfoPath,\r\n readmePath\r\n} from './constants.js';\r\n\r\n\r\ntry {\r\n\r\n const packageNameArgument = process.argv[2];\r\n if (!packageNameArgument)\r\n throw new Error('First argument must be the package name (e.g. \"my-package\" or \"@my-scope/my-package\").');\r\n const packageName = packageNameArgument.replace(/\\\\/g, '/');\r\n\r\n const destinationPath = resolve(process.cwd(), packageName);\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 packageJsonPath = resolve(destinationPath, 'package.json');\r\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\r\n packageJson.name = packageName;\r\n writeFileSync(packageJsonPath, JSON.stringify(packageJson, 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
  "import { resolve } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\n\r\nexport const packageUrl: URL = new URL('../', import.meta.url);\r\nexport const packagePath: string = resolve(fileURLToPath(packageUrl));\r\n\r\nexport const templatePath: string = resolve(packagePath, 'template/');\r\n\r\nexport const changelogPath: string = resolve(packagePath, 'CHANGELOG.md');\r\nexport const buildinfoPath: string = resolve(packagePath, 'buildinfo.txt');\r\nexport const readmePath: string = resolve(packagePath, 'README.md');\r\n"
7
7
  ],
8
- "mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,aCHT,kBAAS,aACT,wBAAS,YAGF,IAAM,EAAkB,IAAI,IAAI,MAAO,YAAY,GAAG,EAChD,EAAsB,EAAQ,EAAc,CAAU,CAAC,EAEvD,EAAuB,EAAQ,EAAa,WAAW,EAEvD,EAAwB,EAAQ,EAAa,cAAc,EAC3D,EAAwB,EAAQ,EAAa,eAAe,EAC5D,EAAqB,EAAQ,EAAa,WAAW,EDClE,GAAI,CAEA,IAAM,EAAsB,QAAQ,KAAK,GACzC,GAAI,CAAC,EAAqB,MAAU,MAAM,0EAA0E,EACpH,IAAM,EAAc,EAAoB,QAAQ,MAAO,GAAG,EAEpD,EAAkB,EAAQ,QAAQ,IAAI,EAAG,CAAW,EAE1D,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,EAAkB,EAAQ,EAAiB,cAAc,EACzD,EAAc,KAAK,MAAM,EAAa,EAAiB,OAAO,CAAC,EACrE,EAAY,KAAO,EACnB,EAAc,EAAiB,KAAK,UAAU,EAAa,KAAM,CAAC,CAAC,EAEnE,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": "05227D46E6CAAF7464756E2164756E21",
8
+ "mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,aCHT,kBAAS,aACT,wBAAS,YAGF,IAAM,EAAkB,IAAI,IAAI,MAAO,YAAY,GAAG,EAChD,EAAsB,EAAQ,EAAc,CAAU,CAAC,EAEvD,EAAuB,EAAQ,EAAa,WAAW,EAEvD,EAAwB,EAAQ,EAAa,cAAc,EAC3D,EAAwB,EAAQ,EAAa,eAAe,EAC5D,EAAqB,EAAQ,EAAa,WAAW,EDClE,GAAI,CAEA,IAAM,EAAsB,QAAQ,KAAK,GACzC,GAAI,CAAC,EACD,MAAU,MAAM,wFAAwF,EAC5G,IAAM,EAAc,EAAoB,QAAQ,MAAO,GAAG,EAEpD,EAAkB,EAAQ,QAAQ,IAAI,EAAG,CAAW,EAE1D,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,EAAkB,EAAQ,EAAiB,cAAc,EACzD,EAAc,KAAK,MAAM,EAAa,EAAiB,OAAO,CAAC,EACrE,EAAY,KAAO,EACnB,EAAc,EAAiB,KAAK,UAAU,EAAa,KAAM,CAAC,CAAC,EAEnE,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": "C4A0E6EEF1219B4364756E2164756E21",
10
10
  "names": []
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temir.ra/create-ts-lib",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Typescript library template",
5
5
  "author": "temir.ra",
6
6
  "license": "MIT",
@@ -14,12 +14,16 @@
14
14
  "type": "git",
15
15
  "url": "https://git.chimps.quest/trs/create-ts-lib.git"
16
16
  },
17
+ "private": false,
17
18
  "type": "module",
18
19
  "imports": {
19
20
  "#src/*.js": "./src/*.ts"
20
21
  },
21
22
  "bin": "./dist/cli.bundle.js",
22
23
  "files": [
24
+ "scripts/buildinfo.ts",
25
+ "scripts/build-bundle.ts",
26
+ "scripts/cdn-rewrite-map.json",
23
27
  "dist",
24
28
  "CHANGELOG.md",
25
29
  "buildinfo.txt",
@@ -27,15 +31,15 @@
27
31
  ],
28
32
  "scripts": {
29
33
  "clean:dist": "rm -rf dist/",
30
- "clean:tsbuildinfo": "rm -f tsconfig.build.tsbuildinfo",
34
+ "clean:tsbuildinfo": "rm -f *.tsbuildinfo || true",
31
35
  "clean": "bun run clean:dist && bun run clean:tsbuildinfo",
32
- "prebuild": "bun run scripts/buildinfo.ts",
36
+ "buildinfo": "bun run scripts/buildinfo.ts",
33
37
  "tests": "bun test",
34
- "build": "bun run build:lib && bun run build:cli-bundle",
35
- "build:lib": "tsc --project tsconfig.build.json",
36
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external",
37
38
  "typecheck": "tsc --noEmit",
38
- "dev": "bun run --watch src/dev.ts"
39
+ "reinstall": "rm -rf node_modules && rm -f bun.lock && bun pm cache rm && bun install && bunx tsc --version",
40
+ "prebuild": "bun run buildinfo",
41
+ "build": "bun run build:cli-bundle",
42
+ "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
39
43
  },
40
44
  "devDependencies": {
41
45
  "@types/bun": "latest",
@@ -1,14 +1,15 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
+
3
4
  import CDN_REWRITE_MAP from './cdn-rewrite-map.json';
4
5
 
5
6
 
6
7
  interface ExportConditions {
7
8
  [key: string]: string | undefined;
8
- import?: string;
9
+ entrypoint?: string;
9
10
  types?: string;
10
11
  browser?: string;
11
- entrypoint?: string;
12
+ import?: string;
12
13
  }
13
14
 
14
15
  interface DependencyMap {
@@ -34,9 +35,9 @@ function getManifest(packageIdentifier?: string): PackageManifest {
34
35
  manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
35
36
  } catch {
36
37
  if (packageIdentifier)
37
- throw new Error("[scripts/build-lib-bundle.ts] Could not read manifest for '" + packageIdentifier + "' at '" + manifestPath + "'. Is it installed?");
38
+ throw new Error(`[scripts/build-bundle.ts] Could not read manifest for '${packageIdentifier}' at '${manifestPath}'.`);
38
39
  else
39
- throw new Error("[scripts/build-lib-bundle.ts] Could not read package manifest at '" + manifestPath + "'.");
40
+ throw new Error(`[scripts/build-bundle.ts] Could not read package manifest at '${manifestPath}'.`);
40
41
  }
41
42
 
42
43
  return manifest;
@@ -46,11 +47,13 @@ function getManifest(packageIdentifier?: string): PackageManifest {
46
47
  function getManifestEntrypoints(packageManifest: PackageManifest): string[] {
47
48
 
48
49
  const exports = packageManifest.exports;
49
- if (!exports) throw new Error('[scripts/build-lib-bundle.ts] No exports field found in package.json.');
50
+ if (!exports)
51
+ throw new Error(`[scripts/build-bundle.ts] No 'exports' field found in the given package manifest.`);
50
52
 
51
53
  const entrypoints = Object.entries(exports)
52
54
  .map(([key, conditions]) => {
53
- if (!conditions.entrypoint) throw new Error(`[scripts/build-lib-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
55
+ if (!conditions.entrypoint)
56
+ throw new Error(`[scripts/build-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
54
57
  return conditions.entrypoint;
55
58
  });
56
59
 
@@ -70,11 +73,13 @@ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string
70
73
  };
71
74
 
72
75
  version = dependencies[packageIdentifier];
73
- if (!version) throw new Error(`[scripts/build-lib-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
76
+ if (!version)
77
+ throw new Error(`[scripts/build-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
74
78
 
75
79
  }
76
80
  else {
77
- if (!manifest.version) throw new Error('[scripts/build-lib-bundle.ts] Package manifest does not contain a version field.');
81
+ if (!manifest.version)
82
+ throw new Error('[scripts/build-bundle.ts] Package manifest does not contain a version field.');
78
83
  version = manifest.version;
79
84
  }
80
85
 
@@ -109,11 +114,11 @@ const cdnRewritePlugin = {
109
114
 
110
115
 
111
116
  const entrypoints = getManifestEntrypoints(getManifest());
112
- console.log('[scripts/build-lib-bundle.ts] Entrypoints:', entrypoints);
117
+ console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
113
118
 
114
119
  let buildResult;
115
120
 
116
- console.log('[scripts/build-lib-bundle.ts] Starting ESM bundle build...');
121
+ console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
117
122
  buildResult = await Bun.build({
118
123
  entrypoints,
119
124
  outdir: 'dist',
@@ -126,15 +131,15 @@ buildResult = await Bun.build({
126
131
  });
127
132
 
128
133
  if (!buildResult.success) {
129
- console.error('[scripts/build-lib-bundle.ts] Build failed:');
134
+ console.error('[scripts/build-bundle.ts] Build failed:');
130
135
  for (const message of buildResult.logs) {
131
136
  console.error(message);
132
137
  }
133
138
  process.exit(1);
134
139
  }
135
- console.log('[scripts/build-lib-bundle.ts] ESM bundle build completed successfully.');
140
+ console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
136
141
 
137
- console.log('[scripts/build-lib-bundle.ts] Starting IIFE bundle build...');
142
+ console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
138
143
  buildResult = await Bun.build({
139
144
  entrypoints,
140
145
  outdir: 'dist',
@@ -147,10 +152,10 @@ buildResult = await Bun.build({
147
152
  });
148
153
 
149
154
  if (!buildResult.success) {
150
- console.error('[scripts/build-lib-bundle.ts] Build failed:');
155
+ console.error('[scripts/build-bundle.ts] Build failed:');
151
156
  for (const message of buildResult.logs) {
152
157
  console.error(message);
153
158
  }
154
159
  process.exit(1);
155
160
  }
156
- console.log('[scripts/build-lib-bundle.ts] IIFE bundle build completed successfully.');
161
+ console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
@@ -0,0 +1,25 @@
1
+ import { execSync } from 'child_process';
2
+ import { readFileSync, 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: string = JSON.parse(readFileSync('package.json', 'utf-8')).version;
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
18
+ ? version.includes('+')
19
+ ? `${version}.${gitHash}`
20
+ : `${version}+${gitHash}`
21
+ : version;
22
+
23
+ writeFileSync(BUILD_INFO_FILE, buildinfo.trim(), 'utf-8');
24
+
25
+ console.log(`'${BUILD_INFO_FILE}' has been updated with build info: ${buildinfo}`);
@@ -0,0 +1 @@
1
+ {}
@@ -2,4 +2,4 @@
2
2
 
3
3
  ## 0.0.0
4
4
 
5
- 1. Versioning initialized.
5
+ 1. Package created.
@@ -14,31 +14,25 @@
14
14
 
15
15
  # Quick Start
16
16
 
17
- ```bash
18
- # remove dist/ and tsconfig.tsbuildinfo and tsconfig.build.tsbuildinfo
19
- bun run clean
17
+ *&lt;QUICK START INSTRUCTIONS&gt;*
20
18
 
21
- # remove dist/ only
22
- bun run clean:dist
19
+ # Documentation
23
20
 
24
- # remove tsconfig.tsbuildinfo and tsconfig.build.tsbuildinfo only
25
- bun run clean:tsbuildinfo
21
+ *&lt;DOCUMENTATION&gt;*
26
22
 
27
- # compile + bundle
28
- bun run build
23
+ # DevOps
24
+
25
+ ```bash
26
+ bun install
29
27
 
30
- # run tests
28
+ bun run clean
29
+ bun run build
31
30
  bun run tests
32
31
 
33
- # run src/dev.ts in watch mode
34
32
  bun run dev
35
- ```
36
-
37
- # Documentation
38
33
 
39
- *&lt;DOCUMENTATION&gt;*
40
-
41
- # DevOps
34
+ # see publish section for publish instructions
35
+ ```
42
36
 
43
37
  ## Change Management
44
38
 
@@ -47,7 +41,7 @@ bun run dev
47
41
  3. Bump the version in [`package.json`](package.json).
48
42
  4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
49
43
  5. Pull request the branch.
50
- 6. After merge, run `bun run build` - ensures artifacts are current before publish.
44
+ 6. Ensure package artifacts are current.
51
45
  7. Publish.
52
46
 
53
47
  ## Publish
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -1,7 +1,7 @@
1
- dist
2
1
  node_modules
3
2
  buildinfo.txt
4
3
  *.tsbuildinfo
5
4
  buildinfo-template.txt
6
5
  CHANGELOG-template.md
7
6
  README-template.md
7
+ dist
@@ -11,6 +11,7 @@
11
11
  "type": "git",
12
12
  "url": ""
13
13
  },
14
+ "private": false,
14
15
  "type": "module",
15
16
  "exports": {
16
17
  ".": {
@@ -24,21 +25,24 @@
24
25
  "#src/*.js": "./src/*.ts"
25
26
  },
26
27
  "files": [
28
+ "scripts/buildinfo.ts",
29
+ "scripts/build-bundle.ts",
30
+ "scripts/cdn-rewrite-map.json",
27
31
  "dist",
28
32
  "CHANGELOG.md",
29
33
  "buildinfo.txt"
30
34
  ],
31
35
  "scripts": {
32
36
  "clean:dist": "rm -rf dist/",
33
- "clean:tsbuildinfo": "rm -f tsconfig.build.tsbuildinfo",
37
+ "clean:tsbuildinfo": "rm -f *.tsbuildinfo || true",
34
38
  "clean": "bun run clean:dist && bun run clean:tsbuildinfo",
35
- "prebuild": "bun run scripts/buildinfo.ts",
39
+ "buildinfo": "bun run scripts/buildinfo.ts",
36
40
  "tests": "bun test",
37
- "build": "bun run build:lib && bun run build:lib-bundle",
38
- "build:lib": "tsc --project tsconfig.build.json",
39
- "build:lib-bundle": "bun run scripts/build-lib-bundle.ts",
40
41
  "typecheck": "tsc --noEmit",
41
- "dev": "bun run --watch src/dev.ts"
42
+ "reinstall": "rm -rf node_modules && rm -f bun.lock && bun pm cache rm && bun install && bunx tsc --version",
43
+ "prebuild": "bun run buildinfo",
44
+ "build": "bun run build:bundle",
45
+ "build:bundle": "bun run scripts/build-bundle.ts"
42
46
  },
43
47
  "devDependencies": {
44
48
  "@types/bun": "latest",
@@ -0,0 +1,161 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+
4
+ import CDN_REWRITE_MAP from './cdn-rewrite-map.json';
5
+
6
+
7
+ interface ExportConditions {
8
+ [key: string]: string | undefined;
9
+ entrypoint?: string;
10
+ types?: string;
11
+ browser?: string;
12
+ import?: string;
13
+ }
14
+
15
+ interface DependencyMap {
16
+ [packageName: string]: string;
17
+ }
18
+
19
+ interface PackageManifest {
20
+ version: string;
21
+ exports?: Record<string, ExportConditions>;
22
+ dependencies?: DependencyMap;
23
+ devDependencies?: DependencyMap;
24
+ peerDependencies?: DependencyMap;
25
+ }
26
+
27
+ function getManifest(packageIdentifier?: string): PackageManifest {
28
+
29
+ const manifestPath = packageIdentifier
30
+ ? join('node_modules', packageIdentifier, 'package.json')
31
+ : 'package.json';
32
+
33
+ let manifest: PackageManifest;
34
+ try {
35
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
36
+ } catch {
37
+ if (packageIdentifier)
38
+ throw new Error(`[scripts/build-bundle.ts] Could not read manifest for '${packageIdentifier}' at '${manifestPath}'.`);
39
+ else
40
+ throw new Error(`[scripts/build-bundle.ts] Could not read package manifest at '${manifestPath}'.`);
41
+ }
42
+
43
+ return manifest;
44
+
45
+ }
46
+
47
+ function getManifestEntrypoints(packageManifest: PackageManifest): string[] {
48
+
49
+ const exports = packageManifest.exports;
50
+ if (!exports)
51
+ throw new Error(`[scripts/build-bundle.ts] No 'exports' field found in the given package manifest.`);
52
+
53
+ const entrypoints = Object.entries(exports)
54
+ .map(([key, conditions]) => {
55
+ if (!conditions.entrypoint)
56
+ throw new Error(`[scripts/build-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
57
+ return conditions.entrypoint;
58
+ });
59
+
60
+ return entrypoints;
61
+
62
+ }
63
+
64
+ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string): string {
65
+
66
+ let version: string | undefined;
67
+ if (packageIdentifier) {
68
+
69
+ const dependencies = {
70
+ ...manifest.dependencies,
71
+ ...manifest.devDependencies,
72
+ ...manifest.peerDependencies,
73
+ };
74
+
75
+ version = dependencies[packageIdentifier];
76
+ if (!version)
77
+ throw new Error(`[scripts/build-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
78
+
79
+ }
80
+ else {
81
+ if (!manifest.version)
82
+ throw new Error('[scripts/build-bundle.ts] Package manifest does not contain a version field.');
83
+ version = manifest.version;
84
+ }
85
+
86
+ return version;
87
+
88
+ }
89
+
90
+ function resolveCdnUrl(importSpecifier: string, urlTemplate: string): string {
91
+ const manifest = getManifest();
92
+ const version = getPackageVersion(manifest, importSpecifier);
93
+ return urlTemplate.replace('<VERSION>', version);
94
+ }
95
+
96
+ const cdnRewritePlugin = {
97
+ name: 'cdn-rewrite',
98
+ setup(build: any) {
99
+
100
+ const resolved = new Map<string, string>();
101
+ for (const [importSpecifier, urlTemplate] of Object.entries(CDN_REWRITE_MAP) as [string, string][]) {
102
+ const url = resolveCdnUrl(importSpecifier, urlTemplate);
103
+ resolved.set(importSpecifier, url);
104
+ console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
105
+ }
106
+
107
+ build.onResolve({ filter: /\*/ }, (args: any) => {
108
+ const url = resolved.get(args.path);
109
+ if (url) return { path: url, external: true };
110
+ });
111
+
112
+ },
113
+ };
114
+
115
+
116
+ const entrypoints = getManifestEntrypoints(getManifest());
117
+ console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
118
+
119
+ let buildResult;
120
+
121
+ console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
122
+ buildResult = await Bun.build({
123
+ entrypoints,
124
+ outdir: 'dist',
125
+ naming: '[dir]/[name].bundle.[ext]',
126
+ target: 'browser',
127
+ format: 'esm',
128
+ minify: true,
129
+ sourcemap: 'external',
130
+ plugins: [cdnRewritePlugin],
131
+ });
132
+
133
+ if (!buildResult.success) {
134
+ console.error('[scripts/build-bundle.ts] Build failed:');
135
+ for (const message of buildResult.logs) {
136
+ console.error(message);
137
+ }
138
+ process.exit(1);
139
+ }
140
+ console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
141
+
142
+ console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
143
+ buildResult = await Bun.build({
144
+ entrypoints,
145
+ outdir: 'dist',
146
+ naming: '[dir]/[name].iife.[ext]',
147
+ target: 'browser',
148
+ format: 'iife',
149
+ minify: true,
150
+ sourcemap: 'external',
151
+ plugins: [cdnRewritePlugin],
152
+ });
153
+
154
+ if (!buildResult.success) {
155
+ console.error('[scripts/build-bundle.ts] Build failed:');
156
+ for (const message of buildResult.logs) {
157
+ console.error(message);
158
+ }
159
+ process.exit(1);
160
+ }
161
+ console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
@@ -7,7 +7,7 @@ const packageUrl = new URL('../', import.meta.url);
7
7
  console.log(`'packagePath':`, fileURLToPath(packageUrl));
8
8
 
9
9
 
10
- // dev code
10
+ // dev scratchpad
11
11
 
12
12
 
13
13
  console.log(`${(performance.now() - start).toFixed(3)}ms`);
@@ -3,8 +3,7 @@
3
3
  "target": "ESNext",
4
4
  "module": "ESNext",
5
5
  "lib": [
6
- "ESNext",
7
- "DOM"
6
+ "ESNext"
8
7
  ],
9
8
  "moduleResolution": "bundler",
10
9
  "strict": true,
@@ -24,13 +23,13 @@
24
23
  "declaration": true,
25
24
  "declarationMap": true,
26
25
  "emitDeclarationOnly": true,
27
- "outDir": "./dist",
26
+ "outDir": "./dist"
28
27
  },
29
28
  "include": [
30
- "src/**/*.ts",
31
29
  "tests/**/*.ts",
32
30
  "scripts/**/*.ts",
33
- "scripts/**/*.json"
31
+ "scripts/**/*.json",
32
+ "src/**/*.ts"
34
33
  ],
35
34
  "exclude": [
36
35
  "node_modules",
package/dist/cli.d.ts DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- import { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';
3
- import { resolve } from 'path';
4
- import { templatePath, changelogPath, buildinfoPath, readmePath } from './constants.js';
5
- try {
6
- const packageNameArgument = process.argv[2];
7
- if (!packageNameArgument)
8
- throw new Error('Package name argument is required. Usage: `create-ts-lib <package-name>`');
9
- const packageName = packageNameArgument.replace(/\\/g, '/');
10
- const destinationPath = resolve(process.cwd(), packageName);
11
- cpSync(templatePath, destinationPath, { recursive: true });
12
- cpSync(changelogPath, resolve(destinationPath, 'CHANGELOG-template.md'));
13
- cpSync(buildinfoPath, resolve(destinationPath, 'buildinfo-template.txt'));
14
- cpSync(readmePath, resolve(destinationPath, 'README-template.md'));
15
- const packageJsonPath = resolve(destinationPath, 'package.json');
16
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
17
- packageJson.name = packageName;
18
- writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
19
- renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));
20
- console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);
21
- }
22
- catch (error) {
23
- const err = error instanceof Error ? error : new Error(String(error));
24
- console.error('Error:', err.message);
25
- process.exit(1);
26
- }
@@ -1,7 +0,0 @@
1
- export declare const packageUrl: URL;
2
- export declare const packagePath: string;
3
- export declare const templatePath: string;
4
- export declare const changelogPath: string;
5
- export declare const buildinfoPath: string;
6
- export declare const readmePath: string;
7
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,EAAE,GAAqC,CAAC;AAC/D,eAAO,MAAM,WAAW,EAAE,MAA2C,CAAC;AAEtE,eAAO,MAAM,YAAY,EAAE,MAA0C,CAAC;AAEtE,eAAO,MAAM,aAAa,EAAE,MAA6C,CAAC;AAC1E,eAAO,MAAM,aAAa,EAAE,MAA8C,CAAC;AAC3E,eAAO,MAAM,UAAU,EAAE,MAA0C,CAAC"}
package/dist/constants.js DELETED
@@ -1,8 +0,0 @@
1
- import { resolve } from 'path';
2
- import { fileURLToPath } from 'url';
3
- export const packageUrl = new URL('../', import.meta.url);
4
- export const packagePath = resolve(fileURLToPath(packageUrl));
5
- export const templatePath = resolve(packagePath, 'template/');
6
- export const changelogPath = resolve(packagePath, 'CHANGELOG.md');
7
- export const buildinfoPath = resolve(packagePath, 'buildinfo.txt');
8
- export const readmePath = resolve(packagePath, 'README.md');
@@ -1,19 +0,0 @@
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
- }