@andy2639/jest-context 1.0.0 → 1.0.2
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/CHANGELOG.md +12 -0
- package/README.md +23 -1
- package/dist/bin/console-context.cjs +31 -8
- package/dist/bin/console-context.cjs.map +1 -1
- package/dist/bin/console-context.mjs +2 -2
- package/dist/bin/coverage-context.cjs +47 -30
- package/dist/bin/coverage-context.cjs.map +1 -1
- package/dist/bin/coverage-context.mjs +2 -2
- package/dist/bin/jest-context-init.cjs +142 -0
- package/dist/bin/jest-context-init.cjs.map +1 -0
- package/dist/bin/jest-context-init.d.mts +1 -0
- package/dist/bin/jest-context-init.d.ts +1 -0
- package/dist/bin/jest-context-init.mjs +14 -0
- package/dist/bin/jest-context-init.mjs.map +1 -0
- package/dist/bin/test-context.cjs +30 -7
- package/dist/bin/test-context.cjs.map +1 -1
- package/dist/bin/test-context.mjs +2 -2
- package/dist/{chunk-WPFTKCAT.mjs → chunk-5QGDUTB3.mjs} +4 -4
- package/dist/chunk-5QGDUTB3.mjs.map +1 -0
- package/dist/{chunk-YTFA3KPD.mjs → chunk-GV4AYRBZ.mjs} +43 -25
- package/dist/chunk-GV4AYRBZ.mjs.map +1 -0
- package/dist/{chunk-DUQBPBV4.mjs → chunk-RCPJ7B43.mjs} +4 -4
- package/dist/{chunk-DUQBPBV4.mjs.map → chunk-RCPJ7B43.mjs.map} +1 -1
- package/dist/chunk-UPBDVC5T.mjs +71 -0
- package/dist/chunk-UPBDVC5T.mjs.map +1 -0
- package/dist/{chunk-DEJBEL4M.mjs → chunk-WEP26C5H.mjs} +10 -11
- package/dist/chunk-WEP26C5H.mjs.map +1 -0
- package/dist/index.cjs +115 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +8 -4
- package/package.json +3 -3
- package/dist/chunk-DEJBEL4M.mjs.map +0 -1
- package/dist/chunk-WPFTKCAT.mjs.map +0 -1
- package/dist/chunk-YTFA3KPD.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JEST_PATTERNS,
|
|
3
|
-
|
|
3
|
+
createSpinner,
|
|
4
4
|
displayBanner,
|
|
5
5
|
displayHelp,
|
|
6
6
|
handleExportOrDisplay,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
runJest,
|
|
10
10
|
shouldShowUI,
|
|
11
11
|
validateCliArgs
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-GV4AYRBZ.mjs";
|
|
13
13
|
|
|
14
14
|
// src/commands/coverage-context.ts
|
|
15
15
|
import path from "path";
|
|
@@ -116,25 +116,24 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
116
116
|
const showUI = shouldShowUI(exportFormat, noBanner);
|
|
117
117
|
if (showUI) {
|
|
118
118
|
displayBanner({
|
|
119
|
-
text: "
|
|
119
|
+
text: "JEST",
|
|
120
|
+
subtitle: "COVERAGE",
|
|
120
121
|
info: {
|
|
121
122
|
Threshold: `>=${threshold}%`
|
|
122
123
|
},
|
|
123
124
|
colors: ["magenta", "blue"]
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
127
|
+
const spinner = showUI ? createSpinner("Running Jest coverage...", "magenta") : null;
|
|
128
|
+
spinner?.start();
|
|
128
129
|
const result = await runJest([], {
|
|
129
130
|
coverage: true,
|
|
130
131
|
coverageReporters: ["text", "text-summary"],
|
|
131
132
|
ignoreErrors: true
|
|
132
133
|
});
|
|
133
|
-
bar?.update(70, { status: "Parsing output..." });
|
|
134
134
|
const rows = parseCoverage(result.output);
|
|
135
135
|
if (rows.length === 0) {
|
|
136
|
-
|
|
137
|
-
bar?.stop();
|
|
136
|
+
spinner?.warn("No coverage rows parsed");
|
|
138
137
|
handleExportOrDisplay("No coverage rows parsed from Jest output.", {
|
|
139
138
|
exportFormat,
|
|
140
139
|
prefix: "export-coverage-context",
|
|
@@ -144,9 +143,8 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
144
143
|
}
|
|
145
144
|
const incomplete = filterIncomplete(rows, threshold);
|
|
146
145
|
const grouped = groupByFolder(incomplete);
|
|
147
|
-
bar?.update(100, { status: "Done" });
|
|
148
|
-
bar?.stop();
|
|
149
146
|
if (Object.keys(grouped).length === 0) {
|
|
147
|
+
spinner?.succeed(`All files meet threshold >= ${threshold}%`);
|
|
150
148
|
handleExportOrDisplay(`All files meet threshold >= ${threshold}%`, {
|
|
151
149
|
exportFormat,
|
|
152
150
|
prefix: "export-coverage-context",
|
|
@@ -155,6 +153,7 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
155
153
|
return;
|
|
156
154
|
}
|
|
157
155
|
const formatted = formatCoverageOutput(grouped);
|
|
156
|
+
spinner?.warn(`Found ${incomplete.length} file(s) below threshold`);
|
|
158
157
|
handleExportOrDisplay(formatted, {
|
|
159
158
|
exportFormat,
|
|
160
159
|
prefix: "export-coverage-context",
|
|
@@ -165,4 +164,4 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
165
164
|
export {
|
|
166
165
|
runCoverageContext
|
|
167
166
|
};
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
167
|
+
//# sourceMappingURL=chunk-WEP26C5H.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/coverage-context.ts"],"sourcesContent":["import path from \"node:path\";\n\nimport {\n createSpinner,\n displayBanner,\n displayHelp,\n exitWithError,\n handleExportOrDisplay,\n JEST_PATTERNS,\n parseExportCliArgs,\n runJest,\n shouldShowUI,\n validateCliArgs,\n logWarning,\n} from \"../core\";\n\nfunction parseCoverage(text: string) {\n const lines = text.split(\"\\n\");\n const rows: Array<{\n folder: string;\n file: string;\n stmts: number;\n branch: number;\n funcs: number;\n lines: number;\n uncovered?: string;\n }> = [];\n\n let currentFolder: string | null = null;\n\n for (const line of lines) {\n const match = line.match(JEST_PATTERNS.COVERAGE_LINE);\n if (!match) continue;\n\n const [, rawFile, stmts, branch, funcs, linesPct, uncovered] = match;\n const normalized = rawFile.trim();\n\n if (normalized === \"All files\") continue;\n\n const isFile = /\\.(ts|tsx)$/.test(normalized);\n if (!isFile) {\n currentFolder = normalized;\n continue;\n }\n\n if (/index\\.(ts|tsx)$/.test(normalized)) continue;\n if (!currentFolder) currentFolder = path.dirname(normalized);\n\n rows.push({\n folder: currentFolder,\n file: path.basename(normalized),\n stmts: Number(stmts),\n branch: Number(branch),\n funcs: Number(funcs),\n lines: Number(linesPct),\n uncovered: uncovered?.trim(),\n });\n }\n\n return rows;\n}\n\nfunction filterIncomplete(rows: ReturnType<typeof parseCoverage>, threshold = 100) {\n return rows.filter(\n (r) => !(r.stmts >= threshold && r.branch >= threshold && r.funcs >= threshold && r.lines >= threshold)\n );\n}\n\nfunction groupByFolder(rows: ReturnType<typeof parseCoverage>) {\n const grouped: Record<string, Array<{ file: string; coverage: Omit<(typeof rows)[number], \"folder\" | \"file\"> }>> = {};\n\n for (const row of rows) {\n const { folder, file, ...rest } = row;\n if (!grouped[folder]) grouped[folder] = [];\n grouped[folder].push({ file, coverage: rest });\n }\n\n return grouped;\n}\n\nfunction formatCoverageOutput(grouped: ReturnType<typeof groupByFolder>): string {\n let output = \"\";\n\n for (const folder of Object.keys(grouped)) {\n output += `📁 Folder: ${folder}\\n`;\n\n for (const item of grouped[folder]) {\n const { file, coverage } = item;\n output += ` 📄 File: ${file}\\n`;\n output += `- Coverage:\\n`;\n output += ` - Stmts: ${coverage.stmts}\\n`;\n output += ` - Branch: ${coverage.branch}\\n`;\n output += ` - Funcs: ${coverage.funcs}\\n`;\n output += ` - Lines: ${coverage.lines}\\n`;\n output += ` - Uncovered: ${coverage.uncovered || \"N/A\"}\\n\\n`;\n }\n\n output += \"\\n\";\n }\n\n return output.trim();\n}\n\nexport async function runCoverageContext(argv = process.argv.slice(2)): Promise<void> {\n if (argv.includes(\"-h\") || argv.includes(\"--help\")) {\n displayHelp(\"Coverage Context Script\", {\n description: \"Run Jest coverage and print files below threshold.\",\n usage: [\"coverage-context\", \"coverage-context --threshold=90\"],\n options: [\n \"--threshold=0..100 Minimum percentage for stmts/branch/funcs/lines (default: 100)\",\n \"--export Export output as txt\",\n \"--export=txt|md Export output in selected format\",\n \"--no-banner Disable fancy terminal UI\",\n \"-h, --help Show this help\",\n ],\n examples: [\"coverage-context --threshold=90 --export=md\"],\n });\n }\n\n const noBanner = argv.includes(\"--no-banner\");\n const args = argv.filter((arg) => arg !== \"--no-banner\");\n\n const { exportFormat, exportArgs } = parseExportCliArgs(args);\n const { parsed, unknownArgs } = validateCliArgs(args, {\n threshold: {\n prefix: \"--threshold=\",\n allowedValues: Array.from({ length: 101 }, (_, i) => String(i)),\n },\n });\n\n const exportArgSet = new Set(exportArgs);\n const filteredUnknownArgs = unknownArgs.filter((arg) => !exportArgSet.has(arg));\n if (filteredUnknownArgs.length > 0) {\n logWarning(`Unknown arguments ignored: ${filteredUnknownArgs.join(\", \")}`);\n }\n\n const threshold = parsed.threshold ? Number(parsed.threshold) : 100;\n const showUI = shouldShowUI(exportFormat, noBanner);\n\n if (showUI) {\n displayBanner({\n text: \"JEST\",\n subtitle: \"COVERAGE\",\n info: {\n Threshold: `>=${threshold}%`,\n },\n colors: [\"magenta\", \"blue\"],\n });\n }\n\n const spinner = showUI ? createSpinner(\"Running Jest coverage...\", \"magenta\") : null;\n spinner?.start();\n\n const result = await runJest([], {\n coverage: true,\n coverageReporters: [\"text\", \"text-summary\"],\n ignoreErrors: true,\n });\n\n const rows = parseCoverage(result.output);\n if (rows.length === 0) {\n spinner?.warn(\"No coverage rows parsed\");\n\n handleExportOrDisplay(\"No coverage rows parsed from Jest output.\", {\n exportFormat,\n prefix: \"export-coverage-context\",\n title: \"Coverage Context\",\n });\n\n return;\n }\n\n const incomplete = filterIncomplete(rows, threshold);\n const grouped = groupByFolder(incomplete);\n\n if (Object.keys(grouped).length === 0) {\n spinner?.succeed(`All files meet threshold >= ${threshold}%`);\n\n handleExportOrDisplay(`All files meet threshold >= ${threshold}%`, {\n exportFormat,\n prefix: \"export-coverage-context\",\n title: \"Coverage Context\",\n });\n\n return;\n }\n\n const formatted = formatCoverageOutput(grouped);\n spinner?.warn(`Found ${incomplete.length} file(s) below threshold`);\n\n handleExportOrDisplay(formatted, {\n exportFormat,\n prefix: \"export-coverage-context\",\n title: \"Coverage Context\",\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -69,6 +69,7 @@ __export(index_exports, {
|
|
|
69
69
|
resolveCommand: () => resolveCommand,
|
|
70
70
|
runConsoleContext: () => runConsoleContext,
|
|
71
71
|
runCoverageContext: () => runCoverageContext,
|
|
72
|
+
runInitContextScripts: () => runInitContextScripts,
|
|
72
73
|
runJest: () => runJest,
|
|
73
74
|
runTestContext: () => runTestContext,
|
|
74
75
|
shouldShowUI: () => shouldShowUI,
|
|
@@ -147,7 +148,7 @@ async function execCommand(cmd, args = [], options = {}) {
|
|
|
147
148
|
return new Promise((resolve, reject) => {
|
|
148
149
|
const resolvedCmd = resolveCommand(cmd);
|
|
149
150
|
const child = (0, import_node_child_process.spawn)(resolvedCmd, args, {
|
|
150
|
-
shell: options.shell ??
|
|
151
|
+
shell: options.shell ?? false
|
|
151
152
|
});
|
|
152
153
|
let stdout = "";
|
|
153
154
|
let stderr = "";
|
|
@@ -227,6 +228,7 @@ async function runJest(args = [], options = {}) {
|
|
|
227
228
|
disableVerbose = false
|
|
228
229
|
} = options;
|
|
229
230
|
const jestCmd = getJestCommand(packageManager);
|
|
231
|
+
const command = resolveCommand(jestCmd[0]);
|
|
230
232
|
const jestArgs = [...jestCmd.slice(1)];
|
|
231
233
|
if (verbose && !disableVerbose) {
|
|
232
234
|
jestArgs.push("--verbose");
|
|
@@ -244,8 +246,8 @@ async function runJest(args = [], options = {}) {
|
|
|
244
246
|
}
|
|
245
247
|
jestArgs.push(...args);
|
|
246
248
|
return new Promise((resolve, reject) => {
|
|
247
|
-
const child = (0, import_node_child_process2.spawn)(
|
|
248
|
-
shell:
|
|
249
|
+
const child = (0, import_node_child_process2.spawn)(command, jestArgs, {
|
|
250
|
+
shell: false
|
|
249
251
|
});
|
|
250
252
|
let stdout = "";
|
|
251
253
|
let stderr = "";
|
|
@@ -470,6 +472,14 @@ function logSuccess(message) {
|
|
|
470
472
|
}
|
|
471
473
|
|
|
472
474
|
// src/core/ui.ts
|
|
475
|
+
var NOOP_PROGRESS_BAR = {
|
|
476
|
+
update: () => {
|
|
477
|
+
},
|
|
478
|
+
stop: () => {
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
var hasWarnedSpinnerFallback = false;
|
|
482
|
+
var hasWarnedProgressFallback = false;
|
|
473
483
|
function shouldShowUI(exportMode, noBanner = false) {
|
|
474
484
|
return !exportMode && !noBanner && Boolean(process.stdout.isTTY);
|
|
475
485
|
}
|
|
@@ -515,29 +525,38 @@ function displayBanner(config) {
|
|
|
515
525
|
console.log(boxed);
|
|
516
526
|
}
|
|
517
527
|
function createSpinner(text, color = "cyan") {
|
|
518
|
-
|
|
519
|
-
|
|
528
|
+
try {
|
|
529
|
+
const ora = require("ora");
|
|
530
|
+
return ora({ text, color, spinner: "dots" });
|
|
531
|
+
} catch {
|
|
532
|
+
if (!hasWarnedSpinnerFallback) {
|
|
533
|
+
hasWarnedSpinnerFallback = true;
|
|
534
|
+
console.warn("Warning: spinner UI unavailable, continuing without spinner.");
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
start: () => NOOP_SPINNER,
|
|
538
|
+
stop: () => NOOP_SPINNER,
|
|
539
|
+
succeed: () => NOOP_SPINNER,
|
|
540
|
+
warn: () => NOOP_SPINNER,
|
|
541
|
+
fail: () => NOOP_SPINNER
|
|
542
|
+
};
|
|
543
|
+
}
|
|
520
544
|
}
|
|
545
|
+
var NOOP_SPINNER = {
|
|
546
|
+
start: () => NOOP_SPINNER,
|
|
547
|
+
stop: () => NOOP_SPINNER,
|
|
548
|
+
succeed: () => NOOP_SPINNER,
|
|
549
|
+
warn: () => NOOP_SPINNER,
|
|
550
|
+
fail: () => NOOP_SPINNER
|
|
551
|
+
};
|
|
521
552
|
function createProgressBar(total = 100, task = "Progress") {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
barsize: 24
|
|
530
|
-
},
|
|
531
|
-
cliProgress.Presets.shades_classic
|
|
532
|
-
);
|
|
533
|
-
bar.start(total, 0, {
|
|
534
|
-
task,
|
|
535
|
-
status: "Starting..."
|
|
536
|
-
});
|
|
537
|
-
return {
|
|
538
|
-
update: (value, payload) => bar.update(value, payload),
|
|
539
|
-
stop: () => bar.stop()
|
|
540
|
-
};
|
|
553
|
+
if (!hasWarnedProgressFallback) {
|
|
554
|
+
hasWarnedProgressFallback = true;
|
|
555
|
+
console.warn(
|
|
556
|
+
`Warning: progress bar UI is no longer used. Ignoring createProgressBar(${total}, ${JSON.stringify(task)}).`
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
return NOOP_PROGRESS_BAR;
|
|
541
560
|
}
|
|
542
561
|
|
|
543
562
|
// src/commands/test-context.ts
|
|
@@ -627,8 +646,8 @@ async function runTestContext(argv = process.argv.slice(2)) {
|
|
|
627
646
|
const showUI = shouldShowUI(exportFormat, noBanner);
|
|
628
647
|
if (showUI) {
|
|
629
648
|
displayBanner({
|
|
630
|
-
text: "
|
|
631
|
-
subtitle: "
|
|
649
|
+
text: "JEST",
|
|
650
|
+
subtitle: "TEST",
|
|
632
651
|
info: {
|
|
633
652
|
Mode: mode
|
|
634
653
|
},
|
|
@@ -792,25 +811,24 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
792
811
|
const showUI = shouldShowUI(exportFormat, noBanner);
|
|
793
812
|
if (showUI) {
|
|
794
813
|
displayBanner({
|
|
795
|
-
text: "
|
|
814
|
+
text: "JEST",
|
|
815
|
+
subtitle: "COVERAGE",
|
|
796
816
|
info: {
|
|
797
817
|
Threshold: `>=${threshold}%`
|
|
798
818
|
},
|
|
799
819
|
colors: ["magenta", "blue"]
|
|
800
820
|
});
|
|
801
821
|
}
|
|
802
|
-
const
|
|
803
|
-
|
|
822
|
+
const spinner = showUI ? createSpinner("Running Jest coverage...", "magenta") : null;
|
|
823
|
+
spinner?.start();
|
|
804
824
|
const result = await runJest([], {
|
|
805
825
|
coverage: true,
|
|
806
826
|
coverageReporters: ["text", "text-summary"],
|
|
807
827
|
ignoreErrors: true
|
|
808
828
|
});
|
|
809
|
-
bar?.update(70, { status: "Parsing output..." });
|
|
810
829
|
const rows = parseCoverage(result.output);
|
|
811
830
|
if (rows.length === 0) {
|
|
812
|
-
|
|
813
|
-
bar?.stop();
|
|
831
|
+
spinner?.warn("No coverage rows parsed");
|
|
814
832
|
handleExportOrDisplay("No coverage rows parsed from Jest output.", {
|
|
815
833
|
exportFormat,
|
|
816
834
|
prefix: "export-coverage-context",
|
|
@@ -820,9 +838,8 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
820
838
|
}
|
|
821
839
|
const incomplete = filterIncomplete(rows, threshold);
|
|
822
840
|
const grouped = groupByFolder(incomplete);
|
|
823
|
-
bar?.update(100, { status: "Done" });
|
|
824
|
-
bar?.stop();
|
|
825
841
|
if (Object.keys(grouped).length === 0) {
|
|
842
|
+
spinner?.succeed(`All files meet threshold >= ${threshold}%`);
|
|
826
843
|
handleExportOrDisplay(`All files meet threshold >= ${threshold}%`, {
|
|
827
844
|
exportFormat,
|
|
828
845
|
prefix: "export-coverage-context",
|
|
@@ -831,6 +848,7 @@ async function runCoverageContext(argv = process.argv.slice(2)) {
|
|
|
831
848
|
return;
|
|
832
849
|
}
|
|
833
850
|
const formatted = formatCoverageOutput(grouped);
|
|
851
|
+
spinner?.warn(`Found ${incomplete.length} file(s) below threshold`);
|
|
834
852
|
handleExportOrDisplay(formatted, {
|
|
835
853
|
exportFormat,
|
|
836
854
|
prefix: "export-coverage-context",
|
|
@@ -1021,8 +1039,8 @@ async function runConsoleContext(argv = process.argv.slice(2)) {
|
|
|
1021
1039
|
const showUI = shouldShowUI(exportFormat, noBanner);
|
|
1022
1040
|
if (showUI) {
|
|
1023
1041
|
displayBanner({
|
|
1024
|
-
text: "
|
|
1025
|
-
subtitle: "
|
|
1042
|
+
text: "JEST",
|
|
1043
|
+
subtitle: "CONSOLE",
|
|
1026
1044
|
info: {
|
|
1027
1045
|
Mode: mode,
|
|
1028
1046
|
Filter: filter ?? "none"
|
|
@@ -1062,6 +1080,66 @@ async function runConsoleContext(argv = process.argv.slice(2)) {
|
|
|
1062
1080
|
title: "Console Warnings Context"
|
|
1063
1081
|
});
|
|
1064
1082
|
}
|
|
1083
|
+
|
|
1084
|
+
// src/commands/init-context-scripts.ts
|
|
1085
|
+
var import_node_fs2 = require("fs");
|
|
1086
|
+
var import_node_path4 = __toESM(require("path"));
|
|
1087
|
+
var CONTEXT_SCRIPTS = {
|
|
1088
|
+
"console:context": "console-context",
|
|
1089
|
+
"coverage:context": "coverage-context",
|
|
1090
|
+
"test:context": "test-context"
|
|
1091
|
+
};
|
|
1092
|
+
function runInitContextScripts(argv = process.argv.slice(2)) {
|
|
1093
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
1094
|
+
displayHelp("Jest Context Init Script", {
|
|
1095
|
+
description: "Inject context scripts into package.json in the current project.",
|
|
1096
|
+
usage: ["jest-context-init", "jest-context-init --help"],
|
|
1097
|
+
options: ["-h, --help Show this help"],
|
|
1098
|
+
examples: ["npx jest-context-init", "pnpm dlx @andy2639/jest-context jest-context-init"]
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
const packageJsonPath = import_node_path4.default.resolve(process.cwd(), "package.json");
|
|
1102
|
+
let raw = "";
|
|
1103
|
+
try {
|
|
1104
|
+
raw = (0, import_node_fs2.readFileSync)(packageJsonPath, "utf-8");
|
|
1105
|
+
} catch {
|
|
1106
|
+
exitWithError(`Could not read package.json at: ${packageJsonPath}`);
|
|
1107
|
+
}
|
|
1108
|
+
let packageJson;
|
|
1109
|
+
try {
|
|
1110
|
+
packageJson = JSON.parse(raw);
|
|
1111
|
+
} catch {
|
|
1112
|
+
exitWithError(`Invalid JSON in package.json: ${packageJsonPath}`);
|
|
1113
|
+
}
|
|
1114
|
+
const scripts = packageJson.scripts && typeof packageJson.scripts === "object" ? { ...packageJson.scripts } : {};
|
|
1115
|
+
const added = [];
|
|
1116
|
+
const updated = [];
|
|
1117
|
+
for (const [name, value] of Object.entries(CONTEXT_SCRIPTS)) {
|
|
1118
|
+
if (!(name in scripts)) {
|
|
1119
|
+
scripts[name] = value;
|
|
1120
|
+
added.push(name);
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
if (scripts[name] !== value) {
|
|
1124
|
+
scripts[name] = value;
|
|
1125
|
+
updated.push(name);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
if (added.length === 0 && updated.length === 0) {
|
|
1129
|
+
logInfo("package.json already has the expected context scripts.");
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
packageJson.scripts = scripts;
|
|
1133
|
+
(0, import_node_fs2.writeFileSync)(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
|
|
1134
|
+
`, "utf-8");
|
|
1135
|
+
logSuccess(`Updated package.json scripts at: ${packageJsonPath}`);
|
|
1136
|
+
if (added.length > 0) {
|
|
1137
|
+
logInfo(`Added scripts: ${added.join(", ")}`);
|
|
1138
|
+
}
|
|
1139
|
+
if (updated.length > 0) {
|
|
1140
|
+
logInfo(`Updated scripts: ${updated.join(", ")}`);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1065
1143
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1066
1144
|
0 && (module.exports = {
|
|
1067
1145
|
CONSOLE_LOG_TYPES,
|
|
@@ -1103,6 +1181,7 @@ async function runConsoleContext(argv = process.argv.slice(2)) {
|
|
|
1103
1181
|
resolveCommand,
|
|
1104
1182
|
runConsoleContext,
|
|
1105
1183
|
runCoverageContext,
|
|
1184
|
+
runInitContextScripts,
|
|
1106
1185
|
runJest,
|
|
1107
1186
|
runTestContext,
|
|
1108
1187
|
shouldShowUI,
|