importmapify 1.5.0 → 1.6.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/README.md CHANGED
@@ -21,12 +21,14 @@ per matched source file instead. This package performs that expansion and writes
21
21
 
22
22
  ```sh
23
23
  npm install importmapify
24
+ deno add jsr:@kjanat/importmapify
24
25
  ```
25
26
 
26
27
  ## CLI
27
28
 
28
29
  ```sh
29
30
  npx importmapify --root . --out import_map.json
31
+ deno run -A jsr:@kjanat/importmapify [...]
30
32
  ```
31
33
 
32
34
  | Flag | Alias | Meaning | Default |
package/deno.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/denoland/deno/refs/heads/main/cli/schemas/config-file.v1.json",
3
3
  "name": "@kjanat/importmapify",
4
- "version": "1.5.0",
4
+ "version": "1.6.0",
5
5
  "exports": "./src/mod.ts",
6
6
  "publish": {
7
7
  "include": [
@@ -16,26 +16,38 @@
16
16
  "compilerOptions": {
17
17
  "lib": ["ESNext", "DOM", "deno.ns"]
18
18
  },
19
- "importMap": "./import_map.json",
19
+ "importMap": "import_map.json",
20
20
  "license": "MIT",
21
21
  "tasks": {
22
22
  "build": {
23
- "description": "build for npm distribution",
24
- "command": "bun run build",
25
- "files": ["src/**", "package.json", "bun.lock"],
26
- "output": ["dist/**", "deno.json"]
23
+ "description": "build for npm distribution (requires bun)",
24
+ "command": "bun run build"
27
25
  },
28
26
  "publish": {
29
27
  "command": "deno publish --config deno.json --allow-dirty",
30
- "description": "Publish package to jsr",
31
- "dependencies": ["importmapify"]
28
+ "description": "Publish package to jsr"
32
29
  },
33
30
  "importmapify": {
34
- "description": "generate importmap for deno",
35
- "command": "bun scripts/generate-importmap.ts",
36
- "files": ["package.json", "scripts/generate-importmap.ts", "src/**"],
37
- "output": ["import_map.json"]
38
- }
31
+ "description": "generate importmap for deno (requires bun)",
32
+ "command": "bun scripts/generate-importmap.ts"
33
+ },
34
+ "doc:html": {
35
+ "command": "sh -c 'set -e; root=$PWD; [ -f dist/mod.d.mts ] || bun run build; tmp=$(mktemp -d); { awk \"NR>1{print} /\\*\\//{if(NR>1) exit}\" src/mod.ts; cat dist/mod.d.mts; } > \"$tmp/importmapify.d.ts\"; cd \"$tmp\"; deno doc --html --name=\"$(jq -r .name \"$root/package.json\")\" --category-docs=\"$root/category-docs.json\" --output=\"$root/.denodocs/\" ./importmapify.d.ts; cd \"$root\"; deno doc --json $(jq -r \".exports | .[]? // .\" deno.json) > \"$tmp/nodes.json\" 2>/dev/null; bun scripts/link-source-buttons.mjs .denodocs \"$tmp/nodes.json\" \"$(git rev-parse HEAD)\"; bun scripts/inject-favicon.mjs .denodocs assets/favicon.svg; bunx vite-svg-to-ico generate assets/favicon.svg --out-dir .denodocs; rm -rf \"$tmp\"'",
36
+ "description": "generate categorized HTML docs into .denodocs (requires bun)"
37
+ },
38
+ "doc:json": {
39
+ "command": "mkdir -p .denodocs && deno doc --name=\"$(jq -r .name package.json)\" --json $(jq -r '.exports | .[]? // .' deno.json) > .denodocs/documentation.json",
40
+ "description": "emit JSON doc nodes into .denodocs"
41
+ },
42
+ "doc:lint": {
43
+ "command": "deno doc --lint $(jq -r '.exports | .[]? // .' deno.json)",
44
+ "description": "lint docs on exported symbols"
45
+ },
46
+ "format:docs": {
47
+ "command": "bunx dprint fmt --includes-override '.denodocs/**/*.{html,css,js,json}' --excludes-override='!.denodocs/**/*.{html,css,js,json}' --no-gitignore --allow-no-files",
48
+ "description": "format the output docs (requires bun)"
49
+ },
50
+ "ci:docs": "run -s doc:html doc:json format:docs"
39
51
  },
40
52
  "lint": {
41
53
  "rules": {
@@ -43,7 +55,7 @@
43
55
  }
44
56
  },
45
57
  "preferPackageJson": false,
46
- "homepage": "https://github.com/kjanat/importmapify#readme",
58
+ "homepage": "https://importmapify.kjanat.dev",
47
59
  "repository": {
48
60
  "type": "git",
49
61
  "url": "git+https://github.com/kjanat/importmapify.git"
package/dist/mod.d.mts CHANGED
@@ -12,6 +12,7 @@
12
12
  * scopes: { './tests/': { '#lib/bytes': './tests/stub/bytes.ts' } },
13
13
  * };
14
14
  * ```
15
+ * @category Generate
15
16
  */
16
17
  interface ImportMapDocument {
17
18
  /**
@@ -45,6 +46,7 @@ interface ImportMapDocument {
45
46
  *
46
47
  * const root: PathOrUrl = new URL('..', import.meta.url);
47
48
  * ```
49
+ * @category Options
48
50
  */
49
51
  type PathOrUrl = string | URL;
50
52
  /**
@@ -58,6 +60,7 @@ type PathOrUrl = string | URL;
58
60
  * // Drop hashed internal chunks like ./dist/internal-qo9O8jzH.js.
59
61
  * const filter: readonly TargetFilter[] = [/^(?!.*internal)/];
60
62
  * ```
63
+ * @category Options
61
64
  */
62
65
  type TargetFilter = RegExp | ((target: string) => boolean);
63
66
  /**
@@ -75,6 +78,7 @@ type TargetFilter = RegExp | ((target: string) => boolean);
75
78
  *
76
79
  * createImportMap(options);
77
80
  * ```
81
+ * @category Options
78
82
  */
79
83
  interface CreateImportMapOptions {
80
84
  /**
@@ -194,6 +198,7 @@ interface CreateImportMapOptions {
194
198
  *
195
199
  * writeImportMap(options);
196
200
  * ```
201
+ * @category Options
197
202
  */
198
203
  interface WriteImportMapOptions extends CreateImportMapOptions {
199
204
  /**
@@ -232,6 +237,7 @@ interface WriteImportMapOptions extends CreateImportMapOptions {
232
237
  *
233
238
  * const logRoot = (ctx: HookContext) => console.log(`scanning ${ctx.root}, writing ${ctx.out}`);
234
239
  * ```
240
+ * @category Configuration
235
241
  */
236
242
  interface HookContext {
237
243
  /**
@@ -270,6 +276,7 @@ interface HookContext {
270
276
  * },
271
277
  * });
272
278
  * ```
279
+ * @category Configuration
273
280
  */
274
281
  interface ImportMapHooks {
275
282
  /**
@@ -308,6 +315,7 @@ interface ImportMapHooks {
308
315
  * extensions: ['ts'],
309
316
  * });
310
317
  * ```
318
+ * @category Configuration
311
319
  */
312
320
  interface Config extends Partial<WriteImportMapOptions> {
313
321
  /**
@@ -343,6 +351,7 @@ interface Config extends Partial<WriteImportMapOptions> {
343
351
  *
344
352
  * @param options Project, manifest, condition, and rebasing options.
345
353
  * @returns A sorted import map document.
354
+ * @category Generate
346
355
  */
347
356
  declare function createImportMap(options: CreateImportMapOptions): ImportMapDocument;
348
357
  /**
@@ -361,6 +370,7 @@ declare function createImportMap(options: CreateImportMapOptions): ImportMapDocu
361
370
  * @param map Import map to serialize.
362
371
  * @param indent Indentation with `JSON.stringify` space semantics; defaults to a tab.
363
372
  * @returns Formatted JSON ready to print or write.
373
+ * @category Generate
364
374
  */
365
375
  declare function formatImportMap(map: ImportMapDocument, indent?: string | number): string;
366
376
  /**
@@ -380,6 +390,7 @@ declare function formatImportMap(map: ImportMapDocument, indent?: string | numbe
380
390
  *
381
391
  * @param options Creation options plus the optional output path.
382
392
  * @returns The absolute path of the written file.
393
+ * @category Generate
383
394
  */
384
395
  declare function writeImportMap(options: WriteImportMapOptions): string;
385
396
  /**
@@ -399,6 +410,7 @@ declare function writeImportMap(options: WriteImportMapOptions): string;
399
410
  * @param name Bare package specifier.
400
411
  * @param target Exact target for {@link name}.
401
412
  * @returns The bare entry and its trailing-slash subpath entry.
413
+ * @category Generate
402
414
  */
403
415
  declare function packageEntries(name: string, target: string): Record<string, string>;
404
416
  /**
@@ -433,6 +445,7 @@ declare function packageEntries(name: string, target: string): Record<string, st
433
445
  * @param config Import map configuration; every field is optional.
434
446
  * @returns The same {@linkcode config} value with its exact type preserved, so a config that includes {@linkcode CreateImportMapOptions.root} stays
435
447
  * assignable to {@link writeImportMap} while one that omits it is still a valid config file.
448
+ * @category Configuration
436
449
  */
437
450
  declare function defineConfig<T extends Config>(config: T): T;
438
451
  //#endregion
package/dist/mod.mjs CHANGED
@@ -118,6 +118,10 @@ function rebaseTarget(root, relativeTo, target) {
118
118
  }
119
119
  //#endregion
120
120
  //#region src/config.ts
121
+ /** Set `key` on `target` unless the value is `undefined`, keeping the key/value pairing type-checked. */
122
+ function assign(target, key, value) {
123
+ if (value !== void 0) target[key] = value;
124
+ }
121
125
  const CONFIG_BASENAMES = ["importmapify.config", ".importmapify"];
122
126
  const CONFIG_EXTENSIONS = [
123
127
  "mjs",
@@ -200,6 +204,11 @@ function asScopes(value) {
200
204
  }
201
205
  return scopes;
202
206
  }
207
+ function resolveRoot(root, configDir) {
208
+ if (root === void 0) return configDir;
209
+ if (typeof root === "string" && !path.isAbsolute(root) && !root.startsWith("file://")) return path.resolve(configDir, root);
210
+ return root;
211
+ }
203
212
  function isHook(value) {
204
213
  return typeof value === "function";
205
214
  }
@@ -223,33 +232,18 @@ function asHooks(value) {
223
232
  * @returns The subset of {@link WriteImportMapOptions} the config declares, plus any hooks.
224
233
  */
225
234
  function configToOptions(config, configDir) {
226
- const result = {};
227
- const root = asPath(config.root);
228
- if (root === void 0) result.root = configDir;
229
- else if (typeof root === "string" && !path.isAbsolute(root) && !root.startsWith("file://")) result.root = path.resolve(configDir, root);
230
- else result.root = root;
231
- const manifest = asString(config.manifest);
232
- if (manifest !== void 0) result.manifest = manifest;
233
- const out = asPath(config.out);
234
- if (out !== void 0) result.out = out;
235
- const indent = asIndent(config.indent);
236
- if (indent !== void 0) result.indent = indent;
237
- const relativeTo = asPath(config.relativeTo);
238
- if (relativeTo !== void 0) result.relativeTo = relativeTo;
239
- const conditions = asStringArray(config.conditions);
240
- if (conditions !== void 0) result.conditions = conditions;
241
- const extensions = asStringArray(config.extensions);
242
- if (extensions !== void 0) result.extensions = extensions;
243
- const filter = asTargetFilters(config.filter);
244
- if (filter !== void 0) result.filter = filter;
245
- const packages = asStringRecord(config.packages);
246
- if (packages !== void 0) result.packages = packages;
247
- const additionalImports = asStringRecord(config.additionalImports);
248
- if (additionalImports !== void 0) result.additionalImports = additionalImports;
249
- const scopes = asScopes(config.scopes);
250
- if (scopes !== void 0) result.scopes = scopes;
251
- const hooks = asHooks(config.hooks);
252
- if (hooks !== void 0) result.hooks = hooks;
235
+ const result = { root: resolveRoot(asPath(config.root), configDir) };
236
+ assign(result, "manifest", asString(config.manifest));
237
+ assign(result, "out", asPath(config.out));
238
+ assign(result, "indent", asIndent(config.indent));
239
+ assign(result, "relativeTo", asPath(config.relativeTo));
240
+ assign(result, "conditions", asStringArray(config.conditions));
241
+ assign(result, "extensions", asStringArray(config.extensions));
242
+ assign(result, "filter", asTargetFilters(config.filter));
243
+ assign(result, "packages", asStringRecord(config.packages));
244
+ assign(result, "additionalImports", asStringRecord(config.additionalImports));
245
+ assign(result, "scopes", asScopes(config.scopes));
246
+ assign(result, "hooks", asHooks(config.hooks));
253
247
  return result;
254
248
  }
255
249
  /**
@@ -271,12 +265,26 @@ function mergeScopes(base, overrides) {
271
265
  //#endregion
272
266
  //#region src/map.ts
273
267
  const DEFAULT_CONDITIONS = ["import", "default"];
268
+ /** Default output filename for a written import map. */
274
269
  const DEFAULT_OUT = "import_map.json";
275
270
  const SCHEME_PREFIX = /^(jsr|npm):(?!\/)/;
271
+ /**
272
+ * Normalize a location to a filesystem path.
273
+ *
274
+ * @param value Path string, `file://` URL string, or {@link URL}.
275
+ * @returns The filesystem path.
276
+ */
276
277
  function toPath(value) {
277
278
  if (typeof value === "string") return value.startsWith("file://") ? fileURLToPath(value) : value;
278
279
  return fileURLToPath(value.href);
279
280
  }
281
+ /**
282
+ * Resolve an output location against a project root.
283
+ *
284
+ * @param root Project root directory.
285
+ * @param out Output location, relative or absolute.
286
+ * @returns The absolute output path.
287
+ */
280
288
  function resolveOut(root, out) {
281
289
  return path.resolve(toPath(root), toPath(out));
282
290
  }
@@ -398,6 +406,7 @@ function rebaseScopePrefix(root, relativeTo, scope) {
398
406
  *
399
407
  * @param options Project, manifest, condition, and rebasing options.
400
408
  * @returns A sorted import map document.
409
+ * @category Generate
401
410
  */
402
411
  function createImportMap(options) {
403
412
  const root = toPath(options.root);
@@ -413,7 +422,7 @@ function createImportMap(options) {
413
422
  for (const [key, value] of Object.entries(collectAdditional(options))) imports[key] = rebaseTarget(root, relativeTo, value);
414
423
  const scopes = buildScopes$1(root, relativeTo, options.scopes ?? {});
415
424
  const sortedImports = sortEntries(imports);
416
- const sortedScopes = Object.fromEntries(Object.entries(scopes).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
425
+ const sortedScopes = sortEntries(scopes);
417
426
  return Object.keys(sortedScopes).length === 0 ? { imports: sortedImports } : {
418
427
  imports: sortedImports,
419
428
  scopes: sortedScopes
@@ -435,6 +444,7 @@ function createImportMap(options) {
435
444
  * @param map Import map to serialize.
436
445
  * @param indent Indentation with `JSON.stringify` space semantics; defaults to a tab.
437
446
  * @returns Formatted JSON ready to print or write.
447
+ * @category Generate
438
448
  */
439
449
  function formatImportMap(map, indent = " ") {
440
450
  return `${JSON.stringify(map, null, indent)}\n`;
@@ -456,6 +466,7 @@ function formatImportMap(map, indent = " ") {
456
466
  *
457
467
  * @param options Creation options plus the optional output path.
458
468
  * @returns The absolute path of the written file.
469
+ * @category Generate
459
470
  */
460
471
  function writeImportMap(options) {
461
472
  const out = resolveOut(options.root, options.out ?? "import_map.json");
@@ -488,6 +499,7 @@ function directoryTarget(target) {
488
499
  * @param name Bare package specifier.
489
500
  * @param target Exact target for {@link name}.
490
501
  * @returns The bare entry and its trailing-slash subpath entry.
502
+ * @category Generate
491
503
  */
492
504
  function packageEntries(name, target) {
493
505
  return {
@@ -527,6 +539,7 @@ function packageEntries(name, target) {
527
539
  * @param config Import map configuration; every field is optional.
528
540
  * @returns The same {@linkcode config} value with its exact type preserved, so a config that includes {@linkcode CreateImportMapOptions.root} stays
529
541
  * assignable to {@link writeImportMap} while one that omits it is still a valid config file.
542
+ * @category Configuration
530
543
  */
531
544
  function defineConfig(config) {
532
545
  return config;
@@ -649,12 +662,12 @@ async function resolveGenerateOptions(flags) {
649
662
  },
650
663
  scopes: mergeScopes(base.scopes, buildScopes(flags.scope ?? []))
651
664
  };
652
- if (base.relativeTo !== void 0) options.relativeTo = base.relativeTo;
653
- if (indent !== void 0) options.indent = indent;
654
- if (conditions !== void 0) options.conditions = conditions;
655
- if (extensions !== void 0) options.extensions = extensions;
656
- if (filter !== void 0) options.filter = filter;
657
- if (base.hooks !== void 0) options.hooks = base.hooks;
665
+ assign(options, "relativeTo", base.relativeTo);
666
+ assign(options, "indent", indent);
667
+ assign(options, "conditions", conditions);
668
+ assign(options, "extensions", extensions);
669
+ assign(options, "filter", filter);
670
+ assign(options, "hooks", base.hooks);
658
671
  return options;
659
672
  }
660
673
  /** DreamCLI command that writes, checks, or prints an expanded Deno import map. */
@@ -700,10 +713,22 @@ const generateCommand = command("generate").description("Expand package.json sub
700
713
  //#endregion
701
714
  //#region src/mod.ts
702
715
  /**
716
+ *
717
+ * [![NPM](https://img.shields.io/npm/v/importmapify?logo=npm&labelColor=CB3837&color=black)][npm]
718
+ * [![JSR](https://img.shields.io/jsr/v/@kjanat/importmapify?logoColor=083344&logo=jsr&logoSize=auto&label=&labelColor=f7df1e&color=black)][jsr]
719
+ * [![CI](https://github.com/kjanat/importmapify/actions/workflows/publish.yml/badge.svg)][ci]
720
+ * [![Socket](https://badge.socket.dev/npm/package/importmapify)][socket]
721
+ *
722
+ * [ci]: https://github.com/kjanat/importmapify/actions/workflows/publish.yml
723
+ * [npm]: https://npm.im/importmapify
724
+ * [jsr]: https://jsr.io/@kjanat/importmapify
725
+ * [socket]: https://socket.dev/npm/package/importmapify
726
+ *
727
+ *
703
728
  * Expand package import patterns into explicit Deno import map entries.
704
729
  *
705
- * Use the library API to create, format, or write deterministic import maps that conform to the
706
- * {@link https://html.spec.whatwg.org/multipage/webappapis.html#import-maps | Import Maps Standard}.
730
+ * Use the library API to create, format, or write deterministic import maps that conform to the {@link https://html.spec.whatwg.org/multipage/webappapis.html#import-maps | Import Maps Standard}.
731
+ *
707
732
  * This module also runs the `importmapify` CLI when executed directly.
708
733
  *
709
734
  * @example
@@ -715,6 +740,12 @@ const generateCommand = command("generate").description("Expand package.json sub
715
740
  * console.log(importMap.imports);
716
741
  * ```
717
742
  *
743
+ * @example
744
+ * ```sh
745
+ * // Access these docs programmatically
746
+ * deno doc jsr:@kjanat/importmapify
747
+ * ```
748
+ *
718
749
  * @module importmapify
719
750
  */
720
751
  const cli$1 = cli("importmapify").manifest({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "importmapify",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Expand package.json subpath-pattern imports into explicit Deno import map entries.",
5
5
  "keywords": [
6
6
  "deno",
@@ -11,7 +11,7 @@
11
11
  "dreamcli",
12
12
  "ansispeck"
13
13
  ],
14
- "homepage": "https://github.com/kjanat/importmapify#readme",
14
+ "homepage": "https://importmapify.kjanat.dev",
15
15
  "bugs": {
16
16
  "url": "https://github.com/kjanat/importmapify/issues"
17
17
  },