doc-detective 4.6.0-next.6 → 4.6.0-next.8

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
@@ -37,9 +37,11 @@ Doc Detective has multiple components to integrate with your workflows as you ne
37
37
 
38
38
  ### Lazy-installed runtime
39
39
 
40
- `npm i doc-detective` installs only the CLI and a small set of light dependencies — no browser download, no heavy npm packages, no deprecation warnings from their transitive trees. Heavy runtime assets — browsers (Chrome, Firefox), drivers (ChromeDriver, Geckodriver), ffmpeg, and the npm packages that drive them (webdriverio, appium, sharp, etc.) — install lazily into `<os.tmpdir()>/doc-detective/` the first time a test needs them, or up front via `doc-detective install all`.
40
+ `npm i doc-detective` installs the CLI and then, at postinstall, pre-installs the heavy runtime assets — browsers (Chrome, Firefox), drivers (ChromeDriver, Geckodriver), ffmpeg, and the npm packages that drive them (webdriverio, appium, sharp, etc.) — into `<os.tmpdir()>/doc-detective/` (or `DOC_DETECTIVE_CACHE_DIR`). This keeps a fresh install and any Docker image built `FROM` it — ready to run without a separate step. The pre-install runs in a child process whose output is captured, so npm's deprecation warnings from the heavy transitive trees never reach your terminal.
41
41
 
42
- The published package does not declare the heavy packages in `dependencies` or `optionalDependencies`, so npm never fetches them at install time. Their version constraints live in a custom `ddRuntimeDependencies` field that the lazy resolver reads when it installs each dep into the cache on first use.
42
+ **Opt out of the heavy pre-install** by setting `DOC_DETECTIVE_AUTOINSTALL=0` (also accepts `false`/`no`/`off`). The CLI install then stays small no browser download, no heavy npm packages and the heavy assets install lazily the first time a test needs them instead, or up front via `doc-detective install all`.
43
+
44
+ Either way, the heavy packages are never declared in `dependencies` or `optionalDependencies`, so npm itself never fetches them as part of the dependency tree. Their version constraints live in a custom `ddRuntimeDependencies` field that the resolver reads when it installs each dep into the cache — whether at postinstall or on first use.
43
45
 
44
46
  - **Pre-install everything up front:**
45
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"typeKeys.d.ts","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,CAAC;AA+DpB,iBAAe,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE;;;GA6HxF"}
1
+ {"version":3,"file":"typeKeys.d.ts","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,CAAC;AAqFpB,iBAAe,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE;;;GA+IxF"}
@@ -1,66 +1,77 @@
1
1
  import { validate } from "../../common/src/validate.js";
2
- import { Key } from "webdriverio";
3
2
  import { findElementByCriteria, } from "./findStrategies.js";
3
+ import { loadHeavyDep } from "../../runtime/loader.js";
4
4
  export { typeKeys };
5
- const specialKeyMap = {
6
- $CTRL$: Key.Ctrl,
7
- $NULL$: Key.NULL,
8
- $CANCEL$: Key.Cancel,
9
- $HELP$: Key.Help,
10
- $BACKSPACE$: Key.Backspace,
11
- $TAB$: Key.Tab,
12
- $CLEAR$: Key.Clear,
13
- $RETURN$: Key.Return,
14
- $ENTER$: Key.Enter,
15
- $SHIFT$: Key.Shift,
16
- $CONTROL$: Key.Control,
17
- $ALT$: Key.Alt,
18
- $PAUSE$: Key.Pause,
19
- $ESCAPE$: Key.Escape,
20
- $SPACE$: Key.Space,
21
- $PAGE_UP$: Key.PageUp,
22
- $PAGE_DOWN$: Key.PageDown,
23
- $END$: Key.End,
24
- $HOME$: Key.Home,
25
- $ARROW_LEFT$: Key.ArrowLeft,
26
- $ARROW_UP$: Key.ArrowUp,
27
- $ARROW_RIGHT$: Key.ArrowRight,
28
- $ARROW_DOWN$: Key.ArrowDown,
29
- $INSERT$: Key.Insert,
30
- $DELETE$: Key.Delete,
31
- $SEMICOLON$: Key.Semicolon,
32
- $EQUALS$: Key.Equals,
33
- $NUMPAD_0$: Key.Numpad0,
34
- $NUMPAD_1$: Key.Numpad1,
35
- $NUMPAD_2$: Key.Numpad2,
36
- $NUMPAD_3$: Key.Numpad3,
37
- $NUMPAD_4$: Key.Numpad4,
38
- $NUMPAD_5$: Key.Numpad5,
39
- $NUMPAD_6$: Key.Numpad6,
40
- $NUMPAD_7$: Key.Numpad7,
41
- $NUMPAD_8$: Key.Numpad8,
42
- $NUMPAD_9$: Key.Numpad9,
43
- $MULTIPLY$: Key.Multiply,
44
- $ADD$: Key.Add,
45
- $SEPARATOR$: Key.Separator,
46
- $SUBSTRACT$: Key.Subtract,
47
- $DECIMAL$: Key.Decimal,
48
- $DIVIDE$: Key.Divide,
49
- $F1$: Key.F1,
50
- $F2$: Key.F2,
51
- $F3$: Key.F3,
52
- $F4$: Key.F4,
53
- $F5$: Key.F5,
54
- $F6$: Key.F6,
55
- $F7$: Key.F7,
56
- $F8$: Key.F8,
57
- $F9$: Key.F9,
58
- $F10$: Key.F10,
59
- $F11$: Key.F11,
60
- $F12$: Key.F12,
61
- $COMMAND$: Key.Command,
62
- $ZANKAKU_HANDKAKU$: Key.ZenkakuHankaku,
63
- };
5
+ let _specialKeyMap = null;
6
+ async function getSpecialKeyMap(ctx = {}) {
7
+ if (_specialKeyMap)
8
+ return _specialKeyMap;
9
+ const wdio = await loadHeavyDep("webdriverio", { ctx });
10
+ const { Key } = wdio;
11
+ _specialKeyMap = {
12
+ $CTRL$: Key.Ctrl,
13
+ $NULL$: Key.NULL,
14
+ $CANCEL$: Key.Cancel,
15
+ $HELP$: Key.Help,
16
+ $BACKSPACE$: Key.Backspace,
17
+ $TAB$: Key.Tab,
18
+ $CLEAR$: Key.Clear,
19
+ $RETURN$: Key.Return,
20
+ $ENTER$: Key.Enter,
21
+ $SHIFT$: Key.Shift,
22
+ $CONTROL$: Key.Control,
23
+ $ALT$: Key.Alt,
24
+ $PAUSE$: Key.Pause,
25
+ $ESCAPE$: Key.Escape,
26
+ $SPACE$: Key.Space,
27
+ $PAGE_UP$: Key.PageUp,
28
+ $PAGE_DOWN$: Key.PageDown,
29
+ $END$: Key.End,
30
+ $HOME$: Key.Home,
31
+ $ARROW_LEFT$: Key.ArrowLeft,
32
+ $ARROW_UP$: Key.ArrowUp,
33
+ $ARROW_RIGHT$: Key.ArrowRight,
34
+ $ARROW_DOWN$: Key.ArrowDown,
35
+ $INSERT$: Key.Insert,
36
+ $DELETE$: Key.Delete,
37
+ $SEMICOLON$: Key.Semicolon,
38
+ $EQUALS$: Key.Equals,
39
+ $NUMPAD_0$: Key.Numpad0,
40
+ $NUMPAD_1$: Key.Numpad1,
41
+ $NUMPAD_2$: Key.Numpad2,
42
+ $NUMPAD_3$: Key.Numpad3,
43
+ $NUMPAD_4$: Key.Numpad4,
44
+ $NUMPAD_5$: Key.Numpad5,
45
+ $NUMPAD_6$: Key.Numpad6,
46
+ $NUMPAD_7$: Key.Numpad7,
47
+ $NUMPAD_8$: Key.Numpad8,
48
+ $NUMPAD_9$: Key.Numpad9,
49
+ $MULTIPLY$: Key.Multiply,
50
+ $ADD$: Key.Add,
51
+ $SEPARATOR$: Key.Separator,
52
+ // `$SUBSTRACT$` is a long-standing misspelling kept for backwards
53
+ // compatibility; `$SUBTRACT$` is the correctly-spelled alias.
54
+ $SUBSTRACT$: Key.Subtract,
55
+ $SUBTRACT$: Key.Subtract,
56
+ $DECIMAL$: Key.Decimal,
57
+ $DIVIDE$: Key.Divide,
58
+ $F1$: Key.F1,
59
+ $F2$: Key.F2,
60
+ $F3$: Key.F3,
61
+ $F4$: Key.F4,
62
+ $F5$: Key.F5,
63
+ $F6$: Key.F6,
64
+ $F7$: Key.F7,
65
+ $F8$: Key.F8,
66
+ $F9$: Key.F9,
67
+ $F10$: Key.F10,
68
+ $F11$: Key.F11,
69
+ $F12$: Key.F12,
70
+ $COMMAND$: Key.Command,
71
+ $ZANKAKU_HANDKAKU$: Key.ZenkakuHankaku,
72
+ };
73
+ return _specialKeyMap;
74
+ }
64
75
  // Type a sequence of keys in the active element.
65
76
  async function typeKeys({ config, step, driver }) {
66
77
  let result = { status: "PASS", description: "Typed keys." };
@@ -148,14 +159,31 @@ async function typeKeys({ config, step, driver }) {
148
159
  step.type.keys = keys;
149
160
  }
150
161
  // Substitute special keys
151
- // 1. For each key, identify if it following the escape pattern of `$...$`.
152
- // 2. If it does, replace it with the corresponding `Key` object from `specialKeyMap`.
153
- step.type.keys = step.type.keys.map((key) => {
154
- if (key.startsWith("$") && key.endsWith("$") && specialKeyMap[key]) {
155
- return specialKeyMap[key];
162
+ // 1. For each key, identify if it follows the escape pattern of `$...$`.
163
+ // 2. If it does, replace it with the corresponding `Key` value from `specialKeyMap`.
164
+ // Only load the map (and thus webdriverio) when a sentinel token is actually
165
+ // present plain-text typing must not pull in the heavy dep or risk a
166
+ // load-time FAIL. Loading webdriverio can throw (e.g. the runtime dep isn't
167
+ // installed yet); return a step-level FAIL rather than aborting the whole run,
168
+ // matching how other heavy-dep-backed steps behave.
169
+ const hasSpecialTokens = step.type.keys.some((key) => key.startsWith("$") && key.endsWith("$"));
170
+ if (hasSpecialTokens) {
171
+ let specialKeyMap;
172
+ try {
173
+ specialKeyMap = await getSpecialKeyMap({ cacheDir: config?.cacheDir });
174
+ }
175
+ catch (error) {
176
+ result.status = "FAIL";
177
+ result.description = `Couldn't load key definitions: ${error.message}`;
178
+ return result;
156
179
  }
157
- return key;
158
- });
180
+ step.type.keys = step.type.keys.map((key) => {
181
+ if (key.startsWith("$") && key.endsWith("$") && specialKeyMap[key]) {
182
+ return specialKeyMap[key];
183
+ }
184
+ return key;
185
+ });
186
+ }
159
187
  // Run action
160
188
  try {
161
189
  if (config.recording) {
@@ -1 +1 @@
1
- {"version":3,"file":"typeKeys.js","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EACL,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,MAAM,aAAa,GAA2B;IAC5C,MAAM,EAAE,GAAG,CAAC,IAAI;IAChB,MAAM,EAAE,GAAG,CAAC,IAAI;IAChB,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,MAAM,EAAE,GAAG,CAAC,IAAI;IAChB,WAAW,EAAE,GAAG,CAAC,SAAS;IAC1B,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,OAAO,EAAE,GAAG,CAAC,KAAK;IAClB,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,OAAO,EAAE,GAAG,CAAC,KAAK;IAClB,OAAO,EAAE,GAAG,CAAC,KAAK;IAClB,SAAS,EAAE,GAAG,CAAC,OAAO;IACtB,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,OAAO,EAAE,GAAG,CAAC,KAAK;IAClB,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,OAAO,EAAE,GAAG,CAAC,KAAK;IAClB,SAAS,EAAE,GAAG,CAAC,MAAM;IACrB,WAAW,EAAE,GAAG,CAAC,QAAQ;IACzB,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,MAAM,EAAE,GAAG,CAAC,IAAI;IAChB,YAAY,EAAE,GAAG,CAAC,SAAS;IAC3B,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,aAAa,EAAE,GAAG,CAAC,UAAU;IAC7B,YAAY,EAAE,GAAG,CAAC,SAAS;IAC3B,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,WAAW,EAAE,GAAG,CAAC,SAAS;IAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,OAAO;IACvB,UAAU,EAAE,GAAG,CAAC,QAAQ;IACxB,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,WAAW,EAAE,GAAG,CAAC,SAAS;IAC1B,WAAW,EAAE,GAAG,CAAC,QAAQ;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM;IACpB,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,IAAI,EAAE,GAAG,CAAC,EAAE;IACZ,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,KAAK,EAAE,GAAG,CAAC,GAAG;IACd,SAAS,EAAE,GAAG,CAAC,OAAO;IACtB,kBAAkB,EAAE,GAAG,CAAC,cAAc;CACvC,CAAC;AAEF,iDAAiD;AACjD,KAAK,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAA2C;IACvF,IAAI,MAAM,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;IAE5D,wBAAwB;IACxB,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,4BAA4B,WAAW,CAAC,MAAM,EAAE,CAAC;QACtE,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,sCAAsC;IACtC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;IAE1B,mBAAmB;IACnB,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,oBAAoB;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,kCAAkC;IAClC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,qBAAqB;IACrB,IAAI,CAAC,IAAI,GAAG;QACV,GAAG,IAAI,CAAC,IAAI;QACZ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;QAC1B,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG;KACxC,CAAC;IAEF,0BAA0B;IAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC;QAC1B,MAAM,CAAC,WAAW,GAAG,kBAAkB,CAAC;QACxC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,GAAQ,IAAI,CAAC;IACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW;QAC3C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa;QAC9C,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB;QACpD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;IAEjD,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,qBAAqB,CAAC;YACnE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa;YACtC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,OAAO,EAAE,IAAI;YACb,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,WAAW,GAAG,KAAK,IAAI,qCAAqC,CAAC;YACpE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,YAAY,CAAC;QAEvB,qCAAqC;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,WAAW,GAAG,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC;YACnE,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,IAAI,IAAI,GAAU,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAQ,EAAE,EAAE;YAClC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,yBAAyB;gBACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,0BAA0B;IAC1B,2EAA2E;IAC3E,sFAAsF;IACtF,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE;QAC/C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,0BAA0B;YAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5B,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAC1C,CAAC,CAAC,iCAAiC;YACtC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,wBAAwB;YACxB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,0BAA0B;QAC1B,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,uBAAuB,KAAK,CAAC,OAAO,GAAG,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO;IACP,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"typeKeys.js","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EACL,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,CAAC;AAWpB,IAAI,cAAc,GAAkC,IAAI,CAAC;AAEzD,KAAK,UAAU,gBAAgB,CAC7B,MAA6B,EAAE;IAE/B,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAa,aAAa,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACpE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACrB,cAAc,GAAG;QACf,MAAM,EAAE,GAAG,CAAC,IAAI;QAChB,MAAM,EAAE,GAAG,CAAC,IAAI;QAChB,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,MAAM,EAAE,GAAG,CAAC,IAAI;QAChB,WAAW,EAAE,GAAG,CAAC,SAAS;QAC1B,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,OAAO,EAAE,GAAG,CAAC,KAAK;QAClB,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,OAAO,EAAE,GAAG,CAAC,KAAK;QAClB,OAAO,EAAE,GAAG,CAAC,KAAK;QAClB,SAAS,EAAE,GAAG,CAAC,OAAO;QACtB,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,OAAO,EAAE,GAAG,CAAC,KAAK;QAClB,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,OAAO,EAAE,GAAG,CAAC,KAAK;QAClB,SAAS,EAAE,GAAG,CAAC,MAAM;QACrB,WAAW,EAAE,GAAG,CAAC,QAAQ;QACzB,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,MAAM,EAAE,GAAG,CAAC,IAAI;QAChB,YAAY,EAAE,GAAG,CAAC,SAAS;QAC3B,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,aAAa,EAAE,GAAG,CAAC,UAAU;QAC7B,YAAY,EAAE,GAAG,CAAC,SAAS;QAC3B,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,WAAW,EAAE,GAAG,CAAC,SAAS;QAC1B,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,UAAU,EAAE,GAAG,CAAC,QAAQ;QACxB,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,WAAW,EAAE,GAAG,CAAC,SAAS;QAC1B,kEAAkE;QAClE,8DAA8D;QAC9D,WAAW,EAAE,GAAG,CAAC,QAAQ;QACzB,UAAU,EAAE,GAAG,CAAC,QAAQ;QACxB,SAAS,EAAE,GAAG,CAAC,OAAO;QACtB,QAAQ,EAAE,GAAG,CAAC,MAAM;QACpB,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,EAAE;QACZ,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,KAAK,EAAE,GAAG,CAAC,GAAG;QACd,SAAS,EAAE,GAAG,CAAC,OAAO;QACtB,kBAAkB,EAAE,GAAG,CAAC,cAAc;KACvC,CAAC;IACF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,iDAAiD;AACjD,KAAK,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAA2C;IACvF,IAAI,MAAM,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;IAE5D,wBAAwB;IACxB,MAAM,WAAW,GAAG,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,4BAA4B,WAAW,CAAC,MAAM,EAAE,CAAC;QACtE,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,sCAAsC;IACtC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;IAE1B,mBAAmB;IACnB,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,oBAAoB;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,kCAAkC;IAClC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,qBAAqB;IACrB,IAAI,CAAC,IAAI,GAAG;QACV,GAAG,IAAI,CAAC,IAAI;QACZ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;QAC1B,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG;KACxC,CAAC;IAEF,0BAA0B;IAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC;QAC1B,MAAM,CAAC,WAAW,GAAG,kBAAkB,CAAC;QACxC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,GAAQ,IAAI,CAAC;IACxB,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW;QAC3C,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa;QAC9C,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB;QACpD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;IAEjD,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,qBAAqB,CAAC;YACnE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,aAAa;YACtC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,OAAO,EAAE,IAAI;YACb,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,WAAW,GAAG,KAAK,IAAI,qCAAqC,CAAC;YACpE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,GAAG,YAAY,CAAC;QAEvB,qCAAqC;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,WAAW,GAAG,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC;YACnE,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,IAAI,IAAI,GAAU,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAQ,EAAE,EAAE;YAClC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7C,yBAAyB;gBACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC5B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,0BAA0B;IAC1B,yEAAyE;IACzE,qFAAqF;IACrF,6EAA6E;IAC7E,uEAAuE;IACvE,4EAA4E;IAC5E,+EAA+E;IAC/E,oDAAoD;IACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAC1C,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CACvD,CAAC;IACF,IAAI,gBAAgB,EAAE,CAAC;QACrB,IAAI,aAAqC,CAAC;QAC1C,IAAI,CAAC;YACH,aAAa,GAAG,MAAM,gBAAgB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,MAAM,CAAC,WAAW,GAAG,kCAAkC,KAAK,CAAC,OAAO,EAAE,CAAC;YACvE,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE;YAC/C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnE,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;IAED,aAAa;IACb,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,0BAA0B;YAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5B,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAC1C,CAAC,CAAC,iCAAiC;YACtC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,wBAAwB;YACxB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,0BAA0B;QAC1B,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,WAAW,GAAG,uBAAuB,KAAK,CAAC,OAAO,GAAG,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO;IACP,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/index.cjs CHANGED
@@ -130574,6 +130574,19 @@ var init_heavyDeps = __esm({
130574
130574
  }
130575
130575
  });
130576
130576
 
130577
+ // dist/runtime/installOutput.js
130578
+ function isNpmNoiseLine(line) {
130579
+ const l = line.trim();
130580
+ if (!l)
130581
+ return true;
130582
+ return /^npm warn deprecated/i.test(l) || /^npm notice/i.test(l) || /^npm fund/i.test(l) || /packages are looking for funding/i.test(l);
130583
+ }
130584
+ var init_installOutput = __esm({
130585
+ "dist/runtime/installOutput.js"() {
130586
+ "use strict";
130587
+ }
130588
+ });
130589
+
130577
130590
  // dist/runtime/cacheDir.js
130578
130591
  function emptyRecord() {
130579
130592
  return { npmPackages: {}, browsers: {} };
@@ -130775,7 +130788,7 @@ async function ensureRuntimeInstalled(packages, options = {}) {
130775
130788
  const specs = toInstall.map((name) => `${name}@${getDeclaredVersion(name)}`);
130776
130789
  const runtimeDir = getRuntimeDir(ctx);
130777
130790
  ensureRuntimePackageJson(runtimeDir);
130778
- logger(`Installing ${specs.length} runtime dep(s) into ${runtimeDir}: ${specs.join(", ")}`, "info");
130791
+ logger("Installing dependencies\u2026", "info");
130779
130792
  const npmExe = process.platform === "win32" ? "npm.cmd" : "npm";
130780
130793
  const args = [
130781
130794
  "install",
@@ -130788,50 +130801,104 @@ async function ensureRuntimeInstalled(packages, options = {}) {
130788
130801
  ];
130789
130802
  assertSafeRuntimePath(runtimeDir, "DOC_DETECTIVE_CACHE_DIR / config.cacheDir");
130790
130803
  await new Promise((resolve, reject) => {
130791
- const child = spawner(npmExe, args, {
130792
- cwd: runtimeDir,
130793
- env: process.env,
130794
- shell: process.platform === "win32",
130795
- stdio: ["ignore", "pipe", "pipe"]
130796
- });
130797
- const onLine = (stream, chunk) => {
130798
- const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
130799
- for (const line of text.split(/\r?\n/)) {
130800
- if (line.length > 0)
130801
- logger(`npm[${stream}]: ${line}`, "debug");
130804
+ const logPath = import_node_path4.default.join(runtimeDir, "install.log");
130805
+ let logStream = null;
130806
+ try {
130807
+ import_node_fs4.default.mkdirSync(runtimeDir, { recursive: true });
130808
+ logStream = import_node_fs4.default.createWriteStream(logPath, { flags: "w" });
130809
+ logStream.on("error", () => {
130810
+ logStream = null;
130811
+ });
130812
+ logStream.write(`# doc-detective: installing ${specs.join(", ")}
130813
+ # into ${runtimeDir}
130814
+
130815
+ `);
130816
+ } catch {
130817
+ logStream = null;
130818
+ }
130819
+ const logHint = logStream ? ` See full npm output: ${logPath}` : "";
130820
+ const child = (() => {
130821
+ const prevNoDeprecation = process.noDeprecation;
130822
+ process.noDeprecation = true;
130823
+ try {
130824
+ return spawner(npmExe, args, {
130825
+ cwd: runtimeDir,
130826
+ env: process.env,
130827
+ shell: process.platform === "win32",
130828
+ stdio: ["ignore", "pipe", "pipe"]
130829
+ });
130830
+ } finally {
130831
+ process.noDeprecation = prevNoDeprecation;
130802
130832
  }
130833
+ })();
130834
+ const emitLine = (stream, line) => {
130835
+ if (line.length === 0)
130836
+ return;
130837
+ if (!RUNTIME_DEBUG && isNpmNoiseLine(line))
130838
+ return;
130839
+ logger(`npm[${stream}]: ${line}`, "debug");
130840
+ };
130841
+ const buffers = { stdout: "", stderr: "" };
130842
+ const onChunk = (stream, chunk) => {
130843
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
130844
+ if (logStream)
130845
+ logStream.write(text);
130846
+ const parts = (buffers[stream] + text).split(/\r?\n/);
130847
+ buffers[stream] = parts.pop() ?? "";
130848
+ for (const line of parts)
130849
+ emitLine(stream, line);
130850
+ };
130851
+ const flushBuffers = () => {
130852
+ emitLine("stdout", buffers.stdout);
130853
+ emitLine("stderr", buffers.stderr);
130854
+ buffers.stdout = "";
130855
+ buffers.stderr = "";
130803
130856
  };
130804
130857
  if (child.stdout)
130805
- child.stdout.on("data", (c) => onLine("stdout", c));
130858
+ child.stdout.on("data", (c) => onChunk("stdout", c));
130806
130859
  if (child.stderr)
130807
- child.stderr.on("data", (c) => onLine("stderr", c));
130860
+ child.stderr.on("data", (c) => onChunk("stderr", c));
130808
130861
  let timer = null;
130862
+ const clearTimer = () => {
130863
+ if (timer)
130864
+ clearTimeout(timer);
130865
+ };
130866
+ let settled = false;
130867
+ const finish = (action) => {
130868
+ if (settled)
130869
+ return;
130870
+ settled = true;
130871
+ clearTimer();
130872
+ flushBuffers();
130873
+ const stream = logStream;
130874
+ logStream = null;
130875
+ if (stream) {
130876
+ let acted = false;
130877
+ const once = () => {
130878
+ if (!acted) {
130879
+ acted = true;
130880
+ action();
130881
+ }
130882
+ };
130883
+ stream.once("error", once);
130884
+ stream.end(once);
130885
+ } else {
130886
+ action();
130887
+ }
130888
+ };
130809
130889
  if (installTimeoutMs > 0) {
130810
130890
  timer = setTimeout(() => {
130811
130891
  try {
130812
130892
  child.kill();
130813
130893
  } catch {
130814
130894
  }
130815
- reject(new Error(`npm install timed out after ${installTimeoutMs}ms while installing ${specs.join(", ")} into ${runtimeDir}`));
130895
+ finish(() => reject(new Error(`npm install timed out after ${installTimeoutMs}ms while installing ${specs.join(", ")} into ${runtimeDir}.${logHint}`)));
130816
130896
  }, installTimeoutMs);
130817
130897
  if (typeof timer.unref === "function")
130818
130898
  timer.unref();
130819
130899
  }
130820
- const clearTimer = () => {
130821
- if (timer)
130822
- clearTimeout(timer);
130823
- };
130824
- child.on("error", (err) => {
130825
- clearTimer();
130826
- reject(err);
130827
- });
130828
- child.on("close", (code) => {
130829
- clearTimer();
130830
- if (code === 0)
130831
- resolve();
130832
- else
130833
- reject(new Error(`npm install exited with code ${code ?? "null"}`));
130834
- });
130900
+ child.on("error", (err) => finish(() => reject(err)));
130901
+ child.on("close", (code) => finish(() => code === 0 ? resolve() : reject(new Error(`npm install exited with code ${code ?? "null"} while installing ${specs.join(", ")}.${logHint}`))));
130835
130902
  });
130836
130903
  const record = readInstalledRecord(ctx);
130837
130904
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -130851,6 +130918,7 @@ var init_loader = __esm({
130851
130918
  import_node_url3 = require("node:url");
130852
130919
  import_node_module = require("node:module");
130853
130920
  init_heavyDeps();
130921
+ init_installOutput();
130854
130922
  init_cacheDir();
130855
130923
  RUNTIME_DEBUG = process.env.DOC_DETECTIVE_RUNTIME_DEBUG === "1";
130856
130924
  defaultLogger = (msg, level = "info") => {
@@ -135402,66 +135470,77 @@ async function findElementByCriteria({ selector, elementText, elementId, element
135402
135470
 
135403
135471
  // dist/core/tests/typeKeys.js
135404
135472
  init_validate();
135405
- var import_webdriverio = require("webdriverio");
135406
- var specialKeyMap = {
135407
- $CTRL$: import_webdriverio.Key.Ctrl,
135408
- $NULL$: import_webdriverio.Key.NULL,
135409
- $CANCEL$: import_webdriverio.Key.Cancel,
135410
- $HELP$: import_webdriverio.Key.Help,
135411
- $BACKSPACE$: import_webdriverio.Key.Backspace,
135412
- $TAB$: import_webdriverio.Key.Tab,
135413
- $CLEAR$: import_webdriverio.Key.Clear,
135414
- $RETURN$: import_webdriverio.Key.Return,
135415
- $ENTER$: import_webdriverio.Key.Enter,
135416
- $SHIFT$: import_webdriverio.Key.Shift,
135417
- $CONTROL$: import_webdriverio.Key.Control,
135418
- $ALT$: import_webdriverio.Key.Alt,
135419
- $PAUSE$: import_webdriverio.Key.Pause,
135420
- $ESCAPE$: import_webdriverio.Key.Escape,
135421
- $SPACE$: import_webdriverio.Key.Space,
135422
- $PAGE_UP$: import_webdriverio.Key.PageUp,
135423
- $PAGE_DOWN$: import_webdriverio.Key.PageDown,
135424
- $END$: import_webdriverio.Key.End,
135425
- $HOME$: import_webdriverio.Key.Home,
135426
- $ARROW_LEFT$: import_webdriverio.Key.ArrowLeft,
135427
- $ARROW_UP$: import_webdriverio.Key.ArrowUp,
135428
- $ARROW_RIGHT$: import_webdriverio.Key.ArrowRight,
135429
- $ARROW_DOWN$: import_webdriverio.Key.ArrowDown,
135430
- $INSERT$: import_webdriverio.Key.Insert,
135431
- $DELETE$: import_webdriverio.Key.Delete,
135432
- $SEMICOLON$: import_webdriverio.Key.Semicolon,
135433
- $EQUALS$: import_webdriverio.Key.Equals,
135434
- $NUMPAD_0$: import_webdriverio.Key.Numpad0,
135435
- $NUMPAD_1$: import_webdriverio.Key.Numpad1,
135436
- $NUMPAD_2$: import_webdriverio.Key.Numpad2,
135437
- $NUMPAD_3$: import_webdriverio.Key.Numpad3,
135438
- $NUMPAD_4$: import_webdriverio.Key.Numpad4,
135439
- $NUMPAD_5$: import_webdriverio.Key.Numpad5,
135440
- $NUMPAD_6$: import_webdriverio.Key.Numpad6,
135441
- $NUMPAD_7$: import_webdriverio.Key.Numpad7,
135442
- $NUMPAD_8$: import_webdriverio.Key.Numpad8,
135443
- $NUMPAD_9$: import_webdriverio.Key.Numpad9,
135444
- $MULTIPLY$: import_webdriverio.Key.Multiply,
135445
- $ADD$: import_webdriverio.Key.Add,
135446
- $SEPARATOR$: import_webdriverio.Key.Separator,
135447
- $SUBSTRACT$: import_webdriverio.Key.Subtract,
135448
- $DECIMAL$: import_webdriverio.Key.Decimal,
135449
- $DIVIDE$: import_webdriverio.Key.Divide,
135450
- $F1$: import_webdriverio.Key.F1,
135451
- $F2$: import_webdriverio.Key.F2,
135452
- $F3$: import_webdriverio.Key.F3,
135453
- $F4$: import_webdriverio.Key.F4,
135454
- $F5$: import_webdriverio.Key.F5,
135455
- $F6$: import_webdriverio.Key.F6,
135456
- $F7$: import_webdriverio.Key.F7,
135457
- $F8$: import_webdriverio.Key.F8,
135458
- $F9$: import_webdriverio.Key.F9,
135459
- $F10$: import_webdriverio.Key.F10,
135460
- $F11$: import_webdriverio.Key.F11,
135461
- $F12$: import_webdriverio.Key.F12,
135462
- $COMMAND$: import_webdriverio.Key.Command,
135463
- $ZANKAKU_HANDKAKU$: import_webdriverio.Key.ZenkakuHankaku
135464
- };
135473
+ init_loader();
135474
+ var _specialKeyMap = null;
135475
+ async function getSpecialKeyMap(ctx = {}) {
135476
+ if (_specialKeyMap)
135477
+ return _specialKeyMap;
135478
+ const wdio = await loadHeavyDep("webdriverio", { ctx });
135479
+ const { Key } = wdio;
135480
+ _specialKeyMap = {
135481
+ $CTRL$: Key.Ctrl,
135482
+ $NULL$: Key.NULL,
135483
+ $CANCEL$: Key.Cancel,
135484
+ $HELP$: Key.Help,
135485
+ $BACKSPACE$: Key.Backspace,
135486
+ $TAB$: Key.Tab,
135487
+ $CLEAR$: Key.Clear,
135488
+ $RETURN$: Key.Return,
135489
+ $ENTER$: Key.Enter,
135490
+ $SHIFT$: Key.Shift,
135491
+ $CONTROL$: Key.Control,
135492
+ $ALT$: Key.Alt,
135493
+ $PAUSE$: Key.Pause,
135494
+ $ESCAPE$: Key.Escape,
135495
+ $SPACE$: Key.Space,
135496
+ $PAGE_UP$: Key.PageUp,
135497
+ $PAGE_DOWN$: Key.PageDown,
135498
+ $END$: Key.End,
135499
+ $HOME$: Key.Home,
135500
+ $ARROW_LEFT$: Key.ArrowLeft,
135501
+ $ARROW_UP$: Key.ArrowUp,
135502
+ $ARROW_RIGHT$: Key.ArrowRight,
135503
+ $ARROW_DOWN$: Key.ArrowDown,
135504
+ $INSERT$: Key.Insert,
135505
+ $DELETE$: Key.Delete,
135506
+ $SEMICOLON$: Key.Semicolon,
135507
+ $EQUALS$: Key.Equals,
135508
+ $NUMPAD_0$: Key.Numpad0,
135509
+ $NUMPAD_1$: Key.Numpad1,
135510
+ $NUMPAD_2$: Key.Numpad2,
135511
+ $NUMPAD_3$: Key.Numpad3,
135512
+ $NUMPAD_4$: Key.Numpad4,
135513
+ $NUMPAD_5$: Key.Numpad5,
135514
+ $NUMPAD_6$: Key.Numpad6,
135515
+ $NUMPAD_7$: Key.Numpad7,
135516
+ $NUMPAD_8$: Key.Numpad8,
135517
+ $NUMPAD_9$: Key.Numpad9,
135518
+ $MULTIPLY$: Key.Multiply,
135519
+ $ADD$: Key.Add,
135520
+ $SEPARATOR$: Key.Separator,
135521
+ // `$SUBSTRACT$` is a long-standing misspelling kept for backwards
135522
+ // compatibility; `$SUBTRACT$` is the correctly-spelled alias.
135523
+ $SUBSTRACT$: Key.Subtract,
135524
+ $SUBTRACT$: Key.Subtract,
135525
+ $DECIMAL$: Key.Decimal,
135526
+ $DIVIDE$: Key.Divide,
135527
+ $F1$: Key.F1,
135528
+ $F2$: Key.F2,
135529
+ $F3$: Key.F3,
135530
+ $F4$: Key.F4,
135531
+ $F5$: Key.F5,
135532
+ $F6$: Key.F6,
135533
+ $F7$: Key.F7,
135534
+ $F8$: Key.F8,
135535
+ $F9$: Key.F9,
135536
+ $F10$: Key.F10,
135537
+ $F11$: Key.F11,
135538
+ $F12$: Key.F12,
135539
+ $COMMAND$: Key.Command,
135540
+ $ZANKAKU_HANDKAKU$: Key.ZenkakuHankaku
135541
+ };
135542
+ return _specialKeyMap;
135543
+ }
135465
135544
  async function typeKeys({ config, step, driver }) {
135466
135545
  let result = { status: "PASS", description: "Typed keys." };
135467
135546
  const isValidStep = validate({ schemaKey: "step_v3", object: step });
@@ -135530,12 +135609,23 @@ async function typeKeys({ config, step, driver }) {
135530
135609
  });
135531
135610
  step.type.keys = keys;
135532
135611
  }
135533
- step.type.keys = step.type.keys.map((key) => {
135534
- if (key.startsWith("$") && key.endsWith("$") && specialKeyMap[key]) {
135535
- return specialKeyMap[key];
135612
+ const hasSpecialTokens = step.type.keys.some((key) => key.startsWith("$") && key.endsWith("$"));
135613
+ if (hasSpecialTokens) {
135614
+ let specialKeyMap;
135615
+ try {
135616
+ specialKeyMap = await getSpecialKeyMap({ cacheDir: config?.cacheDir });
135617
+ } catch (error) {
135618
+ result.status = "FAIL";
135619
+ result.description = `Couldn't load key definitions: ${error.message}`;
135620
+ return result;
135536
135621
  }
135537
- return key;
135538
- });
135622
+ step.type.keys = step.type.keys.map((key) => {
135623
+ if (key.startsWith("$") && key.endsWith("$") && specialKeyMap[key]) {
135624
+ return specialKeyMap[key];
135625
+ }
135626
+ return key;
135627
+ });
135628
+ }
135539
135629
  try {
135540
135630
  if (config.recording) {
135541
135631
  for (let i = 0; i < step.type.keys.length; i++) {
@@ -0,0 +1,3 @@
1
+ /** True for npm deprecation / funding / notice noise (and blank lines). */
2
+ export declare function isNpmNoiseLine(line: string): boolean;
3
+ //# sourceMappingURL=installOutput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installOutput.d.ts","sourceRoot":"","sources":["../../src/runtime/installOutput.ts"],"names":[],"mappings":"AAYA,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASpD"}
@@ -0,0 +1,22 @@
1
+ // Shared classifier for npm's noisy, non-actionable output. Deprecation,
2
+ // funding, and notice lines (e.g. `npm warn deprecated glob@10.5.0: …`,
3
+ // `npm warn deprecated whatwg-encoding@3.1.1: …`) are about transitive
4
+ // dependencies the user can't change, and they alarm users out of context.
5
+ // We drop them from all user-facing install output — `install all`,
6
+ // lazy-install on first use, and the postinstall pre-warm — so a noisy
7
+ // transitive tree never produces scary terminal output.
8
+ //
9
+ // NOTE: scripts/postinstall.js keeps a parallel copy of this predicate because
10
+ // it is a plain Node script that runs before/without the compiled `dist/`. Keep
11
+ // the two in sync.
12
+ /** True for npm deprecation / funding / notice noise (and blank lines). */
13
+ export function isNpmNoiseLine(line) {
14
+ const l = line.trim();
15
+ if (!l)
16
+ return true;
17
+ return (/^npm warn deprecated/i.test(l) ||
18
+ /^npm notice/i.test(l) ||
19
+ /^npm fund/i.test(l) ||
20
+ /packages are looking for funding/i.test(l));
21
+ }
22
+ //# sourceMappingURL=installOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installOutput.js","sourceRoot":"","sources":["../../src/runtime/installOutput.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,uEAAuE;AACvE,2EAA2E;AAC3E,oEAAoE;AACpE,uEAAuE;AACvE,wDAAwD;AACxD,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,mBAAmB;AAEnB,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,CACL,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/B,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACtB,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QACpB,mCAAmC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC5C,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/runtime/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAI9F,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;AAe7D,MAAM,MAAM,OAAO,GAAG,CACpB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,YAAY,KAClB,YAAY,CAAC;AAElB,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,eAAoB,GACxB,MAAM,GAAG,IAAI,CAEf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED,MAAM,WAAW,6BAA6B;IAC5C,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAuCD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAwIf"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/runtime/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK9F,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC;AAe7D,MAAM,MAAM,OAAO,GAAG,CACpB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,YAAY,KAClB,YAAY,CAAC;AAElB,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,eAAoB,GACxB,MAAM,GAAG,IAAI,CAEf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED,MAAM,WAAW,6BAA6B;IAC5C,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAuCD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAmOf"}
@@ -4,6 +4,7 @@ import { spawn as nodeSpawn } from "node:child_process";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { createRequire } from "node:module";
6
6
  import { getDeclaredVersion, satisfiesRange, withPeerCompanions } from "./heavyDeps.js";
7
+ import { isNpmNoiseLine } from "./installOutput.js";
7
8
  import { assertSafeRuntimePath, getRuntimeDir, readInstalledRecord, writeInstalledRecord, } from "./cacheDir.js";
8
9
  // The default logger gates `debug` output OFF so call sites that omit a
9
10
  // logger (the JIT pre-flight, the CLI startup self-update check) don't
@@ -164,7 +165,11 @@ export async function ensureRuntimeInstalled(packages, options = {}) {
164
165
  const specs = toInstall.map((name) => `${name}@${getDeclaredVersion(name)}`);
165
166
  const runtimeDir = getRuntimeDir(ctx);
166
167
  ensureRuntimePackageJson(runtimeDir);
167
- logger(`Installing ${specs.length} runtime dep(s) into ${runtimeDir}: ${specs.join(", ")}`, "info");
168
+ // Keep the announcement calm no dependency list or count. The resolved
169
+ // versions are reported once the install completes (the install command's
170
+ // per-asset report; the lazy path stays quiet on success). The full spec list
171
+ // still goes to the install.log for diagnostics.
172
+ logger("Installing dependencies…", "info");
168
173
  const npmExe = process.platform === "win32" ? "npm.cmd" : "npm";
169
174
  const args = [
170
175
  "install",
@@ -184,27 +189,118 @@ export async function ensureRuntimeInstalled(packages, options = {}) {
184
189
  // without a shell.
185
190
  assertSafeRuntimePath(runtimeDir, "DOC_DETECTIVE_CACHE_DIR / config.cacheDir");
186
191
  await new Promise((resolve, reject) => {
187
- const child = spawner(npmExe, args, {
188
- cwd: runtimeDir,
189
- env: process.env,
190
- shell: process.platform === "win32",
191
- stdio: ["ignore", "pipe", "pipe"],
192
- });
193
- const onLine = (stream, chunk) => {
194
- const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
195
- for (const line of text.split(/\r?\n/)) {
196
- if (line.length > 0)
197
- logger(`npm[${stream}]: ${line}`, "debug");
192
+ // Tee the full, RAW npm output (deprecation noise included) to a log file so
193
+ // a non-zero exit is debuggable. The terminal only shows filtered output, so
194
+ // without this the failure reason is lost. Best-effort — logging must never
195
+ // break the install.
196
+ const logPath = path.join(runtimeDir, "install.log");
197
+ let logStream = null;
198
+ try {
199
+ fs.mkdirSync(runtimeDir, { recursive: true });
200
+ logStream = fs.createWriteStream(logPath, { flags: "w" });
201
+ // A write/flush error (disk full, EIO, permissions) must never crash the
202
+ // install via an unhandled 'error' event. Swallow it and stop logging.
203
+ logStream.on("error", () => {
204
+ logStream = null;
205
+ });
206
+ // Header so the log is self-contained for diagnostics, even though the
207
+ // terminal no longer lists the deps.
208
+ logStream.write(`# doc-detective: installing ${specs.join(", ")}\n# into ${runtimeDir}\n\n`);
209
+ }
210
+ catch {
211
+ logStream = null;
212
+ }
213
+ const logHint = logStream ? ` See full npm output: ${logPath}` : "";
214
+ // DEP0190: spawning npm.cmd on Windows needs shell:true, and passing args
215
+ // with shell:true emits a deprecation warning. We keep the CodeQL-safe args
216
+ // array (runtimeDir is validated above), so just suppress that one warning
217
+ // around the synchronous spawn() call — emitWarning() reads
218
+ // process.noDeprecation synchronously.
219
+ const child = (() => {
220
+ const prevNoDeprecation = process.noDeprecation;
221
+ process.noDeprecation = true;
222
+ try {
223
+ return spawner(npmExe, args, {
224
+ cwd: runtimeDir,
225
+ env: process.env,
226
+ shell: process.platform === "win32",
227
+ stdio: ["ignore", "pipe", "pipe"],
228
+ });
229
+ }
230
+ finally {
231
+ process.noDeprecation = prevNoDeprecation;
198
232
  }
233
+ })();
234
+ const emitLine = (stream, line) => {
235
+ if (line.length === 0)
236
+ return;
237
+ // Drop npm's deprecation/funding/notice noise (about transitive deps
238
+ // the user can't fix) so even `--verbose` install output stays calm.
239
+ // DOC_DETECTIVE_RUNTIME_DEBUG=1 shows everything raw for diagnostics.
240
+ if (!RUNTIME_DEBUG && isNpmNoiseLine(line))
241
+ return;
242
+ logger(`npm[${stream}]: ${line}`, "debug");
243
+ };
244
+ // Buffer each stream so a line split across `data` chunks is reassembled
245
+ // before isNpmNoiseLine classifies it — otherwise a fragmented
246
+ // `npm warn deprecated …` line could slip past the filter.
247
+ const buffers = { stdout: "", stderr: "" };
248
+ const onChunk = (stream, chunk) => {
249
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
250
+ if (logStream)
251
+ logStream.write(text); // full raw output → log file
252
+ const parts = (buffers[stream] + text).split(/\r?\n/);
253
+ buffers[stream] = parts.pop() ?? ""; // trailing partial line
254
+ for (const line of parts)
255
+ emitLine(stream, line);
256
+ };
257
+ const flushBuffers = () => {
258
+ emitLine("stdout", buffers.stdout);
259
+ emitLine("stderr", buffers.stderr);
260
+ buffers.stdout = "";
261
+ buffers.stderr = "";
199
262
  };
200
263
  if (child.stdout)
201
- child.stdout.on("data", (c) => onLine("stdout", c));
264
+ child.stdout.on("data", (c) => onChunk("stdout", c));
202
265
  if (child.stderr)
203
- child.stderr.on("data", (c) => onLine("stderr", c));
266
+ child.stderr.on("data", (c) => onChunk("stderr", c));
204
267
  // Wall-clock cap so a stalled npm never freezes the first run. 0 opts
205
268
  // out (callers that explicitly want to wait forever, or unit tests
206
269
  // with a synchronously-resolving fake spawner).
207
270
  let timer = null;
271
+ const clearTimer = () => {
272
+ if (timer)
273
+ clearTimeout(timer);
274
+ };
275
+ // Settle exactly once, flushing the log stream first so the file is fully
276
+ // written before the error propagates and the process may exit. end()'s
277
+ // callback only fires on 'finish'; pair it with a one-shot 'error' guard so
278
+ // a stream error (disk full mid-flush) still settles the promise instead of
279
+ // hanging the install.
280
+ let settled = false;
281
+ const finish = (action) => {
282
+ if (settled)
283
+ return;
284
+ settled = true;
285
+ clearTimer();
286
+ flushBuffers();
287
+ const stream = logStream;
288
+ logStream = null;
289
+ if (stream) {
290
+ let acted = false;
291
+ const once = () => {
292
+ if (!acted) {
293
+ acted = true;
294
+ action();
295
+ }
296
+ };
297
+ stream.once("error", once);
298
+ stream.end(once);
299
+ }
300
+ else {
301
+ action();
302
+ }
303
+ };
208
304
  if (installTimeoutMs > 0) {
209
305
  timer = setTimeout(() => {
210
306
  try {
@@ -213,27 +309,18 @@ export async function ensureRuntimeInstalled(packages, options = {}) {
213
309
  catch {
214
310
  // best-effort — the child may already have exited
215
311
  }
216
- reject(new Error(`npm install timed out after ${installTimeoutMs}ms while installing ${specs.join(", ")} into ${runtimeDir}`));
312
+ finish(() => reject(new Error(`npm install timed out after ${installTimeoutMs}ms while installing ${specs.join(", ")} into ${runtimeDir}.${logHint}`)));
217
313
  }, installTimeoutMs);
218
314
  // Don't keep the event loop alive solely for this timer.
219
315
  if (typeof timer.unref === "function")
220
316
  timer.unref();
221
317
  }
222
- const clearTimer = () => {
223
- if (timer)
224
- clearTimeout(timer);
225
- };
226
- child.on("error", (err) => {
227
- clearTimer();
228
- reject(err);
229
- });
230
- child.on("close", (code) => {
231
- clearTimer();
232
- if (code === 0)
233
- resolve();
234
- else
235
- reject(new Error(`npm install exited with code ${code ?? "null"}`));
236
- });
318
+ // Spawn failure (ENOENT/EINVAL): the OS error is self-descriptive and the
319
+ // log holds no npm output for this path, so we don't append logHint.
320
+ child.on("error", (err) => finish(() => reject(err)));
321
+ child.on("close", (code) => finish(() => code === 0
322
+ ? resolve()
323
+ : reject(new Error(`npm install exited with code ${code ?? "null"} while installing ${specs.join(", ")}.${logHint}`))));
237
324
  });
238
325
  const record = readInstalledRecord(ctx);
239
326
  const now = new Date().toISOString();
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/runtime/loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/runtime/loader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc-detective",
3
- "version": "4.6.0-next.6",
3
+ "version": "4.6.0-next.8",
4
4
  "description": "Treat doc content as testable assertions to validate doc accuracy and product UX.",
5
5
  "bin": {
6
6
  "doc-detective": "bin/doc-detective.js",
@@ -1,21 +1,157 @@
1
+ import fs from "node:fs";
1
2
  import path from "node:path";
2
3
  import { spawn } from "node:child_process";
3
4
  import { fileURLToPath, pathToFileURL } from "node:url";
4
5
 
5
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
7
 
7
- // Browsers, ffmpeg, geckodriver, and the heavy npm packages are no longer
8
- // downloaded at `npm install` time. The shim now lazy-installs them on
9
- // first use into <cacheDir>/ (default <os.tmpdir()>/doc-detective/), or
10
- // up-front via `doc-detective install all`. This postinstall script
11
- // keeps only the optional agent-tools install prompt — it's lightweight
12
- // (TTY-gated, time-bounded, skipped in CI) and unrelated to the runtime.
8
+ // Resolved path to the compiled CLI, shared by both install steps below.
9
+ const CLI_PATH = path.join(__dirname, "..", "bin", "doc-detective.js");
13
10
 
11
+ // Two steps run at `npm install` time:
12
+ // 1. maybeInstallRuntime(): eagerly install the heavy runtime assets
13
+ // (webdriverio/appium/sharp + browsers) via `doc-detective install all`,
14
+ // so a fresh install — and any Docker image built `FROM` it — is ready to
15
+ // run without a separate install step. On by default; opt out with
16
+ // DOC_DETECTIVE_AUTOINSTALL=0.
17
+ // 2. maybePromptInstallAgents(): the optional agent-tools install prompt —
18
+ // lightweight (TTY-gated, time-bounded, skipped in CI).
14
19
  async function main() {
20
+ await maybeInstallRuntime();
15
21
  await maybePromptInstallAgents();
16
22
  }
17
23
 
18
- main();
24
+ // Only run the install steps when executed as the npm lifecycle script, not
25
+ // when a test imports this module for the exported pure helpers below.
26
+ function isInvokedDirectly() {
27
+ try {
28
+ if (!process.argv[1]) return false;
29
+ return (
30
+ fs.realpathSync(process.argv[1]) ===
31
+ fs.realpathSync(fileURLToPath(import.meta.url))
32
+ );
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+ // Swallow any unexpected rejection: a postinstall script must always exit 0,
38
+ // otherwise it fails the user's `npm install`.
39
+ if (isInvokedDirectly()) main().catch(() => {});
40
+
41
+ // --- Runtime + browsers auto-install ----------------------------------------
42
+
43
+ /**
44
+ * True when the user has opted out of the postinstall heavy install via
45
+ * DOC_DETECTIVE_AUTOINSTALL (0/false/no/off, case-insensitive). Default
46
+ * (unset or any other value) installs. Exported for tests.
47
+ */
48
+ export function isRuntimeInstallOptedOut(env = process.env) {
49
+ const v = String(env.DOC_DETECTIVE_AUTOINSTALL ?? "").trim().toLowerCase();
50
+ return v === "0" || v === "false" || v === "no" || v === "off";
51
+ }
52
+
53
+ /**
54
+ * A line we surface to the user: the installer's own clean progress output
55
+ * (`Installing runtime…`, ` [npm] webdriverio — installed`, …). Everything
56
+ * else from the child — npm deprecation/funding noise, blank lines — is
57
+ * suppressed on the success path. Exported for tests.
58
+ */
59
+ export function isProgressLine(line) {
60
+ return /^\s*Installing\b/.test(line) || /^\s*\[(npm|browser)\]/.test(line);
61
+ }
62
+
63
+ /**
64
+ * Pure npm noise (deprecation/funding/notice). Dropped from the captured
65
+ * buffer when surfacing a failure tail so the dump stays readable — genuine
66
+ * warnings/errors (e.g. EBADENGINE) are kept. Exported for tests.
67
+ *
68
+ * Kept in sync with src/runtime/installOutput.ts#isNpmNoiseLine (this is a
69
+ * plain Node script that can't import the compiled TS module reliably).
70
+ */
71
+ export function isNpmNoiseLine(line) {
72
+ const l = line.trim();
73
+ if (!l) return true;
74
+ return (
75
+ /^npm warn deprecated/i.test(l) ||
76
+ /^npm notice/i.test(l) ||
77
+ /^npm fund/i.test(l) ||
78
+ /packages are looking for funding/i.test(l)
79
+ );
80
+ }
81
+
82
+ // Install the heavy runtime assets in a CHILD PROCESS whose stdout/stderr we
83
+ // capture (pipe) rather than inherit, so npm's deprecated-transitive-dependency
84
+ // warnings (glob, whatwg-encoding, …) never reach the user's terminal. We
85
+ // forward only the installer's own progress lines; on failure we surface a
86
+ // curated tail. This never fails the npm install — the assets also lazy-install
87
+ // on first use, so a failure here just forfeits the pre-warm.
88
+ async function maybeInstallRuntime() {
89
+ if (isRuntimeInstallOptedOut()) return;
90
+
91
+ const distDir = path.join(__dirname, "..", "dist");
92
+ // Dev checkout / partial install without a build: the CLI can't run yet.
93
+ // Skip silently — postinstall must never fail.
94
+ if (!fs.existsSync(CLI_PATH) || !fs.existsSync(distDir)) return;
95
+
96
+ console.log(
97
+ "doc-detective: installing runtime + browsers " +
98
+ "(set DOC_DETECTIVE_AUTOINSTALL=0 to skip)…"
99
+ );
100
+
101
+ const captured = [];
102
+ const handleLine = (raw, forward) => {
103
+ if (!raw.trim()) return;
104
+ captured.push(raw);
105
+ if (forward && isProgressLine(raw)) console.log(" " + raw.trim());
106
+ };
107
+ // Buffer per stream so a line split across data chunks is reassembled before
108
+ // the allow-list filter sees it. Returns the new buffer remainder.
109
+ const consume = (buf, chunk, forward) => {
110
+ const parts = (buf + chunk.toString()).split(/\r?\n/);
111
+ const remainder = parts.pop(); // trailing partial line (no newline yet)
112
+ for (const line of parts) handleLine(line, forward);
113
+ return remainder;
114
+ };
115
+
116
+ const { code, signal, errored } = await new Promise((resolve) => {
117
+ let child;
118
+ try {
119
+ child = spawn(
120
+ process.execPath,
121
+ [CLI_PATH, "install", "all", "--yes"],
122
+ { stdio: ["ignore", "pipe", "pipe"], env: process.env }
123
+ );
124
+ } catch {
125
+ resolve({ code: 1, signal: null, errored: true });
126
+ return;
127
+ }
128
+ let outBuf = "";
129
+ let errBuf = "";
130
+ child.stdout?.on("data", (chunk) => (outBuf = consume(outBuf, chunk, true)));
131
+ // stderr is captured for a possible failure dump but never forwarded live.
132
+ child.stderr?.on("data", (chunk) => (errBuf = consume(errBuf, chunk, false)));
133
+ child.on("close", (exitCode, exitSignal) => {
134
+ // Flush any trailing partial lines left without a final newline.
135
+ handleLine(outBuf, true);
136
+ handleLine(errBuf, false);
137
+ resolve({ code: exitCode, signal: exitSignal, errored: false });
138
+ });
139
+ child.on("error", () => resolve({ code: 1, signal: null, errored: true }));
140
+ });
141
+
142
+ if (!errored && !signal && code === 0) {
143
+ console.log("doc-detective: runtime + browsers ready.");
144
+ return;
145
+ }
146
+
147
+ const tail = captured.filter((l) => !isNpmNoiseLine(l)).slice(-20);
148
+ console.error(
149
+ "doc-detective: runtime install did not complete " +
150
+ (signal ? `(signal ${signal})` : `(exit ${code})`) +
151
+ ". Assets will install on first use, or run `doc-detective install all`."
152
+ );
153
+ if (tail.length) console.error(tail.map((l) => " " + l).join("\n"));
154
+ }
19
155
 
20
156
  async function maybePromptInstallAgents() {
21
157
  // Don't prompt in non-interactive contexts. npm sets many of these during
@@ -187,7 +323,6 @@ async function maybePromptInstallAgents() {
187
323
 
188
324
  // Pre-fill --agent so the CLI doesn't re-prompt for the picker. Scope stays
189
325
  // interactive on purpose — project vs global is a per-user decision.
190
- const cliPath = path.join(__dirname, "..", "bin", "doc-detective.js");
191
326
  const cliArgs = ["install-agents"];
192
327
  for (const a of adaptersNeedingInstall) {
193
328
  cliArgs.push("--agent", a.id);
@@ -197,7 +332,7 @@ async function maybePromptInstallAgents() {
197
332
  // `node_modules/.bin` during the install step either.
198
333
  const childEnv = { ...process.env, [pathKey]: sanitizedPath };
199
334
  const { code, signal } = await new Promise((resolve) => {
200
- const child = spawn(process.execPath, [cliPath, ...cliArgs], {
335
+ const child = spawn(process.execPath, [CLI_PATH, ...cliArgs], {
201
336
  stdio: "inherit",
202
337
  cwd: targetCwd,
203
338
  env: childEnv,