@c9up/ream 0.2.25 → 0.2.27

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.
Files changed (178) hide show
  1. package/README.md +2 -0
  2. package/dist/Codemods.d.ts +12 -0
  3. package/dist/Codemods.d.ts.map +1 -1
  4. package/dist/Codemods.js +114 -23
  5. package/dist/Codemods.js.map +1 -1
  6. package/dist/HttpKernel.d.ts +5 -1
  7. package/dist/HttpKernel.d.ts.map +1 -1
  8. package/dist/HttpKernel.js +6 -6
  9. package/dist/HttpKernel.js.map +1 -1
  10. package/dist/Ignitor.d.ts.map +1 -1
  11. package/dist/Ignitor.js +87 -14
  12. package/dist/Ignitor.js.map +1 -1
  13. package/dist/console/Kernel.d.ts.map +1 -1
  14. package/dist/console/Kernel.js +20 -1
  15. package/dist/console/Kernel.js.map +1 -1
  16. package/dist/console/cliui.d.ts +9 -245
  17. package/dist/console/cliui.d.ts.map +1 -1
  18. package/dist/console/cliui.js +9 -583
  19. package/dist/console/cliui.js.map +1 -1
  20. package/dist/console/make/commands.d.ts +19 -0
  21. package/dist/console/make/commands.d.ts.map +1 -0
  22. package/dist/console/make/commands.js +252 -0
  23. package/dist/console/make/commands.js.map +1 -0
  24. package/dist/console/make/eject.d.ts +28 -0
  25. package/dist/console/make/eject.d.ts.map +1 -0
  26. package/dist/console/make/eject.js +161 -0
  27. package/dist/console/make/eject.js.map +1 -0
  28. package/dist/console/make/flush.d.ts +51 -0
  29. package/dist/console/make/flush.d.ts.map +1 -0
  30. package/dist/console/make/flush.js +93 -0
  31. package/dist/console/make/flush.js.map +1 -0
  32. package/dist/console/make/generators.d.ts +36 -0
  33. package/dist/console/make/generators.d.ts.map +1 -0
  34. package/dist/console/make/generators.js +148 -0
  35. package/dist/console/make/generators.js.map +1 -0
  36. package/dist/console/make/naming.d.ts +32 -0
  37. package/dist/console/make/naming.d.ts.map +1 -0
  38. package/dist/console/make/naming.js +82 -0
  39. package/dist/console/make/naming.js.map +1 -0
  40. package/dist/console/make/resolve.d.ts +46 -0
  41. package/dist/console/make/resolve.d.ts.map +1 -0
  42. package/dist/console/make/resolve.js +113 -0
  43. package/dist/console/make/resolve.js.map +1 -0
  44. package/dist/console/prompts.d.ts.map +1 -1
  45. package/dist/console/prompts.js +34 -46
  46. package/dist/console/prompts.js.map +1 -1
  47. package/dist/console/selection.d.ts +54 -0
  48. package/dist/console/selection.d.ts.map +1 -0
  49. package/dist/console/selection.js +235 -0
  50. package/dist/console/selection.js.map +1 -0
  51. package/dist/console/ui.d.ts +9 -15
  52. package/dist/console/ui.d.ts.map +1 -1
  53. package/dist/console/ui.js +11 -24
  54. package/dist/console/ui.js.map +1 -1
  55. package/dist/dev/fullReload.d.ts +35 -10
  56. package/dist/dev/fullReload.d.ts.map +1 -1
  57. package/dist/dev/fullReload.js +55 -14
  58. package/dist/dev/fullReload.js.map +1 -1
  59. package/dist/dev/hotWatcher.d.ts +19 -3
  60. package/dist/dev/hotWatcher.d.ts.map +1 -1
  61. package/dist/dev/hotWatcher.js +168 -18
  62. package/dist/dev/hotWatcher.js.map +1 -1
  63. package/dist/dev/readyBanner.d.ts +45 -0
  64. package/dist/dev/readyBanner.d.ts.map +1 -0
  65. package/dist/dev/readyBanner.js +72 -0
  66. package/dist/dev/readyBanner.js.map +1 -0
  67. package/dist/dev/shortcuts.d.ts +41 -0
  68. package/dist/dev/shortcuts.d.ts.map +1 -0
  69. package/dist/dev/shortcuts.js +142 -0
  70. package/dist/dev/shortcuts.js.map +1 -0
  71. package/dist/errors/prettyPrintError.d.ts.map +1 -1
  72. package/dist/errors/prettyPrintError.js +5 -8
  73. package/dist/errors/prettyPrintError.js.map +1 -1
  74. package/dist/errors/renderError.d.ts +46 -0
  75. package/dist/errors/renderError.d.ts.map +1 -0
  76. package/dist/errors/renderError.js +197 -0
  77. package/dist/errors/renderError.js.map +1 -0
  78. package/dist/hot.js +12 -2
  79. package/dist/hot.js.map +1 -1
  80. package/dist/index.d.ts +4 -3
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +5 -2
  83. package/dist/index.js.map +1 -1
  84. package/dist/profiler/MemoryProfileStore.d.ts +23 -0
  85. package/dist/profiler/MemoryProfileStore.d.ts.map +1 -0
  86. package/dist/profiler/MemoryProfileStore.js +70 -0
  87. package/dist/profiler/MemoryProfileStore.js.map +1 -0
  88. package/dist/profiler/Profiler.d.ts +56 -0
  89. package/dist/profiler/Profiler.d.ts.map +1 -0
  90. package/dist/profiler/Profiler.js +162 -0
  91. package/dist/profiler/Profiler.js.map +1 -0
  92. package/dist/profiler/collectors.d.ts +105 -0
  93. package/dist/profiler/collectors.d.ts.map +1 -0
  94. package/dist/profiler/collectors.js +164 -0
  95. package/dist/profiler/collectors.js.map +1 -0
  96. package/dist/profiler/endpoint.d.ts +27 -0
  97. package/dist/profiler/endpoint.d.ts.map +1 -0
  98. package/dist/profiler/endpoint.js +79 -0
  99. package/dist/profiler/endpoint.js.map +1 -0
  100. package/dist/profiler/index.d.ts +26 -0
  101. package/dist/profiler/index.d.ts.map +1 -0
  102. package/dist/profiler/index.js +41 -0
  103. package/dist/profiler/index.js.map +1 -0
  104. package/dist/profiler/middleware.d.ts +17 -0
  105. package/dist/profiler/middleware.d.ts.map +1 -0
  106. package/dist/profiler/middleware.js +79 -0
  107. package/dist/profiler/middleware.js.map +1 -0
  108. package/dist/profiler/render.d.ts +23 -0
  109. package/dist/profiler/render.d.ts.map +1 -0
  110. package/dist/profiler/render.js +141 -0
  111. package/dist/profiler/render.js.map +1 -0
  112. package/dist/profiler/toolbar.d.ts +34 -0
  113. package/dist/profiler/toolbar.d.ts.map +1 -0
  114. package/dist/profiler/toolbar.js +104 -0
  115. package/dist/profiler/toolbar.js.map +1 -0
  116. package/dist/profiler/types.d.ts +70 -0
  117. package/dist/profiler/types.d.ts.map +1 -0
  118. package/dist/profiler/types.js +11 -0
  119. package/dist/profiler/types.js.map +1 -0
  120. package/dist/router/Router.d.ts +11 -0
  121. package/dist/router/Router.d.ts.map +1 -1
  122. package/dist/router/Router.js +16 -0
  123. package/dist/router/Router.js.map +1 -1
  124. package/dist/stubs/index.d.ts +11 -0
  125. package/dist/stubs/index.d.ts.map +1 -0
  126. package/dist/stubs/index.js +12 -0
  127. package/dist/stubs/index.js.map +1 -0
  128. package/dist/stubs/template.d.ts +63 -0
  129. package/dist/stubs/template.d.ts.map +1 -0
  130. package/dist/stubs/template.js +209 -0
  131. package/dist/stubs/template.js.map +1 -0
  132. package/events.win32-x64-msvc.node +0 -0
  133. package/index.win32-x64-msvc.node +0 -0
  134. package/package.json +7 -1
  135. package/scheduler.win32-x64-msvc.node +0 -0
  136. package/src/Codemods.ts +153 -29
  137. package/src/HttpKernel.ts +12 -8
  138. package/src/Ignitor.ts +95 -14
  139. package/src/console/Kernel.ts +21 -1
  140. package/src/console/cliui.ts +44 -754
  141. package/src/console/make/commands.ts +270 -0
  142. package/src/console/make/eject.ts +163 -0
  143. package/src/console/make/flush.ts +125 -0
  144. package/src/console/make/generators.ts +176 -0
  145. package/src/console/make/naming.ts +85 -0
  146. package/src/console/make/resolve.ts +134 -0
  147. package/src/console/prompts.ts +45 -64
  148. package/src/console/selection.ts +274 -0
  149. package/src/console/ui.ts +12 -24
  150. package/src/dev/fullReload.ts +57 -15
  151. package/src/dev/hotWatcher.ts +165 -21
  152. package/src/dev/readyBanner.ts +84 -0
  153. package/src/dev/shortcuts.ts +158 -0
  154. package/src/errors/prettyPrintError.ts +5 -5
  155. package/src/errors/renderError.ts +230 -0
  156. package/src/hot.ts +12 -2
  157. package/src/index.ts +23 -3
  158. package/src/profiler/MemoryProfileStore.ts +75 -0
  159. package/src/profiler/Profiler.ts +182 -0
  160. package/src/profiler/collectors.ts +230 -0
  161. package/src/profiler/endpoint.ts +98 -0
  162. package/src/profiler/index.ts +56 -0
  163. package/src/profiler/middleware.ts +83 -0
  164. package/src/profiler/render.ts +173 -0
  165. package/src/profiler/toolbar.ts +106 -0
  166. package/src/profiler/types.ts +75 -0
  167. package/src/router/Router.ts +16 -0
  168. package/src/stubs/index.ts +14 -0
  169. package/src/stubs/template.ts +262 -0
  170. package/stubs/make/command.stub +29 -0
  171. package/stubs/make/controller.stub +30 -0
  172. package/stubs/make/entity.stub +11 -0
  173. package/stubs/make/event.stub +13 -0
  174. package/stubs/make/listener.stub +13 -0
  175. package/stubs/make/middleware.stub +16 -0
  176. package/stubs/make/provider.stub +26 -0
  177. package/stubs/make/service.stub +27 -0
  178. package/stubs/make/validator.stub +10 -0
@@ -1,9 +1,23 @@
1
1
  /**
2
2
  * Watching the project for the changes a hot reload reacts to.
3
3
  *
4
- * `fs.watch` with `recursive: true`, which Node implements on Linux, macOS and
5
- * Windows alike — the reason a watcher used to be a dependency here, and is not
6
- * any more.
4
+ * ONE `fs.watch` PER DIRECTORY, walked ourselves — not `recursive: true`, and
5
+ * never a watch on a file. That is not a preference, it is the bug this module
6
+ * was reported for: most editors save by writing a temporary file and renaming
7
+ * it over the original (JetBrains IDEs, several formatters, anything using
8
+ * write-and-replace for crash safety). The rename gives the path a NEW inode,
9
+ * and a watcher holding the old one is watching something that no longer has a
10
+ * name. Measured on Node 25, Linux:
11
+ *
12
+ * fs.watch(dir, { recursive: true }) first rename fires, then silence
13
+ * fs.watch(file) first rename fires, then silence
14
+ * fs.watch(dir) every rename fires
15
+ *
16
+ * So the first save hot-swapped and every one after it was ignored without a
17
+ * word — no reload, no restart, nothing in the log. A directory keeps its inode
18
+ * when a file inside it is replaced, which is why watching directories is the
19
+ * form that survives. A file to watch is watched through its parent instead,
20
+ * filtered by name.
7
21
  *
8
22
  * Two behaviours are worth stating because they are not obvious from the API:
9
23
  *
@@ -26,6 +40,8 @@ export interface WatcherOptions {
26
40
  files: readonly string[];
27
41
  /** Called once per settled change, with an absolute path. */
28
42
  onChange: (file: string) => void;
43
+ /** Told when a directory could not be watched for a reason worth knowing. */
44
+ onWarning?: (message: string) => void;
29
45
  }
30
46
  export interface Watcher {
31
47
  close: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"hotWatcher.d.ts","sourceRoot":"","sources":["../../src/dev/hotWatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,0FAA0F;IAC1F,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CA+C7D"}
1
+ {"version":3,"file":"hotWatcher.d.ts","sourceRoot":"","sources":["../../src/dev/hotWatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AA6BH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,0FAA0F;IAC1F,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAuI7D"}
@@ -1,9 +1,23 @@
1
1
  /**
2
2
  * Watching the project for the changes a hot reload reacts to.
3
3
  *
4
- * `fs.watch` with `recursive: true`, which Node implements on Linux, macOS and
5
- * Windows alike — the reason a watcher used to be a dependency here, and is not
6
- * any more.
4
+ * ONE `fs.watch` PER DIRECTORY, walked ourselves — not `recursive: true`, and
5
+ * never a watch on a file. That is not a preference, it is the bug this module
6
+ * was reported for: most editors save by writing a temporary file and renaming
7
+ * it over the original (JetBrains IDEs, several formatters, anything using
8
+ * write-and-replace for crash safety). The rename gives the path a NEW inode,
9
+ * and a watcher holding the old one is watching something that no longer has a
10
+ * name. Measured on Node 25, Linux:
11
+ *
12
+ * fs.watch(dir, { recursive: true }) first rename fires, then silence
13
+ * fs.watch(file) first rename fires, then silence
14
+ * fs.watch(dir) every rename fires
15
+ *
16
+ * So the first save hot-swapped and every one after it was ignored without a
17
+ * word — no reload, no restart, nothing in the log. A directory keeps its inode
18
+ * when a file inside it is replaced, which is why watching directories is the
19
+ * form that survives. A file to watch is watched through its parent instead,
20
+ * filtered by name.
7
21
  *
8
22
  * Two behaviours are worth stating because they are not obvious from the API:
9
23
  *
@@ -17,13 +31,33 @@
17
31
  * syntax error has nothing left to notice the fix. The outer one covers exactly
18
32
  * that window, and hands back over by restarting the process.
19
33
  */
20
- import { watch } from 'node:fs';
21
- import { join, resolve } from 'node:path';
34
+ import { readdirSync, realpathSync, statSync, watch } from 'node:fs';
35
+ import { basename, dirname, join, resolve } from 'node:path';
22
36
  /** How long to wait for a save to finish arriving before acting on it. */
23
37
  const SETTLE_MS = 40;
38
+ /** Never walked: none of it is application source, and some of it is enormous. */
39
+ const SKIP_DIRECTORIES = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.wolf']);
40
+ /**
41
+ * The half-written files an atomic save leaves behind for a few milliseconds.
42
+ *
43
+ * Reported, they would be a change to `Controller.ts.tmp8f3` — a file the graph
44
+ * has never heard of, on its way to being renamed into the one that matters.
45
+ */
46
+ function isEditorArtefact(name) {
47
+ return (name.endsWith('~') ||
48
+ name.endsWith('.swp') ||
49
+ name.endsWith('.swx') ||
50
+ name.startsWith('.#') ||
51
+ name.startsWith('.goutputstream') ||
52
+ /\.tmp[\w-]*$/.test(name) ||
53
+ /^\.?[\w.-]+\.(?:tmp|temp|crswap|part|partial)$/i.test(name));
54
+ }
24
55
  export function watchProject(options) {
25
- const watchers = [];
56
+ const watchers = new Map();
26
57
  const pending = new Map();
58
+ /** Real paths already walked, so a symlink loop cannot spin forever. */
59
+ const visited = new Set();
60
+ let closed = false;
27
61
  const report = (file) => {
28
62
  const existing = pending.get(file);
29
63
  if (existing !== undefined)
@@ -36,37 +70,153 @@ export function watchProject(options) {
36
70
  timer.unref?.();
37
71
  pending.set(file, timer);
38
72
  };
39
- for (const directory of options.directories) {
40
- const absolute = resolve(options.root, directory);
73
+ const warn = (message) => options.onWarning?.(message);
74
+ /**
75
+ * Watch one directory, then everything under it.
76
+ *
77
+ * Called again for a directory that appears later: a `mkdir app/billing`
78
+ * during a session must be watched, and the parent's event is what says so.
79
+ *
80
+ * `announce` closes the gap between that mkdir and the watch being in place.
81
+ * `mkdir -p app/billing && cp Controller.ts app/billing/` writes the file
82
+ * before the watcher on the new directory exists, so what is already inside a
83
+ * directory discovered mid-session is reported as a change. At startup it is
84
+ * false, or booting would report every file in the project.
85
+ */
86
+ const watchDirectory = (absolute, announce = false) => {
87
+ if (closed || watchers.has(absolute))
88
+ return;
89
+ let real;
90
+ try {
91
+ real = realpathSync(absolute);
92
+ if (!statSync(real).isDirectory())
93
+ return;
94
+ }
95
+ catch (error) {
96
+ // Absent is ordinary — the list is the framework's conventional layout,
97
+ // not a requirement, and a directory can be removed mid-session. Any
98
+ // other reason (no permission, too many open files) is worth saying, or
99
+ // the project silently stops hot-reloading.
100
+ if (!isMissing(error))
101
+ warn(`cannot watch ${absolute}: ${describe(error)}`);
102
+ return;
103
+ }
104
+ if (visited.has(real))
105
+ return;
106
+ visited.add(real);
41
107
  try {
42
- watchers.push(watch(absolute, { recursive: true }, (_event, name) => {
108
+ const watcher = watch(absolute, (_event, name) => {
43
109
  if (typeof name !== 'string' || name === '')
44
110
  return;
45
- report(join(absolute, name));
46
- }));
111
+ const child = join(absolute, name);
112
+ // A new directory has to be picked up, or nothing in it is ever seen.
113
+ // Cheap: only for names that are directories right now.
114
+ if (!SKIP_DIRECTORIES.has(name) && isDirectory(child))
115
+ watchDirectory(child, true);
116
+ if (isEditorArtefact(name))
117
+ return;
118
+ report(child);
119
+ });
120
+ watcher.on('error', (error) => {
121
+ // A watcher whose directory was removed is done; anything else is a
122
+ // surprise the developer should hear about rather than lose.
123
+ watchers.delete(absolute);
124
+ if (!isMissing(error))
125
+ warn(`watch on ${absolute} failed: ${describe(error)}`);
126
+ });
127
+ watchers.set(absolute, watcher);
128
+ }
129
+ catch (error) {
130
+ if (!isMissing(error))
131
+ warn(`cannot watch ${absolute}: ${describe(error)}`);
132
+ return;
47
133
  }
48
- catch {
49
- // A directory this project does not have is not an error: the list is
50
- // the framework's conventional layout, not a requirement.
134
+ let entries = [];
135
+ try {
136
+ entries = readdirSync(absolute);
137
+ }
138
+ catch (error) {
139
+ if (!isMissing(error))
140
+ warn(`cannot read ${absolute}: ${describe(error)}`);
141
+ return;
142
+ }
143
+ for (const entry of entries) {
144
+ if (SKIP_DIRECTORIES.has(entry))
145
+ continue;
146
+ const child = join(absolute, entry);
147
+ if (isDirectory(child)) {
148
+ watchDirectory(child, announce);
149
+ continue;
150
+ }
151
+ if (announce && !isEditorArtefact(entry))
152
+ report(child);
51
153
  }
154
+ };
155
+ for (const directory of options.directories) {
156
+ watchDirectory(resolve(options.root, directory));
52
157
  }
158
+ // A file is watched through its parent directory, for the reason at the top
159
+ // of this module: `fs.watch` on the file itself holds an inode, and an atomic
160
+ // save replaces it. `.env` is saved by the same editors as everything else.
161
+ const watchedFiles = new Map();
53
162
  for (const file of options.files) {
54
163
  const absolute = resolve(options.root, file);
164
+ const parent = dirname(absolute);
165
+ const names = watchedFiles.get(parent) ?? new Set();
166
+ names.add(basename(absolute));
167
+ watchedFiles.set(parent, names);
168
+ }
169
+ for (const [parent, names] of watchedFiles) {
170
+ // The parent may already be covered as a watched directory — `.env` sits at
171
+ // the root, which is not in the list, but a caller is free to pass both.
172
+ if (watchers.has(parent))
173
+ continue;
55
174
  try {
56
- watchers.push(watch(absolute, () => report(absolute)));
175
+ const watcher = watch(parent, (_event, name) => {
176
+ if (typeof name !== 'string' || !names.has(name))
177
+ return;
178
+ report(join(parent, name));
179
+ });
180
+ watcher.on('error', (error) => {
181
+ watchers.delete(parent);
182
+ if (!isMissing(error))
183
+ warn(`watch on ${parent} failed: ${describe(error)}`);
184
+ });
185
+ watchers.set(parent, watcher);
57
186
  }
58
- catch {
59
- // Same: a `.env` that does not exist is simply not watched.
187
+ catch (error) {
188
+ if (!isMissing(error))
189
+ warn(`cannot watch ${parent}: ${describe(error)}`);
60
190
  }
61
191
  }
62
192
  return {
63
193
  close: () => {
194
+ closed = true;
64
195
  for (const timer of pending.values())
65
196
  clearTimeout(timer);
66
197
  pending.clear();
67
- for (const watcher of watchers)
198
+ for (const watcher of watchers.values())
68
199
  watcher.close();
200
+ watchers.clear();
69
201
  },
70
202
  };
71
203
  }
204
+ function isDirectory(path) {
205
+ try {
206
+ return statSync(path).isDirectory();
207
+ }
208
+ catch {
209
+ return false;
210
+ }
211
+ }
212
+ /** ENOENT and friends: the path is simply not there, which is not a failure. */
213
+ function isMissing(error) {
214
+ const code = error.code;
215
+ return code === 'ENOENT' || code === 'ENOTDIR';
216
+ }
217
+ function describe(error) {
218
+ if (error instanceof Error)
219
+ return error.message;
220
+ return String(error);
221
+ }
72
222
  //# sourceMappingURL=hotWatcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hotWatcher.js","sourceRoot":"","sources":["../../src/dev/hotWatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAkB,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC,0EAA0E;AAC1E,MAAM,SAAS,GAAG,EAAE,CAAA;AAiBpB,MAAM,UAAU,YAAY,CAAC,OAAuB;IAClD,MAAM,QAAQ,GAAgB,EAAE,CAAA;IAChC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAA;IAEjD,MAAM,MAAM,GAAG,CAAC,IAAY,EAAQ,EAAE;QACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,QAAQ,KAAK,SAAS;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;QAClD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC,EAAE,SAAS,CAAC,CAAA;QACb,sEAAsE;QACtE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAA;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC1B,CAAC,CAAA;IAED,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACjD,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CACX,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;gBACpD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE;oBAAE,OAAM;gBACnD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;YAC9B,CAAC,CAAC,CACH,CAAA;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sEAAsE;YACtE,0DAA0D;QAC5D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;QAC9D,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,GAAG,EAAE;YACV,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;YACzD,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,OAAO,CAAC,KAAK,EAAE,CAAA;QACjD,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"hotWatcher.js","sourceRoot":"","sources":["../../src/dev/hotWatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * What the dev server says once it is listening.
3
+ *
4
+ * Upstream prints a sticker the moment the child reports ready: the address,
5
+ * the mode, how long the boot took. Read off `@adonisjs/assembler`'s build:
6
+ *
7
+ * this.ui.sticker()
8
+ * .add(`Server address: ${colors.cyan(serverUrl)}`)
9
+ * .add(`Mode: ${colors.cyan(this.mode)}`)
10
+ * .add(`Ready in: ${colors.cyan(prettyHrtime(message.duration))}`)
11
+ *
12
+ * Ours says the same, `Press h to show help` included — the shortcuts are in
13
+ * `./shortcuts.ts`, so the line is an offer this process keeps.
14
+ *
15
+ * Printed from the application rather than from the `ream dev` parent, which
16
+ * is where upstream prints it. The parent is a Rust process here and the port
17
+ * is not its to know: a dev server that found 3000 taken binds 3001, and only
18
+ * the process that bound it can say so. Upstream solves the same problem by
19
+ * having the child send the port over IPC — the address it prints is the
20
+ * child's either way.
21
+ */
22
+ /** Whether `ream dev` is what started this process. */
23
+ export declare function inDevServer(): boolean;
24
+ export interface ReadyBanner {
25
+ /** The host the server bound, as the Ignitor resolved it. */
26
+ host: string;
27
+ port: number;
28
+ /** `HMR` when the loader is swapping modules, `watch` when it only restarts. */
29
+ mode: string;
30
+ /** Milliseconds from process start to listening. */
31
+ bootMs?: number;
32
+ }
33
+ /**
34
+ * The address to show for a bound host and port.
35
+ *
36
+ * `localhost` rather than `0.0.0.0`: bound to every interface is not a link
37
+ * that opens, and printing it sends you looking in the wrong place. Shared
38
+ * with the `o` shortcut so the browser goes where the sticker said.
39
+ */
40
+ export declare function devServerUrl(host: string, port: number): string;
41
+ /** The lines of the sticker, so a test can read them without a terminal. */
42
+ export declare function readyBannerLines(banner: ReadyBanner): string[];
43
+ /** Print it, the way upstream prints its sticker. */
44
+ export declare function printReadyBanner(banner: ReadyBanner): void;
45
+ //# sourceMappingURL=readyBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readyBanner.d.ts","sourceRoot":"","sources":["../../src/dev/readyBanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,uDAAuD;AACvD,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,MAAM,WAAW,WAAW;IAC1B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAY9D;AAED,qDAAqD;AACrD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAK1D"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * What the dev server says once it is listening.
3
+ *
4
+ * Upstream prints a sticker the moment the child reports ready: the address,
5
+ * the mode, how long the boot took. Read off `@adonisjs/assembler`'s build:
6
+ *
7
+ * this.ui.sticker()
8
+ * .add(`Server address: ${colors.cyan(serverUrl)}`)
9
+ * .add(`Mode: ${colors.cyan(this.mode)}`)
10
+ * .add(`Ready in: ${colors.cyan(prettyHrtime(message.duration))}`)
11
+ *
12
+ * Ours says the same, `Press h to show help` included — the shortcuts are in
13
+ * `./shortcuts.ts`, so the line is an offer this process keeps.
14
+ *
15
+ * Printed from the application rather than from the `ream dev` parent, which
16
+ * is where upstream prints it. The parent is a Rust process here and the port
17
+ * is not its to know: a dev server that found 3000 taken binds 3001, and only
18
+ * the process that bound it can say so. Upstream solves the same problem by
19
+ * having the child send the port over IPC — the address it prints is the
20
+ * child's either way.
21
+ */
22
+ import { lumen } from '@c9up/lumen';
23
+ /** Whether `ream dev` is what started this process. */
24
+ export function inDevServer() {
25
+ return process.env.REAM_DEV === 'true';
26
+ }
27
+ /**
28
+ * The address to show for a bound host and port.
29
+ *
30
+ * `localhost` rather than `0.0.0.0`: bound to every interface is not a link
31
+ * that opens, and printing it sends you looking in the wrong place. Shared
32
+ * with the `o` shortcut so the browser goes where the sticker said.
33
+ */
34
+ export function devServerUrl(host, port) {
35
+ const shown = host === '0.0.0.0' || host === '::' ? 'localhost' : host;
36
+ return `http://${shown}:${port}`;
37
+ }
38
+ /** The lines of the sticker, so a test can read them without a terminal. */
39
+ export function readyBannerLines(banner) {
40
+ const ui = lumen();
41
+ const lines = [
42
+ `Server address: ${ui.colors.cyan(devServerUrl(banner.host, banner.port))}`,
43
+ `Mode: ${ui.colors.cyan(banner.mode)}`,
44
+ ];
45
+ if (banner.bootMs !== undefined) {
46
+ lines.push(`Ready in: ${ui.colors.cyan(formatBootTime(banner.bootMs))}`);
47
+ }
48
+ // Only where there is a keyboard: piped into a file, the offer is a lie.
49
+ if (process.stdin.isTTY)
50
+ lines.push(`Press ${ui.colors.dim('h')} to show help`);
51
+ return lines;
52
+ }
53
+ /** Print it, the way upstream prints its sticker. */
54
+ export function printReadyBanner(banner) {
55
+ const ui = lumen();
56
+ const sticker = ui.sticker();
57
+ for (const line of readyBannerLines(banner))
58
+ sticker.add(line);
59
+ sticker.render();
60
+ }
61
+ /**
62
+ * `412 ms`, `1.2 s` — upstream runs the duration through `pretty-hrtime`.
63
+ *
64
+ * Not that dependency: this prints one number once per boot, and the package
65
+ * is 60 lines of unit selection for a case we have exactly one of.
66
+ */
67
+ function formatBootTime(ms) {
68
+ if (ms < 1000)
69
+ return `${Math.round(ms)} ms`;
70
+ return `${(ms / 1000).toFixed(1)} s`;
71
+ }
72
+ //# sourceMappingURL=readyBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readyBanner.js","sourceRoot":"","sources":["../../src/dev/readyBanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC,uDAAuD;AACvD,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAA;AACxC,CAAC;AAYD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,IAAY;IACrD,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA;IACtE,OAAO,UAAU,KAAK,IAAI,IAAI,EAAE,CAAA;AAClC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,MAAmB;IAClD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,KAAK,GAAG;QACZ,mBAAmB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE;QAC3E,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;KACvC,CAAA;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAA;IAC1E,CAAC;IACD,yEAAyE;IACzE,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAC/E,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,gBAAgB,CAAC,MAAmB;IAClD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAA;IAC5B,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC9D,OAAO,CAAC,MAAM,EAAE,CAAA;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAA;IAC5C,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;AACtC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The keys the dev server answers to.
3
+ *
4
+ * Upstream's set, read off `@adonisjs/assembler`'s build: `r` restarts, `c`
5
+ * clears, `o` opens the browser, `h` shows the list, and Ctrl-C or Ctrl-D
6
+ * quits. Same keys, same order, same words.
7
+ *
8
+ * Owned by the application rather than by the `ream dev` parent, which is
9
+ * where upstream owns it — the same split as the ready sticker, and for the
10
+ * same reason: `o` needs the address, and a port found by scanning past a
11
+ * taken 3000 is known only to the process that bound it. Everything else
12
+ * follows from there, because this process already has what each key needs:
13
+ * exiting on the restart code is what makes the parent start it again, and
14
+ * the graceful shutdown is already wired to a signal.
15
+ *
16
+ * NO dependency for opening a browser. Upstream imports `open`; this spawns
17
+ * the platform's opener, which is the one thing that package does on the three
18
+ * platforms a dev server runs on.
19
+ */
20
+ /** The exit code the `ream dev` parent restarts on. */
21
+ export declare const RESTART_EXIT_CODE = 75;
22
+ export interface ShortcutsOptions {
23
+ /** Where the server is listening, for `o`. */
24
+ url?: string;
25
+ /** Leave the process the way a restart leaves it. Defaults to exiting. */
26
+ onRestart?: () => void;
27
+ /** End the session. Defaults to exiting through the normal shutdown. */
28
+ onQuit?: () => void;
29
+ }
30
+ /** The lines `h` prints, so a test can read them without a terminal. */
31
+ export declare function helpLines(): string[];
32
+ /** What to do with one keypress. Exported so the mapping is testable. */
33
+ export declare function handleKey(key: string, options?: ShortcutsOptions): boolean;
34
+ /**
35
+ * Listen for keys. Answers a function that stops listening.
36
+ *
37
+ * A no-op when stdin is not a terminal — `ream dev` piped into a file has no
38
+ * keyboard, and raw mode on a pipe throws.
39
+ */
40
+ export declare function installShortcuts(options?: ShortcutsOptions): () => void;
41
+ //# sourceMappingURL=shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../../src/dev/shortcuts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAQnC,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wEAAwE;AACxE,wBAAgB,SAAS,IAAI,MAAM,EAAE,CAEpC;AAiDD,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAY9E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,IAAI,CAiB3E"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * The keys the dev server answers to.
3
+ *
4
+ * Upstream's set, read off `@adonisjs/assembler`'s build: `r` restarts, `c`
5
+ * clears, `o` opens the browser, `h` shows the list, and Ctrl-C or Ctrl-D
6
+ * quits. Same keys, same order, same words.
7
+ *
8
+ * Owned by the application rather than by the `ream dev` parent, which is
9
+ * where upstream owns it — the same split as the ready sticker, and for the
10
+ * same reason: `o` needs the address, and a port found by scanning past a
11
+ * taken 3000 is known only to the process that bound it. Everything else
12
+ * follows from there, because this process already has what each key needs:
13
+ * exiting on the restart code is what makes the parent start it again, and
14
+ * the graceful shutdown is already wired to a signal.
15
+ *
16
+ * NO dependency for opening a browser. Upstream imports `open`; this spawns
17
+ * the platform's opener, which is the one thing that package does on the three
18
+ * platforms a dev server runs on.
19
+ */
20
+ import { spawn } from 'node:child_process';
21
+ import { lumen } from '@c9up/lumen';
22
+ import { clearScreen } from './fullReload.js';
23
+ /** The exit code the `ream dev` parent restarts on. */
24
+ export const RESTART_EXIT_CODE = 75;
25
+ /** The lines `h` prints, so a test can read them without a terminal. */
26
+ export function helpLines() {
27
+ return ['Available shortcuts:', ...shortcutsFor({}).map((s) => `· ${s.key}: ${s.description}`)];
28
+ }
29
+ function shortcutsFor(options) {
30
+ const ui = lumen();
31
+ return [
32
+ {
33
+ key: 'r',
34
+ description: 'restart server',
35
+ handler: () => {
36
+ ui.logger.log('');
37
+ ui.logger.info('Manual restart triggered...');
38
+ // Exiting on the restart code IS the restart: the parent loops on it,
39
+ // which is the same path a change outside the boundaries takes.
40
+ if (options.onRestart)
41
+ options.onRestart();
42
+ else
43
+ process.exit(RESTART_EXIT_CODE);
44
+ },
45
+ },
46
+ {
47
+ key: 'c',
48
+ description: 'clear console',
49
+ handler: () => {
50
+ clearScreen();
51
+ ui.logger.info('Console cleared');
52
+ },
53
+ },
54
+ {
55
+ key: 'o',
56
+ description: 'open in browser',
57
+ handler: () => {
58
+ if (options.url === undefined) {
59
+ ui.logger.warning('No server address to open');
60
+ return;
61
+ }
62
+ ui.logger.log('');
63
+ ui.logger.info(`Opening ${options.url}...`);
64
+ openBrowser(options.url);
65
+ },
66
+ },
67
+ {
68
+ key: 'h',
69
+ description: 'show this help',
70
+ handler: () => {
71
+ ui.logger.log('');
72
+ for (const line of helpLines())
73
+ ui.logger.log(line);
74
+ },
75
+ },
76
+ ];
77
+ }
78
+ /** What to do with one keypress. Exported so the mapping is testable. */
79
+ export function handleKey(key, options = {}) {
80
+ // \u0003 is Ctrl-C and \u0004 is Ctrl-D. Raw mode means no signal is raised
81
+ // for either, so the process would sit there unkillable without this.
82
+ if (key === '\u0003' || key === '\u0004') {
83
+ if (options.onQuit)
84
+ options.onQuit();
85
+ else
86
+ process.kill(process.pid, 'SIGINT');
87
+ return true;
88
+ }
89
+ const shortcut = shortcutsFor(options).find((entry) => entry.key === key);
90
+ if (shortcut === undefined)
91
+ return false;
92
+ shortcut.handler();
93
+ return true;
94
+ }
95
+ /**
96
+ * Listen for keys. Answers a function that stops listening.
97
+ *
98
+ * A no-op when stdin is not a terminal — `ream dev` piped into a file has no
99
+ * keyboard, and raw mode on a pipe throws.
100
+ */
101
+ export function installShortcuts(options = {}) {
102
+ if (!process.stdin.isTTY)
103
+ return () => { };
104
+ const onData = (data) => {
105
+ handleKey(data.toString(), options);
106
+ };
107
+ process.stdin.setRawMode(true);
108
+ process.stdin.on('data', onData);
109
+ // Nothing should stay alive for a keyboard: a server that finished its work
110
+ // must be able to exit with a listener still attached.
111
+ process.stdin.unref();
112
+ return () => {
113
+ process.stdin.setRawMode(false);
114
+ process.stdin.removeListener('data', onData);
115
+ process.stdin.pause();
116
+ };
117
+ }
118
+ /**
119
+ * Hand the URL to whatever opens links here.
120
+ *
121
+ * Detached and ignored: an opener that writes to stderr, or outlives the dev
122
+ * server, must not take the terminal or the exit with it.
123
+ */
124
+ function openBrowser(url) {
125
+ const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
126
+ try {
127
+ const child = spawn(command, [url], {
128
+ detached: true,
129
+ stdio: 'ignore',
130
+ shell: process.platform === 'win32',
131
+ });
132
+ child.unref();
133
+ child.on('error', () => {
134
+ // No opener on this machine — a headless container, say. The address was
135
+ // printed a moment ago; losing the click is not worth a crash.
136
+ });
137
+ }
138
+ catch {
139
+ // Same.
140
+ }
141
+ }
142
+ //# sourceMappingURL=shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.js","sourceRoot":"","sources":["../../src/dev/shortcuts.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"prettyPrintError.d.ts","sourceRoot":"","sources":["../../src/errors/prettyPrintError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CASrD"}
1
+ {"version":3,"file":"prettyPrintError.d.ts","sourceRoot":"","sources":["../../src/errors/prettyPrintError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAQrD"}
@@ -6,17 +6,14 @@
6
6
  * that would make the two import each other.
7
7
  */
8
8
  import { ReamError } from './ReamError.js';
9
+ import { renderError } from './renderError.js';
9
10
  export function prettyPrintError(error) {
11
+ // A framework error already says what it is, what it was doing and what to
12
+ // try — printing a source excerpt under it would bury that.
10
13
  if (error instanceof ReamError) {
11
14
  console.error(error.toDevString());
15
+ return;
12
16
  }
13
- else if (error instanceof Error) {
14
- console.error(`\n ${error.message}\n`);
15
- if (error.stack)
16
- console.error(error.stack);
17
- }
18
- else {
19
- console.error(error);
20
- }
17
+ console.error(renderError(error));
21
18
  }
22
19
  //# sourceMappingURL=prettyPrintError.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prettyPrintError.js","sourceRoot":"","sources":["../../src/errors/prettyPrintError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;IACpC,CAAC;SAAM,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,OAAO,IAAI,CAAC,CAAA;QACvC,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"prettyPrintError.js","sourceRoot":"","sources":["../../src/errors/prettyPrintError.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,2EAA2E;IAC3E,4DAA4D;IAC5D,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;QAClC,OAAM;IACR,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;AACnC,CAAC"}