@gadgetinc/ggt 0.4.10 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -93
- package/lib/__generated__/graphql.js +66 -1
- package/lib/__generated__/graphql.js.map +1 -1
- package/lib/commands/deploy.js +328 -230
- package/lib/commands/deploy.js.map +1 -1
- package/lib/commands/dev.js +445 -0
- package/lib/commands/dev.js.map +1 -0
- package/lib/commands/list.js +27 -19
- package/lib/commands/list.js.map +1 -1
- package/lib/commands/login.js +15 -11
- package/lib/commands/login.js.map +1 -1
- package/lib/commands/logout.js +5 -5
- package/lib/commands/logout.js.map +1 -1
- package/lib/commands/open.js +200 -0
- package/lib/commands/open.js.map +1 -0
- package/lib/commands/pull.js +128 -0
- package/lib/commands/pull.js.map +1 -0
- package/lib/commands/push.js +126 -0
- package/lib/commands/push.js.map +1 -0
- package/lib/commands/root.js +46 -28
- package/lib/commands/root.js.map +1 -1
- package/lib/commands/status.js +61 -0
- package/lib/commands/status.js.map +1 -0
- package/lib/commands/version.js +6 -6
- package/lib/commands/version.js.map +1 -1
- package/lib/commands/whoami.js +6 -6
- package/lib/commands/whoami.js.map +1 -1
- package/lib/ggt.js +33 -8
- package/lib/ggt.js.map +1 -1
- package/lib/main.js +5 -0
- package/lib/main.js.map +1 -0
- package/lib/services/app/api/api.js +191 -0
- package/lib/services/app/api/api.js.map +1 -0
- package/lib/services/app/api/operation.js +12 -0
- package/lib/services/app/api/operation.js.map +1 -0
- package/lib/services/app/app.js +44 -10
- package/lib/services/app/app.js.map +1 -1
- package/lib/services/app/{edit/client.js → client.js} +29 -19
- package/lib/services/app/client.js.map +1 -0
- package/lib/services/app/edit/edit.js +67 -31
- package/lib/services/app/edit/edit.js.map +1 -1
- package/lib/services/app/edit/operation.js +4 -3
- package/lib/services/app/edit/operation.js.map +1 -1
- package/lib/services/app/{edit/error.js → error.js} +6 -6
- package/lib/services/app/error.js.map +1 -0
- package/lib/services/command/arg.js +4 -4
- package/lib/services/command/arg.js.map +1 -1
- package/lib/services/command/command.js +9 -7
- package/lib/services/command/command.js.map +1 -1
- package/lib/services/command/context.js +82 -20
- package/lib/services/command/context.js.map +1 -1
- package/lib/services/config/config.js +4 -7
- package/lib/services/config/config.js.map +1 -1
- package/lib/services/config/env.js +1 -1
- package/lib/services/config/env.js.map +1 -1
- package/lib/services/filesync/changes.js +76 -37
- package/lib/services/filesync/changes.js.map +1 -1
- package/lib/services/filesync/conflicts.js +10 -9
- package/lib/services/filesync/conflicts.js.map +1 -1
- package/lib/services/filesync/directory.js +16 -1
- package/lib/services/filesync/directory.js.map +1 -1
- package/lib/services/filesync/error.js +96 -27
- package/lib/services/filesync/error.js.map +1 -1
- package/lib/services/filesync/filesync.js +448 -490
- package/lib/services/filesync/filesync.js.map +1 -1
- package/lib/services/filesync/hashes.js +8 -5
- package/lib/services/filesync/hashes.js.map +1 -1
- package/lib/services/filesync/strategy.js +59 -0
- package/lib/services/filesync/strategy.js.map +1 -0
- package/lib/services/filesync/sync-json.js +475 -0
- package/lib/services/filesync/sync-json.js.map +1 -0
- package/lib/services/http/auth.js +30 -1
- package/lib/services/http/auth.js.map +1 -1
- package/lib/services/http/http.js +5 -0
- package/lib/services/http/http.js.map +1 -1
- package/lib/services/output/confirm.js +149 -0
- package/lib/services/output/confirm.js.map +1 -0
- package/lib/services/output/footer.js +22 -0
- package/lib/services/output/footer.js.map +1 -0
- package/lib/services/output/log/format/pretty.js +2 -1
- package/lib/services/output/log/format/pretty.js.map +1 -1
- package/lib/services/output/log/logger.js +13 -5
- package/lib/services/output/log/logger.js.map +1 -1
- package/lib/services/output/log/structured.js +2 -2
- package/lib/services/output/log/structured.js.map +1 -1
- package/lib/services/output/output.js +197 -0
- package/lib/services/output/output.js.map +1 -0
- package/lib/services/output/print.js +31 -0
- package/lib/services/output/print.js.map +1 -0
- package/lib/services/output/problems.js +84 -0
- package/lib/services/output/problems.js.map +1 -0
- package/lib/services/output/prompt.js +173 -40
- package/lib/services/output/prompt.js.map +1 -1
- package/lib/services/output/report.js +63 -19
- package/lib/services/output/report.js.map +1 -1
- package/lib/services/output/select.js +198 -0
- package/lib/services/output/select.js.map +1 -0
- package/lib/services/output/spinner.js +141 -0
- package/lib/services/output/spinner.js.map +1 -0
- package/lib/services/output/sprint.js +38 -15
- package/lib/services/output/sprint.js.map +1 -1
- package/lib/services/output/symbols.js +23 -0
- package/lib/services/output/symbols.js.map +1 -0
- package/lib/services/output/table.js +98 -0
- package/lib/services/output/table.js.map +1 -0
- package/lib/services/output/timestamp.js +12 -0
- package/lib/services/output/timestamp.js.map +1 -0
- package/lib/services/output/update.js +29 -9
- package/lib/services/output/update.js.map +1 -1
- package/lib/services/user/session.js +4 -0
- package/lib/services/user/session.js.map +1 -1
- package/lib/services/user/user.js +15 -10
- package/lib/services/user/user.js.map +1 -1
- package/lib/services/util/assert.js +11 -0
- package/lib/services/util/assert.js.map +1 -0
- package/lib/services/util/boolean.js +2 -2
- package/lib/services/util/boolean.js.map +1 -1
- package/lib/services/util/function.js +45 -7
- package/lib/services/util/function.js.map +1 -1
- package/lib/services/util/is.js +23 -2
- package/lib/services/util/is.js.map +1 -1
- package/lib/services/util/json.js +16 -13
- package/lib/services/util/json.js.map +1 -1
- package/lib/services/util/object.js +2 -2
- package/lib/services/util/object.js.map +1 -1
- package/lib/services/util/promise.js +5 -2
- package/lib/services/util/promise.js.map +1 -1
- package/lib/services/util/types.js.map +1 -1
- package/npm-shrinkwrap.json +3415 -2973
- package/package.json +47 -40
- package/bin/dev.cmd +0 -3
- package/bin/dev.js +0 -14
- package/bin/run.cmd +0 -3
- package/bin/run.js +0 -5
- package/lib/commands/sync.js +0 -284
- package/lib/commands/sync.js.map +0 -1
- package/lib/services/app/edit/client.js.map +0 -1
- package/lib/services/app/edit/error.js.map +0 -1
- package/lib/services/output/log/printer.js +0 -120
- package/lib/services/output/log/printer.js.map +0 -1
- package/lib/services/output/stream.js +0 -54
- package/lib/services/output/stream.js.map +0 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { isString } from "../util/is.js";
|
|
5
|
+
import { defaults } from "../util/object.js";
|
|
6
|
+
import { output } from "./output.js";
|
|
7
|
+
import { println } from "./print.js";
|
|
8
|
+
import { Prompt } from "./prompt.js";
|
|
9
|
+
import { isSprintOptions, sprint, sprintln } from "./sprint.js";
|
|
10
|
+
// TODO: i regret this api... don't make it the same as println... just make it take ctx and options
|
|
11
|
+
const createConfirm = (options)=>{
|
|
12
|
+
options = defaults(options, {
|
|
13
|
+
ensureEmptyLineAbove: true,
|
|
14
|
+
exitWhenNo: true
|
|
15
|
+
});
|
|
16
|
+
return (templateOrOptions, ...values)=>{
|
|
17
|
+
if (isSprintOptions(templateOrOptions)) {
|
|
18
|
+
return createConfirm({
|
|
19
|
+
...options,
|
|
20
|
+
...templateOrOptions
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
let text = templateOrOptions;
|
|
24
|
+
if (!isString(text)) {
|
|
25
|
+
text = sprint(templateOrOptions, ...values);
|
|
26
|
+
}
|
|
27
|
+
const whenNotInteractive = options.whenNotInteractive ?? (()=>{
|
|
28
|
+
// TODO: log an error here
|
|
29
|
+
println(options)(text);
|
|
30
|
+
println({
|
|
31
|
+
ensureEmptyLineAbove: true
|
|
32
|
+
})`
|
|
33
|
+
Aborting because ggt is not running in an interactive terminal.
|
|
34
|
+
`;
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
37
|
+
if (!output.isInteractive) {
|
|
38
|
+
return Promise.resolve(whenNotInteractive());
|
|
39
|
+
}
|
|
40
|
+
return new Promise((resolve)=>{
|
|
41
|
+
const conf = new Confirm(text, options);
|
|
42
|
+
conf.on("submit", resolve);
|
|
43
|
+
conf.on("exit", ()=>process.exit(0));
|
|
44
|
+
conf.on("abort", ()=>process.exit(1));
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export const confirm = createConfirm({});
|
|
49
|
+
/**
|
|
50
|
+
* Inspired by `prompts`:
|
|
51
|
+
* https://github.com/terkelg/prompts/blob/e0519913ec4fcc6746bb3d97d8cd0960c3f3ffde/lib/elements/confirm.js
|
|
52
|
+
*
|
|
53
|
+
* MIT License
|
|
54
|
+
*
|
|
55
|
+
* Copyright (c) 2018 Terkel Gjervig Nielsen
|
|
56
|
+
*
|
|
57
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
58
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
59
|
+
* in the Software without restriction, including without limitation the rights
|
|
60
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
61
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
62
|
+
* furnished to do so, subject to the following conditions:
|
|
63
|
+
*
|
|
64
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
65
|
+
* copies or substantial portions of the Software.
|
|
66
|
+
*
|
|
67
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
68
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
69
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
70
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
71
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
72
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
73
|
+
* SOFTWARE.
|
|
74
|
+
*/ export class Confirm extends Prompt {
|
|
75
|
+
reset() {
|
|
76
|
+
this.value = this.defaultValue;
|
|
77
|
+
this.fire();
|
|
78
|
+
this.render();
|
|
79
|
+
}
|
|
80
|
+
exit() {
|
|
81
|
+
this.abort();
|
|
82
|
+
}
|
|
83
|
+
abort() {
|
|
84
|
+
this.value = false;
|
|
85
|
+
this.done = this.aborted = true;
|
|
86
|
+
this.fire();
|
|
87
|
+
this.render(false);
|
|
88
|
+
this.close();
|
|
89
|
+
if (this.options.exitWhenNo) {
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
submit() {
|
|
94
|
+
this.value = this.value ?? false;
|
|
95
|
+
this.done = true;
|
|
96
|
+
this.aborted = false;
|
|
97
|
+
this.fire();
|
|
98
|
+
this.render();
|
|
99
|
+
this.close();
|
|
100
|
+
if (this.options.exitWhenNo && !this.value) {
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
_(char, _key) {
|
|
105
|
+
if (char.toLowerCase() === "y") {
|
|
106
|
+
this.value = true;
|
|
107
|
+
this.submit();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (char.toLowerCase() === "n") {
|
|
111
|
+
this.value = false;
|
|
112
|
+
this.submit();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.bell();
|
|
116
|
+
}
|
|
117
|
+
render(value = this.value) {
|
|
118
|
+
super.render();
|
|
119
|
+
if (this.done) {
|
|
120
|
+
output.persistPrompt(sprintln`
|
|
121
|
+
${this.text} ${value ? chalk.bold.greenBright("Yes.") : chalk.bold.redBright("No.")}
|
|
122
|
+
`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
output.updatePrompt(sprintln`
|
|
126
|
+
${this.text} ${this.defaultValue ? "[Y/n] " : "[y/N] "}
|
|
127
|
+
`);
|
|
128
|
+
}
|
|
129
|
+
constructor(text, options){
|
|
130
|
+
super();
|
|
131
|
+
_define_property(this, "text", void 0);
|
|
132
|
+
_define_property(this, "value", void 0);
|
|
133
|
+
_define_property(this, "defaultValue", void 0);
|
|
134
|
+
_define_property(this, "options", void 0);
|
|
135
|
+
this.text = text;
|
|
136
|
+
this.value = undefined;
|
|
137
|
+
this.defaultValue = false;
|
|
138
|
+
this.options = defaults(options, {
|
|
139
|
+
exitWhenNo: true,
|
|
140
|
+
ensureEmptyLineAbove: true
|
|
141
|
+
});
|
|
142
|
+
if (this.options.ensureEmptyLineAbove) {
|
|
143
|
+
this.text = "\n" + this.text;
|
|
144
|
+
}
|
|
145
|
+
this.render();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/output/confirm.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport process from \"node:process\";\nimport type { Promisable } from \"type-fest\";\nimport { isString } from \"../util/is.js\";\nimport { defaults } from \"../util/object.js\";\nimport { output } from \"./output.js\";\nimport { println } from \"./print.js\";\nimport { Prompt, type StdinKey } from \"./prompt.js\";\nimport { isSprintOptions, sprint, sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport type ConfirmOptions = SprintOptions & {\n /**\n * If `true`, ggt will exit if the user selects \"No\".\n *\n * @default true\n */\n exitWhenNo?: boolean;\n\n /**\n * What to do if ggt is not running in an interactive terminal.\n *\n * @default ```\n * println(options)(text);\n * println({ ensureEmptyLineAbove: true })`\n * Aborting because ggt is not running in an interactive terminal.\n * `;\n * process.exit(1);\n * ```\n */\n whenNotInteractive?: () => Promisable<void>;\n};\n\nexport type confirm = {\n (str: string): Promise<void>;\n (template: TemplateStringsArray, ...values: unknown[]): Promise<void>;\n (options: ConfirmOptions): confirm;\n};\n\n// TODO: i regret this api... don't make it the same as println... just make it take ctx and options\nconst createConfirm = (options: ConfirmOptions): confirm => {\n options = defaults(options, {\n ensureEmptyLineAbove: true,\n exitWhenNo: true,\n });\n\n return ((templateOrOptions: ConfirmOptions | string | TemplateStringsArray, ...values: unknown[]): confirm | Promise<void> => {\n if (isSprintOptions(templateOrOptions)) {\n return createConfirm({ ...options, ...templateOrOptions });\n }\n\n let text = templateOrOptions as string;\n if (!isString(text)) {\n text = sprint(templateOrOptions as TemplateStringsArray, ...values);\n }\n\n const whenNotInteractive =\n options.whenNotInteractive ??\n (() => {\n // TODO: log an error here\n println(options)(text);\n println({ ensureEmptyLineAbove: true })`\n Aborting because ggt is not running in an interactive terminal.\n `;\n process.exit(1);\n });\n\n if (!output.isInteractive) {\n return Promise.resolve(whenNotInteractive());\n }\n\n return new Promise((resolve) => {\n const conf = new Confirm(text, options);\n conf.on(\"submit\", resolve);\n conf.on(\"exit\", () => process.exit(0));\n conf.on(\"abort\", () => process.exit(1));\n });\n }) as confirm;\n};\n\nexport const confirm = createConfirm({});\n\n/**\n * Inspired by `prompts`:\n * https://github.com/terkelg/prompts/blob/e0519913ec4fcc6746bb3d97d8cd0960c3f3ffde/lib/elements/confirm.js\n *\n * MIT License\n *\n * Copyright (c) 2018 Terkel Gjervig Nielsen\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\nexport class Confirm extends Prompt {\n override value: boolean | undefined = undefined;\n defaultValue = false;\n options;\n\n constructor(\n readonly text: string,\n options: Partial<ConfirmOptions>,\n ) {\n super();\n\n this.options = defaults(options, {\n exitWhenNo: true,\n ensureEmptyLineAbove: true,\n });\n\n if (this.options.ensureEmptyLineAbove) {\n this.text = \"\\n\" + this.text;\n }\n\n this.render();\n }\n\n reset(): void {\n this.value = this.defaultValue;\n this.fire();\n this.render();\n }\n\n exit(): void {\n this.abort();\n }\n\n abort(): void {\n this.value = false;\n this.done = this.aborted = true;\n this.fire();\n this.render(false);\n this.close();\n\n if (this.options.exitWhenNo) {\n process.exit(0);\n }\n }\n\n submit(): void {\n this.value = this.value ?? false;\n this.done = true;\n this.aborted = false;\n this.fire();\n this.render();\n this.close();\n\n if (this.options.exitWhenNo && !this.value) {\n process.exit(0);\n }\n }\n\n override _(char: string, _key: StdinKey): void {\n if (char.toLowerCase() === \"y\") {\n this.value = true;\n this.submit();\n return;\n }\n\n if (char.toLowerCase() === \"n\") {\n this.value = false;\n this.submit();\n return;\n }\n\n this.bell();\n }\n\n override render(value = this.value): void {\n super.render();\n\n if (this.done) {\n output.persistPrompt(sprintln`\n ${this.text} ${value ? chalk.bold.greenBright(\"Yes.\") : chalk.bold.redBright(\"No.\")}\n `);\n return;\n }\n\n output.updatePrompt(sprintln`\n ${this.text} ${this.defaultValue ? \"[Y/n] \" : \"[y/N] \"}\n `);\n }\n}\n"],"names":["chalk","process","isString","defaults","output","println","Prompt","isSprintOptions","sprint","sprintln","createConfirm","options","ensureEmptyLineAbove","exitWhenNo","templateOrOptions","values","text","whenNotInteractive","exit","isInteractive","Promise","resolve","conf","Confirm","on","confirm","reset","value","defaultValue","fire","render","abort","done","aborted","close","submit","_","char","_key","toLowerCase","bell","persistPrompt","bold","greenBright","redBright","updatePrompt","constructor","undefined"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { output } from "./output.js";
|
|
2
|
+
import { isSprintOptions, sprintln } from "./sprint.js";
|
|
3
|
+
const createFooter = (options)=>{
|
|
4
|
+
return (optionsOrString, ...values)=>{
|
|
5
|
+
if (isSprintOptions(optionsOrString)) {
|
|
6
|
+
return createFooter({
|
|
7
|
+
...options,
|
|
8
|
+
...optionsOrString
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
const str = sprintln(options)(optionsOrString, ...values);
|
|
12
|
+
if (output.isInteractive) {
|
|
13
|
+
output.updateFooter(str);
|
|
14
|
+
} else {
|
|
15
|
+
output.writeStdout(str);
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export const footer = createFooter({});
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/output/footer.ts"],"sourcesContent":["import { output } from \"./output.js\";\nimport { isSprintOptions, sprintln, type SprintOptions } from \"./sprint.js\";\n\nexport type footer = {\n (str: string): void;\n (template: TemplateStringsArray, ...values: unknown[]): void;\n (options: SprintOptions): footer;\n};\n\nconst createFooter = (options: SprintOptions): footer => {\n return ((optionsOrString: SprintOptions | string | TemplateStringsArray, ...values: unknown[]): footer | undefined => {\n if (isSprintOptions(optionsOrString)) {\n return createFooter({ ...options, ...optionsOrString });\n }\n\n const str = sprintln(options)(optionsOrString as TemplateStringsArray, ...values);\n\n if (output.isInteractive) {\n output.updateFooter(str);\n } else {\n output.writeStdout(str);\n }\n\n return;\n }) as footer;\n};\n\nexport const footer = createFooter({});\n"],"names":["output","isSprintOptions","sprintln","createFooter","options","optionsOrString","values","str","isInteractive","updateFooter","writeStdout","footer"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AACrC,SAASC,eAAe,EAAEC,QAAQ,QAA4B,cAAc;AAQ5E,MAAMC,eAAe,CAACC;IACpB,OAAQ,CAACC,iBAAgE,GAAGC;QAC1E,IAAIL,gBAAgBI,kBAAkB;YACpC,OAAOF,aAAa;gBAAE,GAAGC,OAAO;gBAAE,GAAGC,eAAe;YAAC;QACvD;QAEA,MAAME,MAAML,SAASE,SAASC,oBAA4CC;QAE1E,IAAIN,OAAOQ,aAAa,EAAE;YACxBR,OAAOS,YAAY,CAACF;QACtB,OAAO;YACLP,OAAOU,WAAW,CAACH;QACrB;QAEA;IACF;AACF;AAEA,OAAO,MAAMI,SAASR,aAAa,CAAC,GAAG"}
|
|
@@ -4,6 +4,7 @@ import assert from "node:assert";
|
|
|
4
4
|
import { config } from "../../../config/config.js";
|
|
5
5
|
import { env } from "../../../config/env.js";
|
|
6
6
|
import { isObject } from "../../../util/is.js";
|
|
7
|
+
import { symbol } from "../../symbols.js";
|
|
7
8
|
import { Level } from "../level.js";
|
|
8
9
|
export const formatPretty = (level, name, msg, fields)=>{
|
|
9
10
|
return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;
|
|
@@ -94,7 +95,7 @@ const formatFields = (fields, indent = 2)=>{
|
|
|
94
95
|
value = Object.fromEntries([
|
|
95
96
|
...entries.slice(0, 10),
|
|
96
97
|
[
|
|
97
|
-
|
|
98
|
+
symbol.ellipsis,
|
|
98
99
|
`${entries.length - 10} more`
|
|
99
100
|
]
|
|
100
101
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value);\n }\n\n if (isObject(value)) {\n const entries = Object.entries(value);\n if (entries.length === 0) {\n buf.push(formatValue(\" {}\", gray, indent));\n continue;\n }\n\n if (entries.length > 10 && config.logLevel > Level.TRACE) {\n // truncate objects to 10 keys when not tracing\n value = Object.fromEntries([...entries.slice(0, 10), [
|
|
1
|
+
{"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { symbol } from \"../../symbols.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value);\n }\n\n if (isObject(value)) {\n const entries = Object.entries(value);\n if (entries.length === 0) {\n buf.push(formatValue(\" {}\", gray, indent));\n continue;\n }\n\n if (entries.length > 10 && config.logLevel > Level.TRACE) {\n // truncate objects to 10 keys when not tracing\n value = Object.fromEntries([...entries.slice(0, 10), [symbol.ellipsis, `${entries.length - 10} more`]]);\n }\n\n buf.push(formatFields(value as Record<string, unknown>, indent + 2));\n continue;\n }\n\n buf.push(SPACE);\n\n switch (typeof value) {\n case \"string\":\n buf.push(formatValue(QUOTE + value.replaceAll(NEW_LINE, NEW_LINE + SPACE.repeat(indent + key.length)) + QUOTE, blueLight, indent));\n break;\n case \"number\":\n buf.push(formatValue(String(value), orangeLight, indent));\n break;\n case \"bigint\":\n buf.push(formatValue(String(value) + \"n\", orangeLight, indent));\n break;\n case \"boolean\":\n buf.push(formatValue(String(value), greenLight, indent));\n break;\n default:\n buf.push(formatValue(String(value), white, indent));\n break;\n }\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatTimestamp = (): string => {\n const ts = dayjs().format(\"hh:mm:ss\");\n return grayDark(ts);\n};\n\nconst formatLevel = (level: Level): string => {\n switch (level) {\n case Level.PRINT:\n return gray(\"PRINT\");\n case Level.TRACE:\n return blue(\"TRACE\");\n case Level.DEBUG:\n return orange(\"DEBUG\");\n case Level.INFO:\n return green(\"INFO\");\n case Level.WARN:\n return pink(\"WARN\");\n case Level.ERROR:\n return red(\"ERROR\");\n // case \"fatal\":\n // return red(colors.bold(level));\n }\n};\n\nconst formatName = (name: string): string => {\n return white(name);\n};\n\nconst formatMessage = (msg: string): string => {\n const lines = msg.split(NEW_LINE);\n if (lines.length === 1) {\n return SPACE + white(msg);\n }\n return NEW_LINE + lines.map((line) => SPACE + SPACE + line).join(NEW_LINE);\n};\n"],"names":["chalk","Chalk","dayjs","assert","config","env","isObject","symbol","Level","formatPretty","level","name","msg","fields","formatTimestamp","formatLevel","formatName","formatMessage","formatFields","NEW_LINE","color","testLike","logLevel","PRINT","blue","hex","blueLight","gray","grayDark","green","greenLight","orange","orangeLight","pink","red","white","EMPTY","SPACE","COLON","QUOTE","formatKey","key","indent","buf","push","i","join","formatValue","value","lines","split","length","firstLine","shift","line","Object","keys","entries","Set","Array","from","isArray","fromEntries","Map","TRACE","slice","ellipsis","replaceAll","repeat","String","ts","format","DEBUG","INFO","WARN","ERROR","map"],"mappings":"AAAA,OAAOA,SAASC,KAAK,QAAQ,QAAQ;AACrC,OAAOC,WAAW,QAAQ;AAC1B,OAAOC,YAAY,cAAc;AACjC,SAASC,MAAM,QAAQ,4BAA4B;AACnD,SAASC,GAAG,QAAQ,yBAAyB;AAC7C,SAASC,QAAQ,QAAQ,sBAAsB;AAC/C,SAASC,MAAM,QAAQ,mBAAmB;AAC1C,SAASC,KAAK,QAAQ,cAAc;AAGpC,OAAO,MAAMC,eAA0B,CAACC,OAAOC,MAAMC,KAAKC;IACxD,OAAO,CAAC,EAAEC,kBAAkB,CAAC,EAAEC,YAAYL,OAAO,CAAC,EAAEM,WAAWL,MAAM,CAAC,EAAEM,cAAcL,KAAK,EAAEM,aAAaL,QAAQ,EAAEM,SAAS,CAAC;AACjI,EAAE;AAEF,MAAMC,QAAQ,IAAInB,MAAM;IACtB,oEAAoE;IACpE,6DAA6D;IAC7D,gEAAgE;IAChES,OAAOL,IAAIgB,QAAQ,IAAIjB,OAAOkB,QAAQ,GAAGd,MAAMe,KAAK,GAAG,IAAIvB,MAAMU,KAAK;AACxE;AAEA,MAAMc,OAAOJ,MAAMK,GAAG,CAAC;AACvB,MAAMC,YAAYN,MAAMK,GAAG,CAAC;AAC5B,MAAME,OAAOP,MAAMK,GAAG,CAAC;AACvB,MAAMG,WAAWR,MAAMK,GAAG,CAAC;AAC3B,MAAMI,QAAQT,MAAMK,GAAG,CAAC;AACxB,MAAMK,aAAaV,MAAMK,GAAG,CAAC;AAC7B,MAAMM,SAASX,MAAMK,GAAG,CAAC;AACzB,MAAMO,cAAcZ,MAAMK,GAAG,CAAC;AAC9B,MAAMQ,OAAOb,MAAMK,GAAG,CAAC;AACvB,MAAMS,MAAMd,MAAMK,GAAG,CAAC;AACtB,MAAMU,QAAQf,MAAMK,GAAG,CAAC;AAExB,MAAMW,QAAQ;AACd,MAAMC,QAAQ;AACd,MAAMlB,WAAW;AACjB,MAAMmB,QAAQ;AACd,MAAMC,QAAQ;AAEd,MAAMC,YAAY,CAACC,KAAaC;IAC9B,MAAMtB,QAAQqB,QAAQ,UAAUP,MAAMP;IAEtC,MAAMgB,MAAgB,EAAE;IACxBA,IAAIC,IAAI,CAACzB;IACT,IAAK,IAAI0B,IAAI,GAAGA,IAAIH,QAAQG,IAAK;QAC/BF,IAAIC,IAAI,CAACP;IACX;IACAM,IAAIC,IAAI,CAACxB,MAAMqB;IACfE,IAAIC,IAAI,CAACN;IAET,OAAOK,IAAIG,IAAI,CAAC;AAClB;AAEA,MAAMC,cAAc,CAACC,OAAe5B,OAA8BsB;IAChE,MAAMO,QAAQD,MAAME,KAAK,CAAC/B;IAC1B,IAAI8B,MAAME,MAAM,KAAK,GAAG;QACtB,OAAOf;IACT;IAEA,MAAMO,MAAgB,EAAE;IACxB,MAAMS,YAAYH,MAAMI,KAAK;IAC7BlD,OAAOiD;IACPT,IAAIC,IAAI,CAACxB,MAAMgC;IAEf,8BAA8B;IAC9B,KAAK,MAAME,QAAQL,MAAO;QACxB,IAAI,CAACK,MAAM;YACT;QACF;QAEAX,IAAIC,IAAI,CAACzB;QACT,IAAK,IAAI0B,IAAI,GAAGA,IAAIH,QAAQG,IAAK;YAC/BF,IAAIC,IAAI,CAACP;QACX;QAEAM,IAAIC,IAAI,CAACxB,MAAMkC;IACjB;IAEA,OAAOX,IAAIG,IAAI,CAACV;AAClB;AAEA,MAAMlB,eAAe,CAACL,QAAiC6B,SAAS,CAAC;IAC/D,IAAIa,OAAOC,IAAI,CAAC3C,QAAQsC,MAAM,KAAK,GAAG;QACpC,OAAOf;IACT;IAEA,MAAMO,MAAgB,EAAE;IACxB,KAAK,IAAI,CAACF,KAAKO,MAAM,IAAIO,OAAOE,OAAO,CAAC5C,QAAS;QAC/C8B,IAAIC,IAAI,CAACJ,UAAUC,KAAKC;QAExB,IAAIM,iBAAiBU,KAAK;YACxBV,QAAQW,MAAMC,IAAI,CAACZ;QACrB;QAEA,IAAIW,MAAME,OAAO,CAACb,QAAQ;YACxB,IAAIA,MAAMG,MAAM,KAAK,GAAG;gBACtBR,IAAIC,IAAI,CAACG,YAAY,OAAOpB,MAAMe;gBAClC;YACF;YAEAM,QAAQO,OAAOO,WAAW,CAACd,MAAMS,OAAO;QAC1C;QAEA,IAAIT,iBAAiBe,KAAK;YACxBf,QAAQO,OAAOO,WAAW,CAACd;QAC7B;QAEA,IAAI1C,SAAS0C,QAAQ;YACnB,MAAMS,UAAUF,OAAOE,OAAO,CAACT;YAC/B,IAAIS,QAAQN,MAAM,KAAK,GAAG;gBACxBR,IAAIC,IAAI,CAACG,YAAY,OAAOpB,MAAMe;gBAClC;YACF;YAEA,IAAIe,QAAQN,MAAM,GAAG,MAAM/C,OAAOkB,QAAQ,GAAGd,MAAMwD,KAAK,EAAE;gBACxD,+CAA+C;gBAC/ChB,QAAQO,OAAOO,WAAW,CAAC;uBAAIL,QAAQQ,KAAK,CAAC,GAAG;oBAAK;wBAAC1D,OAAO2D,QAAQ;wBAAE,CAAC,EAAET,QAAQN,MAAM,GAAG,GAAG,KAAK,CAAC;qBAAC;iBAAC;YACxG;YAEAR,IAAIC,IAAI,CAAC1B,aAAa8B,OAAkCN,SAAS;YACjE;QACF;QAEAC,IAAIC,IAAI,CAACP;QAET,OAAQ,OAAOW;YACb,KAAK;gBACHL,IAAIC,IAAI,CAACG,YAAYR,QAAQS,MAAMmB,UAAU,CAAChD,UAAUA,WAAWkB,MAAM+B,MAAM,CAAC1B,SAASD,IAAIU,MAAM,KAAKZ,OAAOb,WAAWgB;gBAC1H;YACF,KAAK;gBACHC,IAAIC,IAAI,CAACG,YAAYsB,OAAOrB,QAAQhB,aAAaU;gBACjD;YACF,KAAK;gBACHC,IAAIC,IAAI,CAACG,YAAYsB,OAAOrB,SAAS,KAAKhB,aAAaU;gBACvD;YACF,KAAK;gBACHC,IAAIC,IAAI,CAACG,YAAYsB,OAAOrB,QAAQlB,YAAYY;gBAChD;YACF;gBACEC,IAAIC,IAAI,CAACG,YAAYsB,OAAOrB,QAAQb,OAAOO;gBAC3C;QACJ;IACF;IAEA,OAAOC,IAAIG,IAAI,CAACV;AAClB;AAEA,MAAMtB,kBAAkB;IACtB,MAAMwD,KAAKpE,QAAQqE,MAAM,CAAC;IAC1B,OAAO3C,SAAS0C;AAClB;AAEA,MAAMvD,cAAc,CAACL;IACnB,OAAQA;QACN,KAAKF,MAAMe,KAAK;YACd,OAAOI,KAAK;QACd,KAAKnB,MAAMwD,KAAK;YACd,OAAOxC,KAAK;QACd,KAAKhB,MAAMgE,KAAK;YACd,OAAOzC,OAAO;QAChB,KAAKvB,MAAMiE,IAAI;YACb,OAAO5C,MAAM;QACf,KAAKrB,MAAMkE,IAAI;YACb,OAAOzC,KAAK;QACd,KAAKzB,MAAMmE,KAAK;YACd,OAAOzC,IAAI;IAGf;AACF;AAEA,MAAMlB,aAAa,CAACL;IAClB,OAAOwB,MAAMxB;AACf;AAEA,MAAMM,gBAAgB,CAACL;IACrB,MAAMqC,QAAQrC,IAAIsC,KAAK,CAAC/B;IACxB,IAAI8B,MAAME,MAAM,KAAK,GAAG;QACtB,OAAOd,QAAQF,MAAMvB;IACvB;IACA,OAAOO,WAAW8B,MAAM2B,GAAG,CAAC,CAACtB,OAASjB,QAAQA,QAAQiB,MAAMR,IAAI,CAAC3B;AACnE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { unthunk } from "../../util/function.js";
|
|
2
|
-
import { createPrinter } from "./printer.js";
|
|
3
2
|
import { createStructuredLogger } from "./structured.js";
|
|
4
3
|
/**
|
|
5
4
|
* Creates a {@linkcode Logger} with the given name and fields.
|
|
@@ -15,12 +14,21 @@ import { createStructuredLogger } from "./structured.js";
|
|
|
15
14
|
* @example
|
|
16
15
|
* const logger = createLogger({ name: "my-logger" });
|
|
17
16
|
* logger.info("printing hello world", { foo: "bar" });
|
|
18
|
-
*
|
|
17
|
+
* // stderr
|
|
18
|
+
* // 12:00:00 INFO my-logger: printing hello world
|
|
19
|
+
* // foo: "bar"
|
|
20
|
+
* //
|
|
21
|
+
* // stderr w/ --json
|
|
22
|
+
* // {"level":3,"name":"my-logger","msg":"printing hello world","fields":{"foo":"bar"}}
|
|
23
|
+
*
|
|
24
|
+
* logger.println("Hello, world!");
|
|
25
|
+
* // stdout
|
|
26
|
+
* // Hello, world!
|
|
27
|
+
* //
|
|
28
|
+
* // stdout w/ --json
|
|
29
|
+
* // {"level":6,"name":"my-logger","msg":"Hello, world!"}
|
|
19
30
|
*/ export const createLogger = ({ name, fields: loggerFields, devFields: loggerDevFields })=>{
|
|
20
31
|
return {
|
|
21
|
-
...createPrinter({
|
|
22
|
-
name
|
|
23
|
-
}),
|
|
24
32
|
...createStructuredLogger({
|
|
25
33
|
name,
|
|
26
34
|
fields: loggerFields,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/services/output/log/logger.ts"],"sourcesContent":["import { unthunk } from \"../../util/function.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/services/output/log/logger.ts"],"sourcesContent":["import { unthunk } from \"../../util/function.js\";\nimport { createStructuredLogger, type StructuredLogger, type StructuredLoggerOptions } from \"./structured.js\";\n\nexport type Logger = StructuredLogger & {\n /**\n * Creates a child logger with the given options. The child logger\n * inherits the name and fields of the parent logger.\n *\n * @param options\n */\n child(options: Partial<StructuredLoggerOptions>): Logger;\n};\n\n/**\n * Creates a {@linkcode Logger} with the given name and fields.\n *\n * Use the {@linkcode Printer} methods to print messages to stdout for\n * end users to read.\n *\n * Use the {@linkcode StructuredLogger} methods to print structured\n * messages to stderr for developers to read. These messages are only\n * printed when the `GGT_LOG_LEVEL` is greater than or equal to the\n * level of the message.\n *\n * @example\n * const logger = createLogger({ name: \"my-logger\" });\n * logger.info(\"printing hello world\", { foo: \"bar\" });\n * // stderr\n * // 12:00:00 INFO my-logger: printing hello world\n * // foo: \"bar\"\n * //\n * // stderr w/ --json\n * // {\"level\":3,\"name\":\"my-logger\",\"msg\":\"printing hello world\",\"fields\":{\"foo\":\"bar\"}}\n *\n * logger.println(\"Hello, world!\");\n * // stdout\n * // Hello, world!\n * //\n * // stdout w/ --json\n * // {\"level\":6,\"name\":\"my-logger\",\"msg\":\"Hello, world!\"}\n */\nexport const createLogger = ({ name, fields: loggerFields, devFields: loggerDevFields }: StructuredLoggerOptions): Logger => {\n return {\n ...createStructuredLogger({ name, fields: loggerFields, devFields: loggerDevFields }),\n child: ({ name: childName, fields: childFields, devFields: childDevFields }) => {\n return createLogger({\n name: childName || name,\n fields: () => ({ ...unthunk(loggerFields), ...unthunk(childFields) }),\n devFields: { ...unthunk(loggerDevFields), ...unthunk(childDevFields) },\n });\n },\n };\n};\n"],"names":["unthunk","createStructuredLogger","createLogger","name","fields","loggerFields","devFields","loggerDevFields","child","childName","childFields","childDevFields"],"mappings":"AAAA,SAASA,OAAO,QAAQ,yBAAyB;AACjD,SAASC,sBAAsB,QAA6D,kBAAkB;AAY9G;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,MAAMC,eAAe,CAAC,EAAEC,IAAI,EAAEC,QAAQC,YAAY,EAAEC,WAAWC,eAAe,EAA2B;IAC9G,OAAO;QACL,GAAGN,uBAAuB;YAAEE;YAAMC,QAAQC;YAAcC,WAAWC;QAAgB,EAAE;QACrFC,OAAO,CAAC,EAAEL,MAAMM,SAAS,EAAEL,QAAQM,WAAW,EAAEJ,WAAWK,cAAc,EAAE;YACzE,OAAOT,aAAa;gBAClBC,MAAMM,aAAaN;gBACnBC,QAAQ,IAAO,CAAA;wBAAE,GAAGJ,QAAQK,aAAa;wBAAE,GAAGL,QAAQU,YAAY;oBAAC,CAAA;gBACnEJ,WAAW;oBAAE,GAAGN,QAAQO,gBAAgB;oBAAE,GAAGP,QAAQW,eAAe;gBAAC;YACvE;QACF;IACF;AACF,EAAE"}
|
|
@@ -3,7 +3,7 @@ import { config } from "../../config/config.js";
|
|
|
3
3
|
import { env } from "../../config/env.js";
|
|
4
4
|
import { unthunk } from "../../util/function.js";
|
|
5
5
|
import { serializeError } from "../../util/object.js";
|
|
6
|
-
import {
|
|
6
|
+
import { output } from "../output.js";
|
|
7
7
|
import { formatters } from "./format/format.js";
|
|
8
8
|
import { Level } from "./level.js";
|
|
9
9
|
export const createStructuredLogger = ({ name, fields: loggerFields = {}, devFields: devLoggerFields = {} })=>{
|
|
@@ -29,7 +29,7 @@ export const createStructuredLogger = ({ name, fields: loggerFields = {}, devFie
|
|
|
29
29
|
}
|
|
30
30
|
if (shouldLog) {
|
|
31
31
|
const format = formatters[config.logFormat];
|
|
32
|
-
|
|
32
|
+
output.writeStderr(format(level, name, msg, fields));
|
|
33
33
|
}
|
|
34
34
|
if (shouldSendToSentry) {
|
|
35
35
|
addSentryBreadcrumb({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/services/output/log/structured.ts"],"sourcesContent":["import { addBreadcrumb as addSentryBreadcrumb } from \"@sentry/node\";\nimport { config } from \"../../config/config.js\";\nimport { env } from \"../../config/env.js\";\nimport { unthunk, type Thunk } from \"../../util/function.js\";\nimport { serializeError } from \"../../util/object.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/services/output/log/structured.ts"],"sourcesContent":["import { addBreadcrumb as addSentryBreadcrumb } from \"@sentry/node\";\nimport { config } from \"../../config/config.js\";\nimport { env } from \"../../config/env.js\";\nimport { unthunk, type Thunk } from \"../../util/function.js\";\nimport { serializeError } from \"../../util/object.js\";\nimport { output } from \"../output.js\";\nimport type { Fields } from \"./field.js\";\nimport { formatters } from \"./format/format.js\";\nimport { Level } from \"./level.js\";\n\ntype StructuredLog = (msg: Lowercase<string>, fields?: Fields, devFields?: Fields) => void;\n\nexport type StructuredLogger = {\n trace: StructuredLog;\n debug: StructuredLog;\n info: StructuredLog;\n warn: StructuredLog;\n error: StructuredLog;\n};\n\nexport type StructuredLoggerOptions = {\n /**\n * The name of logger.\n */\n name: string;\n\n /**\n * Fields to add to every message logged by the logger.\n */\n fields?: Thunk<Fields>;\n\n /**\n * Fields to add to every message logged by the logger only in\n * development or test environments.\n */\n devFields?: Thunk<Fields>;\n};\n\nexport const createStructuredLogger = ({\n name,\n fields: loggerFields = {},\n devFields: devLoggerFields = {},\n}: StructuredLoggerOptions): StructuredLogger => {\n const createStructuredLog = (level: Level): StructuredLog => {\n return (msg, messageFields, devMessageFields) => {\n const shouldLog = level >= config.logLevel;\n const shouldSendToSentry = level >= Level.INFO;\n if (!shouldLog && !shouldSendToSentry) {\n return;\n }\n\n const fields = { ...unthunk(loggerFields), ...messageFields };\n if (env.developmentOrTestLike) {\n Object.assign(fields, unthunk(devLoggerFields), devMessageFields);\n }\n\n if (\"error\" in fields) {\n fields.error = serializeError(fields.error);\n }\n\n if (\"reason\" in fields) {\n fields.reason = serializeError(fields.reason);\n }\n\n if (shouldLog) {\n const format = formatters[config.logFormat];\n output.writeStderr(format(level, name, msg, fields));\n }\n\n if (shouldSendToSentry) {\n addSentryBreadcrumb({ level: \"log\", message: msg, data: fields });\n }\n };\n };\n\n return {\n trace: createStructuredLog(Level.TRACE),\n debug: createStructuredLog(Level.DEBUG),\n info: createStructuredLog(Level.INFO),\n warn: createStructuredLog(Level.WARN),\n error: createStructuredLog(Level.ERROR),\n };\n};\n"],"names":["addBreadcrumb","addSentryBreadcrumb","config","env","unthunk","serializeError","output","formatters","Level","createStructuredLogger","name","fields","loggerFields","devFields","devLoggerFields","createStructuredLog","level","msg","messageFields","devMessageFields","shouldLog","logLevel","shouldSendToSentry","INFO","developmentOrTestLike","Object","assign","error","reason","format","logFormat","writeStderr","message","data","trace","TRACE","debug","DEBUG","info","warn","WARN","ERROR"],"mappings":"AAAA,SAASA,iBAAiBC,mBAAmB,QAAQ,eAAe;AACpE,SAASC,MAAM,QAAQ,yBAAyB;AAChD,SAASC,GAAG,QAAQ,sBAAsB;AAC1C,SAASC,OAAO,QAAoB,yBAAyB;AAC7D,SAASC,cAAc,QAAQ,uBAAuB;AACtD,SAASC,MAAM,QAAQ,eAAe;AAEtC,SAASC,UAAU,QAAQ,qBAAqB;AAChD,SAASC,KAAK,QAAQ,aAAa;AA8BnC,OAAO,MAAMC,yBAAyB,CAAC,EACrCC,IAAI,EACJC,QAAQC,eAAe,CAAC,CAAC,EACzBC,WAAWC,kBAAkB,CAAC,CAAC,EACP;IACxB,MAAMC,sBAAsB,CAACC;QAC3B,OAAO,CAACC,KAAKC,eAAeC;YAC1B,MAAMC,YAAYJ,SAASd,OAAOmB,QAAQ;YAC1C,MAAMC,qBAAqBN,SAASR,MAAMe,IAAI;YAC9C,IAAI,CAACH,aAAa,CAACE,oBAAoB;gBACrC;YACF;YAEA,MAAMX,SAAS;gBAAE,GAAGP,QAAQQ,aAAa;gBAAE,GAAGM,aAAa;YAAC;YAC5D,IAAIf,IAAIqB,qBAAqB,EAAE;gBAC7BC,OAAOC,MAAM,CAACf,QAAQP,QAAQU,kBAAkBK;YAClD;YAEA,IAAI,WAAWR,QAAQ;gBACrBA,OAAOgB,KAAK,GAAGtB,eAAeM,OAAOgB,KAAK;YAC5C;YAEA,IAAI,YAAYhB,QAAQ;gBACtBA,OAAOiB,MAAM,GAAGvB,eAAeM,OAAOiB,MAAM;YAC9C;YAEA,IAAIR,WAAW;gBACb,MAAMS,SAAStB,UAAU,CAACL,OAAO4B,SAAS,CAAC;gBAC3CxB,OAAOyB,WAAW,CAACF,OAAOb,OAAON,MAAMO,KAAKN;YAC9C;YAEA,IAAIW,oBAAoB;gBACtBrB,oBAAoB;oBAAEe,OAAO;oBAAOgB,SAASf;oBAAKgB,MAAMtB;gBAAO;YACjE;QACF;IACF;IAEA,OAAO;QACLuB,OAAOnB,oBAAoBP,MAAM2B,KAAK;QACtCC,OAAOrB,oBAAoBP,MAAM6B,KAAK;QACtCC,MAAMvB,oBAAoBP,MAAMe,IAAI;QACpCgB,MAAMxB,oBAAoBP,MAAMgC,IAAI;QACpCb,OAAOZ,oBAAoBP,MAAMiC,KAAK;IACxC;AACF,EAAE"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { _ as _define_property } from "@swc/helpers/_/_define_property";
|
|
2
|
+
import cliCursor from "cli-cursor";
|
|
3
|
+
import isInteractive from "is-interactive";
|
|
4
|
+
import assert from "node:assert";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import stdinDiscarder from "stdin-discarder";
|
|
7
|
+
import stringWidth from "string-width";
|
|
8
|
+
import stripAnsi from "strip-ansi";
|
|
9
|
+
import { env } from "../config/env.js";
|
|
10
|
+
import { unthunk } from "../util/function.js";
|
|
11
|
+
import { isObject } from "../util/is.js";
|
|
12
|
+
let cursorIsHidden = false;
|
|
13
|
+
/**
|
|
14
|
+
* Stderr
|
|
15
|
+
* Prompt
|
|
16
|
+
* Spinner
|
|
17
|
+
* Footer
|
|
18
|
+
*/ export class Output {
|
|
19
|
+
get isInteractive() {
|
|
20
|
+
return !env.testLike && isInteractive({
|
|
21
|
+
stream: process.stdout
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
writeStdout(text) {
|
|
25
|
+
this._clearStickyText();
|
|
26
|
+
text = this._stripUnnecessaryNewLines(text, this.lastPrintedLineWasEmpty);
|
|
27
|
+
this._writeStdout(text);
|
|
28
|
+
this.lastPrintedLineWasEmpty = text === "\n" || text.endsWith("\n\n");
|
|
29
|
+
this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;
|
|
30
|
+
this._writeStickyText();
|
|
31
|
+
}
|
|
32
|
+
writeStderr(text) {
|
|
33
|
+
this._clearStickyText();
|
|
34
|
+
text = this._stripUnnecessaryNewLines(text, this.lastPrintedLineWasEmpty);
|
|
35
|
+
this._writeStderr(text);
|
|
36
|
+
this.lastPrintedLineWasEmpty = text === "\n" || text.endsWith("\n\n");
|
|
37
|
+
this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;
|
|
38
|
+
this._writeStickyText();
|
|
39
|
+
}
|
|
40
|
+
updatePrompt(promptTextThunk) {
|
|
41
|
+
assert(this.isInteractive, "cannot update prompt in non-interactive mode");
|
|
42
|
+
this._promptText = unthunk(promptTextThunk, this._promptText);
|
|
43
|
+
this._writeStickyText();
|
|
44
|
+
}
|
|
45
|
+
persistPrompt(finalPromptText = this._promptText) {
|
|
46
|
+
this._promptText = "";
|
|
47
|
+
this.writeStdout(finalPromptText);
|
|
48
|
+
}
|
|
49
|
+
updateSpinner(spinnerTextThunk) {
|
|
50
|
+
assert(this.isInteractive, "cannot update spinner in non-interactive mode");
|
|
51
|
+
this._spinnerText = unthunk(spinnerTextThunk, this._spinnerText);
|
|
52
|
+
this._writeStickyText();
|
|
53
|
+
}
|
|
54
|
+
persistSpinner(finalSpinnerText = this._spinnerText) {
|
|
55
|
+
this._spinnerText = "";
|
|
56
|
+
this.writeStdout(finalSpinnerText);
|
|
57
|
+
}
|
|
58
|
+
updateFooter(footerTextThunk) {
|
|
59
|
+
assert(this.isInteractive, "cannot update footer in non-interactive mode");
|
|
60
|
+
this._footerText = unthunk(footerTextThunk, this._footerText);
|
|
61
|
+
this._writeStickyText();
|
|
62
|
+
}
|
|
63
|
+
persistFooter(finalFooterText = this._footerText) {
|
|
64
|
+
this._footerText = "";
|
|
65
|
+
this.writeStdout(finalFooterText);
|
|
66
|
+
}
|
|
67
|
+
_writeStdout(text) {
|
|
68
|
+
if (text === "") {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!env.testLike) {
|
|
72
|
+
process.stdout.write(text);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// we use console.log/error in tests since vitest doesn't display
|
|
76
|
+
// process.stdout/stderr correctly, so we need to remove the
|
|
77
|
+
// trailing newline because console.log/error adds one
|
|
78
|
+
if (text.endsWith("\n")) {
|
|
79
|
+
text = text.slice(0, -1);
|
|
80
|
+
}
|
|
81
|
+
console.log(text);
|
|
82
|
+
}
|
|
83
|
+
_writeStderr(text) {
|
|
84
|
+
if (text === "") {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!env.testLike) {
|
|
88
|
+
process.stderr.write(text);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// we use console.log/error in tests since vitest doesn't display
|
|
92
|
+
// process.stdout/stderr correctly, so we need to remove the
|
|
93
|
+
// trailing newline because console.log/error adds one
|
|
94
|
+
if (text.endsWith("\n")) {
|
|
95
|
+
text = text.slice(0, -1);
|
|
96
|
+
}
|
|
97
|
+
console.error(text);
|
|
98
|
+
}
|
|
99
|
+
_clearStickyText() {
|
|
100
|
+
this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;
|
|
101
|
+
if (this._stickyTextLinesToClear === 0) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
process.stderr.cursorTo(0);
|
|
105
|
+
for(let i = 0; i < this._stickyTextLinesToClear; i++){
|
|
106
|
+
if (i > 0) {
|
|
107
|
+
process.stderr.moveCursor(0, -1);
|
|
108
|
+
}
|
|
109
|
+
process.stderr.clearLine(1);
|
|
110
|
+
}
|
|
111
|
+
this._stickyTextLinesToClear = 0;
|
|
112
|
+
}
|
|
113
|
+
_writeStickyText() {
|
|
114
|
+
if (!this.isInteractive) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
this._clearStickyText();
|
|
118
|
+
let formattedStickyText = "";
|
|
119
|
+
if (this._promptText) {
|
|
120
|
+
formattedStickyText += this._stripUnnecessaryNewLines(this._promptText, this.lastStickyLineWasEmpty);
|
|
121
|
+
this.lastStickyLineWasEmpty = formattedStickyText === "\n" || formattedStickyText.endsWith("\n\n");
|
|
122
|
+
}
|
|
123
|
+
if (this._spinnerText) {
|
|
124
|
+
formattedStickyText += this._stripUnnecessaryNewLines(this._spinnerText, this.lastStickyLineWasEmpty);
|
|
125
|
+
this.lastStickyLineWasEmpty = formattedStickyText === "\n" || formattedStickyText.endsWith("\n\n");
|
|
126
|
+
}
|
|
127
|
+
if (this._footerText) {
|
|
128
|
+
formattedStickyText += this._stripUnnecessaryNewLines(this._footerText, this.lastStickyLineWasEmpty);
|
|
129
|
+
this.lastStickyLineWasEmpty = formattedStickyText === "\n" || formattedStickyText.endsWith("\n\n");
|
|
130
|
+
}
|
|
131
|
+
this._writeStderr(formattedStickyText);
|
|
132
|
+
this._updateStickyTextLinesToClear(formattedStickyText);
|
|
133
|
+
if (cursorIsHidden && !formattedStickyText) {
|
|
134
|
+
cliCursor.show(process.stderr);
|
|
135
|
+
stdinDiscarder.stop();
|
|
136
|
+
cursorIsHidden = false;
|
|
137
|
+
} else if (!cursorIsHidden && formattedStickyText) {
|
|
138
|
+
cliCursor.hide(process.stderr);
|
|
139
|
+
stdinDiscarder.start();
|
|
140
|
+
cursorIsHidden = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
_updateStickyTextLinesToClear(lastWrittenStickyText) {
|
|
144
|
+
for (const line of stripAnsi(lastWrittenStickyText).split(/\r?\n/)){
|
|
145
|
+
const numCharacters = stringWidth(line, {
|
|
146
|
+
countAnsiEscapeCodes: true
|
|
147
|
+
});
|
|
148
|
+
const numLines = Math.ceil(numCharacters / process.stderr.columns);
|
|
149
|
+
this._stickyTextLinesToClear += Math.max(1, numLines);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
_stripUnnecessaryNewLines(text, lastLineWasEmpty) {
|
|
153
|
+
// remove duplicate empty lines
|
|
154
|
+
let index = -1;
|
|
155
|
+
while((index = text.indexOf("\n\n\n")) !== -1){
|
|
156
|
+
text = text.slice(0, index) + text.slice(index + 1);
|
|
157
|
+
}
|
|
158
|
+
if (lastLineWasEmpty) {
|
|
159
|
+
// we just printed an empty line, so don't print another one
|
|
160
|
+
while(text.startsWith("\n")){
|
|
161
|
+
text = text.slice(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return text;
|
|
165
|
+
}
|
|
166
|
+
constructor(){
|
|
167
|
+
/**
|
|
168
|
+
* Indicates whether the last line that was written to the stream was
|
|
169
|
+
* empty (i.e. "\n"). This is useful for preventing duplicate empty
|
|
170
|
+
* lines from being printed.
|
|
171
|
+
*
|
|
172
|
+
* This is automatically calculated by the {@linkcode writeStdout}
|
|
173
|
+
* method, so you only need to set this property manually when you
|
|
174
|
+
* know something else wrote to the stream directly.
|
|
175
|
+
*/ _define_property(this, "lastPrintedLineWasEmpty", true);
|
|
176
|
+
_define_property(this, "lastStickyLineWasEmpty", true);
|
|
177
|
+
_define_property(this, "_promptText", "");
|
|
178
|
+
_define_property(this, "_spinnerText", "");
|
|
179
|
+
_define_property(this, "_footerText", "");
|
|
180
|
+
_define_property(this, "_stickyTextLinesToClear", 0);
|
|
181
|
+
process.stdout.on("error", (err)=>{
|
|
182
|
+
if (isObject(err) && "code" in err && err.code === "EPIPE") {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
throw err;
|
|
186
|
+
});
|
|
187
|
+
process.stderr.on("error", (err)=>{
|
|
188
|
+
if (isObject(err) && "code" in err && err.code === "EPIPE") {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
throw err;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
export const output = new Output();
|
|
196
|
+
|
|
197
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/output/output.ts"],"sourcesContent":["import cliCursor from \"cli-cursor\";\nimport isInteractive from \"is-interactive\";\nimport assert from \"node:assert\";\nimport process from \"node:process\";\nimport stdinDiscarder from \"stdin-discarder\";\nimport stringWidth from \"string-width\";\nimport stripAnsi from \"strip-ansi\";\nimport { env } from \"../config/env.js\";\nimport { unthunk } from \"../util/function.js\";\nimport { isObject } from \"../util/is.js\";\n\nlet cursorIsHidden = false;\n\n/**\n * Stderr\n * Prompt\n * Spinner\n * Footer\n */\nexport class Output {\n /**\n * Indicates whether the last line that was written to the stream was\n * empty (i.e. \"\\n\"). This is useful for preventing duplicate empty\n * lines from being printed.\n *\n * This is automatically calculated by the {@linkcode writeStdout}\n * method, so you only need to set this property manually when you\n * know something else wrote to the stream directly.\n */\n lastPrintedLineWasEmpty = true;\n\n lastStickyLineWasEmpty = true;\n\n private _promptText = \"\";\n\n private _spinnerText = \"\";\n\n private _footerText = \"\";\n\n private _stickyTextLinesToClear = 0;\n\n constructor() {\n process.stdout.on(\"error\", (err: unknown) => {\n if (isObject(err) && \"code\" in err && err.code === \"EPIPE\") {\n return;\n }\n throw err;\n });\n\n process.stderr.on(\"error\", (err: unknown) => {\n if (isObject(err) && \"code\" in err && err.code === \"EPIPE\") {\n return;\n }\n throw err;\n });\n }\n\n get isInteractive(): boolean {\n return !env.testLike && isInteractive({ stream: process.stdout });\n }\n\n writeStdout(text: string): void {\n this._clearStickyText();\n\n text = this._stripUnnecessaryNewLines(text, this.lastPrintedLineWasEmpty);\n this._writeStdout(text);\n this.lastPrintedLineWasEmpty = text === \"\\n\" || text.endsWith(\"\\n\\n\");\n this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;\n\n this._writeStickyText();\n }\n\n writeStderr(text: string): void {\n this._clearStickyText();\n\n text = this._stripUnnecessaryNewLines(text, this.lastPrintedLineWasEmpty);\n this._writeStderr(text);\n this.lastPrintedLineWasEmpty = text === \"\\n\" || text.endsWith(\"\\n\\n\");\n this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;\n\n this._writeStickyText();\n }\n\n updatePrompt(promptTextThunk: string | ((currentPromptText: string) => string)): void {\n assert(this.isInteractive, \"cannot update prompt in non-interactive mode\");\n this._promptText = unthunk(promptTextThunk, this._promptText);\n this._writeStickyText();\n }\n\n persistPrompt(finalPromptText = this._promptText): void {\n this._promptText = \"\";\n this.writeStdout(finalPromptText);\n }\n\n updateSpinner(spinnerTextThunk: string | ((currentSpinnerText: string) => string)): void {\n assert(this.isInteractive, \"cannot update spinner in non-interactive mode\");\n this._spinnerText = unthunk(spinnerTextThunk, this._spinnerText);\n this._writeStickyText();\n }\n\n persistSpinner(finalSpinnerText = this._spinnerText): void {\n this._spinnerText = \"\";\n this.writeStdout(finalSpinnerText);\n }\n\n updateFooter(footerTextThunk: string | ((currentFooterText: string) => string)): void {\n assert(this.isInteractive, \"cannot update footer in non-interactive mode\");\n this._footerText = unthunk(footerTextThunk, this._footerText);\n this._writeStickyText();\n }\n\n persistFooter(finalFooterText = this._footerText): void {\n this._footerText = \"\";\n this.writeStdout(finalFooterText);\n }\n\n private _writeStdout(text: string): void {\n if (text === \"\") {\n return;\n }\n\n if (!env.testLike) {\n process.stdout.write(text);\n return;\n }\n\n // we use console.log/error in tests since vitest doesn't display\n // process.stdout/stderr correctly, so we need to remove the\n // trailing newline because console.log/error adds one\n if (text.endsWith(\"\\n\")) {\n text = text.slice(0, -1);\n }\n\n console.log(text);\n }\n\n private _writeStderr(text: string): void {\n if (text === \"\") {\n return;\n }\n\n if (!env.testLike) {\n process.stderr.write(text);\n return;\n }\n\n // we use console.log/error in tests since vitest doesn't display\n // process.stdout/stderr correctly, so we need to remove the\n // trailing newline because console.log/error adds one\n if (text.endsWith(\"\\n\")) {\n text = text.slice(0, -1);\n }\n\n console.error(text);\n }\n\n private _clearStickyText(): void {\n this.lastStickyLineWasEmpty = this.lastPrintedLineWasEmpty;\n if (this._stickyTextLinesToClear === 0) {\n return;\n }\n\n process.stderr.cursorTo(0);\n for (let i = 0; i < this._stickyTextLinesToClear; i++) {\n if (i > 0) {\n process.stderr.moveCursor(0, -1);\n }\n process.stderr.clearLine(1);\n }\n\n this._stickyTextLinesToClear = 0;\n }\n\n private _writeStickyText(): void {\n if (!this.isInteractive) {\n return;\n }\n\n this._clearStickyText();\n\n let formattedStickyText = \"\";\n if (this._promptText) {\n formattedStickyText += this._stripUnnecessaryNewLines(this._promptText, this.lastStickyLineWasEmpty);\n this.lastStickyLineWasEmpty = formattedStickyText === \"\\n\" || formattedStickyText.endsWith(\"\\n\\n\");\n }\n\n if (this._spinnerText) {\n formattedStickyText += this._stripUnnecessaryNewLines(this._spinnerText, this.lastStickyLineWasEmpty);\n this.lastStickyLineWasEmpty = formattedStickyText === \"\\n\" || formattedStickyText.endsWith(\"\\n\\n\");\n }\n\n if (this._footerText) {\n formattedStickyText += this._stripUnnecessaryNewLines(this._footerText, this.lastStickyLineWasEmpty);\n this.lastStickyLineWasEmpty = formattedStickyText === \"\\n\" || formattedStickyText.endsWith(\"\\n\\n\");\n }\n\n this._writeStderr(formattedStickyText);\n this._updateStickyTextLinesToClear(formattedStickyText);\n\n if (cursorIsHidden && !formattedStickyText) {\n cliCursor.show(process.stderr);\n stdinDiscarder.stop();\n cursorIsHidden = false;\n } else if (!cursorIsHidden && formattedStickyText) {\n cliCursor.hide(process.stderr);\n stdinDiscarder.start();\n cursorIsHidden = true;\n }\n }\n\n private _updateStickyTextLinesToClear(lastWrittenStickyText: string): void {\n for (const line of stripAnsi(lastWrittenStickyText).split(/\\r?\\n/)) {\n const numCharacters = stringWidth(line, { countAnsiEscapeCodes: true });\n const numLines = Math.ceil(numCharacters / process.stderr.columns);\n this._stickyTextLinesToClear += Math.max(1, numLines);\n }\n }\n\n private _stripUnnecessaryNewLines(text: string, lastLineWasEmpty: boolean): string {\n // remove duplicate empty lines\n let index = -1;\n while ((index = text.indexOf(\"\\n\\n\\n\")) !== -1) {\n text = text.slice(0, index) + text.slice(index + 1);\n }\n\n if (lastLineWasEmpty) {\n // we just printed an empty line, so don't print another one\n while (text.startsWith(\"\\n\")) {\n text = text.slice(1);\n }\n }\n\n return text;\n }\n}\n\nexport const output = new Output();\n"],"names":["cliCursor","isInteractive","assert","process","stdinDiscarder","stringWidth","stripAnsi","env","unthunk","isObject","cursorIsHidden","Output","testLike","stream","stdout","writeStdout","text","_clearStickyText","_stripUnnecessaryNewLines","lastPrintedLineWasEmpty","_writeStdout","endsWith","lastStickyLineWasEmpty","_writeStickyText","writeStderr","_writeStderr","updatePrompt","promptTextThunk","_promptText","persistPrompt","finalPromptText","updateSpinner","spinnerTextThunk","_spinnerText","persistSpinner","finalSpinnerText","updateFooter","footerTextThunk","_footerText","persistFooter","finalFooterText","write","slice","console","log","stderr","error","_stickyTextLinesToClear","cursorTo","i","moveCursor","clearLine","formattedStickyText","_updateStickyTextLinesToClear","show","stop","hide","start","lastWrittenStickyText","line","split","numCharacters","countAnsiEscapeCodes","numLines","Math","ceil","columns","max","lastLineWasEmpty","index","indexOf","startsWith","constructor","on","err","code","output"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { config } from "../config/config.js";
|
|
2
|
+
import { output } from "./output.js";
|
|
3
|
+
import { isSprintOptions, sprint } from "./sprint.js";
|
|
4
|
+
const createPrint = (options)=>{
|
|
5
|
+
return (templateOrOptions, ...values)=>{
|
|
6
|
+
if (isSprintOptions(templateOrOptions)) {
|
|
7
|
+
return createPrint({
|
|
8
|
+
...options,
|
|
9
|
+
...templateOrOptions
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const { json, ...sprintOptions } = options;
|
|
13
|
+
if (config.logFormat === "json") {
|
|
14
|
+
if (json) {
|
|
15
|
+
output.writeStdout(JSON.stringify(json) + "\n");
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const text = sprint(sprintOptions)(templateOrOptions, ...values);
|
|
20
|
+
output.writeStdout(text);
|
|
21
|
+
return;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export const print = createPrint({
|
|
25
|
+
ensureNewLine: false
|
|
26
|
+
});
|
|
27
|
+
export const println = createPrint({
|
|
28
|
+
ensureNewLine: true
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=print.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/services/output/print.ts"],"sourcesContent":["import { config } from \"../config/config.js\";\nimport type { Field } from \"./log/field.js\";\nimport { output } from \"./output.js\";\nimport { isSprintOptions, sprint, type SprintOptions } from \"./sprint.js\";\n\nexport type PrintOptions = SprintOptions & {\n /**\n * What to print if --json was passed.\n *\n * @default undefined (print nothing)\n */\n json?: Field;\n};\n\nexport type print = {\n /**\n * Prints the given string as is.\n *\n * @param str - The string to print.\n * @example\n * print(\"Hello, world!\");\n * // => \"Hello, world!\"\n *\n * print(`\n * Hello, world!\n *\n * How are you?\n * `);\n * // => \"\\n Hello, world!\\n\\n How are you?\\n\"\n */\n (str: string): void;\n\n /**\n * Prints the given template string with dedent and chalk-template.\n *\n * @param template - The template string to format.\n * @param values - The values to interpolate into the template.\n * @example\n * ```\n * let name = \"Jane\";\n *\n * print`Hello, ${name}!`;\n * // => \"Hello, Jane!\"\n *\n * print`Hello, {red ${name}}!`;\n * // => \"Hello, \\u001b[31mJane\\u001b[39m!\"\n *\n * print`\n * Hello, {red ${name}}!\n *\n * How are you?\n * `;\n * // => \"Hello, \\u001b[31mJane\\u001b[39m!\\n\\nHow are you?\"\n * ```\n * @see dedent https://github.com/tamino-martinius/node-ts-dedent\n * @see chalk-template https://github.com/chalk/chalk-template\n */\n (template: TemplateStringsArray, ...values: unknown[]): void;\n\n /**\n * Configures print with options before printing the given template\n * string with dedent and chalk-template.\n *\n * @example\n * ```\n * let name = \"Jane\";\n * print({ ensureEmptyLineAbove: true })`Hello, ${name}!`;\n * // => \"\\nHello, Jane!\"\n *\n * print({ ensureEmptyLineAbove: true })`Hello, {red ${name}}!`;\n * // => \"\\nHello, \\u001b[31mJane\\u001b[39m!\"\n *\n * print({ ensureEmptyLineAbove: true })`\n * Hello, {red ${name}}!\n *\n * How are you?\n * `;\n * // => \"\\nHello, \\u001b[31mJane\\u001b[39m!\\n\\nHow are you?\"\n * ```\n * @see PrintOptions\n */\n (options: PrintOptions): print;\n};\n\nconst createPrint = (options: PrintOptions): print => {\n return ((templateOrOptions: PrintOptions | string | TemplateStringsArray, ...values: unknown[]): print | undefined => {\n if (isSprintOptions(templateOrOptions)) {\n return createPrint({ ...options, ...templateOrOptions });\n }\n\n const { json, ...sprintOptions } = options;\n\n if (config.logFormat === \"json\") {\n if (json) {\n output.writeStdout(JSON.stringify(json) + \"\\n\");\n }\n return;\n }\n\n const text = sprint(sprintOptions)(templateOrOptions as TemplateStringsArray, ...values);\n output.writeStdout(text);\n return;\n }) as print;\n};\n\nexport const print = createPrint({ ensureNewLine: false });\nexport const println = createPrint({ ensureNewLine: true });\n"],"names":["config","output","isSprintOptions","sprint","createPrint","options","templateOrOptions","values","json","sprintOptions","logFormat","writeStdout","JSON","stringify","text","print","ensureNewLine","println"],"mappings":"AAAA,SAASA,MAAM,QAAQ,sBAAsB;AAE7C,SAASC,MAAM,QAAQ,cAAc;AACrC,SAASC,eAAe,EAAEC,MAAM,QAA4B,cAAc;AAiF1E,MAAMC,cAAc,CAACC;IACnB,OAAQ,CAACC,mBAAiE,GAAGC;QAC3E,IAAIL,gBAAgBI,oBAAoB;YACtC,OAAOF,YAAY;gBAAE,GAAGC,OAAO;gBAAE,GAAGC,iBAAiB;YAAC;QACxD;QAEA,MAAM,EAAEE,IAAI,EAAE,GAAGC,eAAe,GAAGJ;QAEnC,IAAIL,OAAOU,SAAS,KAAK,QAAQ;YAC/B,IAAIF,MAAM;gBACRP,OAAOU,WAAW,CAACC,KAAKC,SAAS,CAACL,QAAQ;YAC5C;YACA;QACF;QAEA,MAAMM,OAAOX,OAAOM,eAAeH,sBAA8CC;QACjFN,OAAOU,WAAW,CAACG;QACnB;IACF;AACF;AAEA,OAAO,MAAMC,QAAQX,YAAY;IAAEY,eAAe;AAAM,GAAG;AAC3D,OAAO,MAAMC,UAAUb,YAAY;IAAEY,eAAe;AAAK,GAAG"}
|