importmapify 1.2.0 → 1.3.1

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
@@ -43,6 +43,7 @@ npx importmapify --root . --out import_map.json
43
43
  | `--no-config` | | Skip config file discovery | off |
44
44
  | `--check` | | Exit 1 if the output file is stale, without writing it | off |
45
45
  | `--stdout` | | Print the map instead of writing it | off |
46
+ | `--quiet` | `-q` | Suppress the `Wrote <path>` confirmation (written to stderr) | off |
46
47
 
47
48
  Add global and test-scoped dependencies from the CLI:
48
49
 
@@ -61,9 +62,21 @@ order (first match wins): `importmapify.config.{mjs,cjs,js,ts,mts,cts}`, then `.
61
62
 
62
63
  ```js
63
64
  // importmapify.config.mjs
65
+ import { defineConfig } from 'importmapify';
66
+
67
+ export default defineConfig({
68
+ packages: { dreamcli: 'jsr:@kjanat/dreamcli@^3' },
69
+ extensions: ['ts'],
70
+ });
71
+ ```
72
+
73
+ Or annotate a plain object, no import:
74
+
75
+ ```js
76
+ /** @type {import('importmapify').Config} */
64
77
  export default {
65
- packages: { dreamcli: 'jsr:@kjanat/dreamcli@^3' },
66
- extensions: ['ts'],
78
+ packages: { dreamcli: 'jsr:@kjanat/dreamcli@^3' },
79
+ extensions: ['ts'],
67
80
  };
68
81
  ```
69
82
 
@@ -72,9 +85,8 @@ Then `npx importmapify` reads it automatically. Point at a specific file with `-
72
85
 
73
86
  Explicitly-passed flags override the config, which overrides built-in defaults: `--import`/`--package`/`--scope` merge
74
87
  onto the config's records with flag keys winning; `--condition`/`--ext` replace; `--root`/`--manifest`/`--out` win when
75
- passed. Configs are imported natively; a TypeScript config needs a runtime that strips types (Bun, Deno, or Node
76
-
77
- > = 22.6), so on older Node use a `.mjs`/`.cjs`/`.js` config.
88
+ passed. Configs are imported natively; a TypeScript config needs a type-stripping runtime (Bun, Deno, or Node \>= 22.6);
89
+ on older Node use a `.mjs`/`.cjs`/`.js` config.
78
90
 
79
91
  ## Library
80
92
 
@@ -95,13 +107,13 @@ const out = writeImportMap({
95
107
  });
96
108
  ```
97
109
 
98
- | Export | Signature | Purpose |
99
- | ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- |
100
- | `defineConfig` | `(options: WriteImportMapOptions) => WriteImportMapOptions` | Identity helper that types a config object for export and reuse. |
101
- | `createImportMap` | `(options: CreateImportMapOptions) => ImportMapDocument` | Build the import map in memory. |
102
- | `formatImportMap` | `(map: ImportMapDocument) => string` | Serialize to the canonical sorted, tab-indented JSON text. |
103
- | `writeImportMap` | `(options: WriteImportMapOptions) => string` | Build, serialize, and write to disk; returns the written path. |
104
- | `packageEntries` | `(name: string, target: string) => Record<string, string>` | Build the bare and trailing-slash entry pair a package needs to resolve its subpaths. |
110
+ | Export | Signature | Purpose |
111
+ | ----------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------- |
112
+ | `defineConfig` | `(config: Config) => Config` | Identity helper that types a config object for export and reuse. |
113
+ | `createImportMap` | `(options: CreateImportMapOptions) => ImportMapDocument` | Build the import map in memory. |
114
+ | `formatImportMap` | `(map: ImportMapDocument) => string` | Serialize to the canonical sorted, tab-indented JSON text. |
115
+ | `writeImportMap` | `(options: WriteImportMapOptions) => string` | Build, serialize, and write to disk; returns the written path. |
116
+ | `packageEntries` | `(name: string, target: string) => Record<string, string>` | Build the bare and trailing-slash entry pair a package needs to resolve its subpaths. |
105
117
 
106
118
  `CreateImportMapOptions`:
107
119
 
@@ -121,6 +133,8 @@ resolved against `root` and accepts a relative path, an absolute path, or a `fil
121
133
  automatically against `out`'s directory, so a nested `out` (for example `.cache/maps/import_map.json`) still produces
122
134
  targets that resolve correctly from the map's own location.
123
135
 
136
+ `Config` is an alias for `WriteImportMapOptions` — the shape a config file's default export and `defineConfig` take.
137
+
124
138
  `defineConfig` returns its argument unchanged; it exists only to type a config object for export and reuse without a
125
139
  manual annotation.
126
140
 
@@ -398,11 +412,10 @@ import { writeImportMap } from 'importmapify';
398
412
  const root = '/path/to/source-tree';
399
413
  const importMap = writeImportMap({ root, out: 'import_map.json' });
400
414
 
401
- const documentation = execFileSync(
402
- 'deno',
403
- ['doc', '--import-map', importMap, '--json', 'src/index.ts'],
404
- { cwd: root, encoding: 'utf8' },
405
- );
415
+ const documentation = execFileSync('deno', ['doc', '--import-map', importMap, '--json', 'src/index.ts'], {
416
+ cwd: root,
417
+ encoding: 'utf8',
418
+ });
406
419
  ```
407
420
 
408
421
  ### `@deno/doc`
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.2.0",
4
+ "version": "1.3.1",
5
5
  "exports": "./src/mod.ts",
6
6
  "publish": {
7
7
  "include": [
@@ -51,6 +51,7 @@
51
51
  "lock": false,
52
52
  "jsrDepsInNodeModules": false,
53
53
  "minimumDependencyAge": {
54
+ "age": 0,
54
55
  "exclude": ["jsr:@kjanat/*", "npm:@kjanat/*"]
55
56
  }
56
57
  }
package/dist/mod.d.mts CHANGED
@@ -33,6 +33,8 @@ interface WriteImportMapOptions extends CreateImportMapOptions {
33
33
  */
34
34
  readonly out?: string | URL;
35
35
  }
36
+ /** An importmapify config: the shape a config file's default export and {@linkcode defineConfig} take. */
37
+ type Config = WriteImportMapOptions;
36
38
  /**
37
39
  * Expand a package's exact and patterned `imports` into a Deno import map.
38
40
  *
@@ -129,9 +131,9 @@ declare function packageEntries(name: string, target: string): Record<string, st
129
131
  * writeImportMap(config);
130
132
  * ```
131
133
  *
132
- * @param options Import map configuration, with an optional `out`.
133
- * @returns The same `options` value, typed as {@link WriteImportMapOptions}.
134
+ * @param config Import map configuration, with an optional `out`.
135
+ * @returns The same `config` value, typed as {@link Config}.
134
136
  */
135
- declare function defineConfig(options: WriteImportMapOptions): WriteImportMapOptions;
137
+ declare function defineConfig(config: Config): Config;
136
138
  //#endregion
137
- export { type CreateImportMapOptions, type ImportMapDocument, type WriteImportMapOptions, createImportMap, defineConfig, formatImportMap, packageEntries, writeImportMap };
139
+ export { type Config, type CreateImportMapOptions, type ImportMapDocument, type WriteImportMapOptions, createImportMap, defineConfig, formatImportMap, packageEntries, writeImportMap };
package/dist/mod.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import { bold, cyan, detectHyperlinkSupport } from "ansispeck";
2
3
  import { CLIError, cli, command, flag } from "dreamcli";
3
4
  import fs, { existsSync, readFileSync } from "node:fs";
4
5
  import path, { dirname } from "node:path";
5
- import { cwd } from "node:process";
6
+ import { argv, cwd } from "node:process";
6
7
  import { fileURLToPath, pathToFileURL } from "node:url";
7
8
  //#region src/expand.ts
8
9
  function escapeRegExp(value) {
@@ -470,14 +471,22 @@ function packageEntries(name, target) {
470
471
  * writeImportMap(config);
471
472
  * ```
472
473
  *
473
- * @param options Import map configuration, with an optional `out`.
474
- * @returns The same `options` value, typed as {@link WriteImportMapOptions}.
474
+ * @param config Import map configuration, with an optional `out`.
475
+ * @returns The same `config` value, typed as {@link Config}.
475
476
  */
476
- function defineConfig(options) {
477
- return options;
477
+ function defineConfig(config) {
478
+ return config;
478
479
  }
479
480
  //#endregion
480
481
  //#region src/cli.ts
482
+ const EXAMPLE_TOKEN = /(?:'[^']*'|"[^"]*"|\S)+/g;
483
+ const JSON_MODE = argv.includes("--json");
484
+ function highlightExample(example) {
485
+ if (JSON_MODE) return example;
486
+ const tokens = example.match(EXAMPLE_TOKEN);
487
+ if (tokens === null) return example;
488
+ return tokens.map((token, index) => index === 0 ? bold(token) : token.startsWith("-") ? cyan(token) : token).join(" ");
489
+ }
481
490
  function parseKeyValue(raw, flagName, code) {
482
491
  const eq = raw.indexOf("=");
483
492
  if (eq === -1) throw new CLIError(`--${flagName} expects key=value, got "${raw}"`, {
@@ -571,9 +580,9 @@ async function resolveGenerateOptions(flags) {
571
580
  const generateCommand = command("generate").description("Expand package.json subpath-pattern imports into a Deno import map.").flag("root", flag.path({
572
581
  mustExist: true,
573
582
  type: "directory"
574
- }).default(cwd()).describe("Project root containing the manifest.").alias("r")).flag("manifest", flag.string().default("package.json").describe("Manifest path, relative to root.").alias("m")).flag("out", flag.string().default(DEFAULT_OUT).describe("Output path resolved against root; relative, absolute, or file:// URL.").alias("o")).flag("import", flag.array(flag.string()).describe("Additional import entry as key=value. Repeatable.").alias("i")).flag("package", flag.array(flag.string()).describe("Package as name=target, expanded to a conformant bare and trailing-slash pair. Repeatable.").alias("p")).flag("ext", flag.array(flag.string()).describe("Restrict pattern matches to these file extensions. Repeatable.").alias("e")).flag("scope", flag.array(flag.string()).describe("Scoped import as prefix::key=value. Repeatable.").alias("s")).flag("condition", flag.array(flag.string()).describe("Condition to try when a target is a conditional object. Repeatable.").alias("c")).flag("config", flag.string().describe("Config file path; skips discovery.").alias("C")).flag("no-config", flag.boolean().describe("Skip config file discovery.")).flag("check", flag.boolean().describe("Exit 1 if the output file is stale instead of writing it.")).flag("stdout", flag.boolean().describe("Print the import map to stdout instead of writing it.")).example("importmapify --stdout", "Print the generated import map").example(`importmapify --package 'dreamcli=jsr:@kjanat/dreamcli@^3' --scope './tests/::dreamcli/testkit=jsr:@kjanat/dreamcli@^3/testkit'`, "Add global and test-scoped dependencies").example("importmapify --check", "Fail when the generated file is stale").action(async ({ flags, out }) => {
575
- const { log, error, setExitCode } = out;
576
- const { check, stdout } = flags;
583
+ }).default(cwd()).describe("Project root containing the manifest.").alias("r")).flag("manifest", flag.string().default("package.json").describe("Manifest path, relative to root.").alias("m")).flag("out", flag.string().default(DEFAULT_OUT).describe("Output path resolved against root; relative, absolute, or file:// URL.").alias("o")).flag("import", flag.array(flag.string()).describe("Additional import entry as key=value. Repeatable.").alias("i")).flag("package", flag.array(flag.string()).describe("Package as name=target, expanded to a conformant bare and trailing-slash pair. Repeatable.").alias("p")).flag("ext", flag.array(flag.string()).describe("Restrict pattern matches to these file extensions. Repeatable.").alias("e")).flag("scope", flag.array(flag.string()).describe("Scoped import as prefix::key=value. Repeatable.").alias("s")).flag("condition", flag.array(flag.string()).describe("Condition to try when a target is a conditional object. Repeatable.").alias("c")).flag("config", flag.string().describe("Config file path; skips discovery.").alias("C")).flag("no-config", flag.boolean().describe("Skip config file discovery.")).flag("check", flag.boolean().describe("Exit 1 if the output file is stale instead of writing it.")).flag("stdout", flag.boolean().describe("Print the import map to stdout instead of writing it.")).flag("quiet", flag.boolean().describe("Suppress the confirmation message on stderr.").alias("q")).example(highlightExample("importmapify --stdout"), "Print the generated import map").example(highlightExample(`importmapify --package 'dreamcli=jsr:@kjanat/dreamcli@^3' --scope './tests/::dreamcli/testkit=jsr:@kjanat/dreamcli@^3/testkit'`), "Add global and test-scoped dependencies").example(highlightExample("importmapify --check"), "Fail when the generated file is stale").action(async ({ flags, out }) => {
584
+ const { log, warn, error, setExitCode } = out;
585
+ const { check, stdout, quiet } = flags;
577
586
  if (check && stdout) throw new CLIError("--check and --stdout are mutually exclusive", {
578
587
  code: "conflicting-flags",
579
588
  exitCode: 2
@@ -595,10 +604,11 @@ const generateCommand = command("generate").description("Expand package.json sub
595
604
  setExitCode(1);
596
605
  return;
597
606
  }
598
- log(`${outPath} is up to date`);
607
+ if (!quiet) warn(`${outPath} is up to date`);
599
608
  return;
600
609
  }
601
- log(`Wrote ${writeImportMap(options)}`);
610
+ const written = writeImportMap(options);
611
+ if (!quiet) warn(`Wrote ${written}`);
602
612
  });
603
613
  //#endregion
604
614
  //#region src/mod.ts
@@ -623,6 +633,12 @@ const cli$1 = cli("importmapify").manifest({
623
633
  from: import.meta.url,
624
634
  files: ["package.json", "deno.json"]
625
635
  }).links().default(generateCommand).completions({ as: "flag" });
626
- if (import.meta.main) cli$1.run();
636
+ if (import.meta.main) cli$1.run({ help: {
637
+ hyperlinks: detectHyperlinkSupport(),
638
+ theme: (c) => ({
639
+ headerName: (input) => c.bold(c.underline(input)),
640
+ headerVersion: (input) => c.dim(c.underline(input))
641
+ })
642
+ } });
627
643
  //#endregion
628
644
  export { createImportMap, defineConfig, formatImportMap, packageEntries, writeImportMap };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "importmapify",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Expand package.json subpath-pattern imports into explicit Deno import map entries.",
5
5
  "keywords": [
6
6
  "deno",
@@ -65,6 +65,7 @@
65
65
  "volta:bump": "volta pin node@latest npm@11; node --version>.node-version; run bd"
66
66
  },
67
67
  "dependencies": {
68
+ "ansispeck": "^0.2.0",
68
69
  "dreamcli": "npm:@kjanat/dreamcli@^3.0.0-rc.11"
69
70
  },
70
71
  "devDependencies": {