spec-controller 0.1.0-alpha.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -11
- package/dist/cli-allocate/cli.d.ts +2 -0
- package/dist/cli-allocate/cli.d.ts.map +1 -0
- package/dist/cli-allocate/cli.js +61 -0
- package/dist/cli-allocate/cli.js.map +1 -0
- package/dist/cli-allocate/readHistory.d.ts +14 -0
- package/dist/cli-allocate/readHistory.d.ts.map +1 -0
- package/dist/cli-allocate/readHistory.js +109 -0
- package/dist/cli-allocate/readHistory.js.map +1 -0
- package/dist/cli-allocate/readParts.d.ts +2 -0
- package/dist/cli-allocate/readParts.d.ts.map +1 -0
- package/dist/cli-allocate/readParts.js +23 -0
- package/dist/cli-allocate/readParts.js.map +1 -0
- package/dist/cli-allocate/readTree.d.ts +5 -0
- package/dist/cli-allocate/readTree.d.ts.map +1 -0
- package/dist/cli-allocate/readTree.js +74 -0
- package/dist/cli-allocate/readTree.js.map +1 -0
- package/dist/cli-allocate/refStore.d.ts +2 -0
- package/dist/cli-allocate/refStore.d.ts.map +1 -0
- package/dist/cli-allocate/refStore.js +35 -0
- package/dist/cli-allocate/refStore.js.map +1 -0
- package/dist/cli-allocate/request.d.ts +9 -0
- package/dist/cli-allocate/request.d.ts.map +1 -0
- package/dist/cli-allocate/request.js +23 -0
- package/dist/cli-allocate/request.js.map +1 -0
- package/dist/cli-allocate/stderr.d.ts +7 -0
- package/dist/cli-allocate/stderr.d.ts.map +1 -0
- package/dist/cli-allocate/stderr.js +32 -0
- package/dist/cli-allocate/stderr.js.map +1 -0
- package/dist/cli-allocate/unreadable.d.ts +13 -0
- package/dist/cli-allocate/unreadable.d.ts.map +1 -0
- package/dist/cli-allocate/unreadable.js +37 -0
- package/dist/cli-allocate/unreadable.js.map +1 -0
- package/dist/cli-args.d.ts +15 -70
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +167 -85
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-balance/cli.d.ts +1 -82
- package/dist/cli-balance/cli.d.ts.map +1 -1
- package/dist/cli-balance/cli.js +86 -397
- package/dist/cli-balance/cli.js.map +1 -1
- package/dist/cli-balance/emit/format.d.ts +18 -39
- package/dist/cli-balance/emit/format.d.ts.map +1 -1
- package/dist/cli-balance/emit/format.js +32 -63
- package/dist/cli-balance/emit/format.js.map +1 -1
- package/dist/cli-balance/emit/writer.d.ts +2 -34
- package/dist/cli-balance/emit/writer.d.ts.map +1 -1
- package/dist/cli-balance/emit/writer.js +62 -37
- package/dist/cli-balance/emit/writer.js.map +1 -1
- package/dist/cli-balance/exitStatus.d.ts +2 -0
- package/dist/cli-balance/exitStatus.d.ts.map +1 -0
- package/dist/cli-balance/exitStatus.js +5 -0
- package/dist/cli-balance/exitStatus.js.map +1 -0
- package/dist/cli-balance/inputsRead.d.ts +11 -0
- package/dist/cli-balance/inputsRead.d.ts.map +1 -0
- package/dist/cli-balance/inputsRead.js +51 -0
- package/dist/cli-balance/inputsRead.js.map +1 -0
- package/dist/cli-balance/reRender.d.ts +8 -0
- package/dist/cli-balance/reRender.d.ts.map +1 -0
- package/dist/cli-balance/reRender.js +21 -0
- package/dist/cli-balance/reRender.js.map +1 -0
- package/dist/cli-balance/unreadableInputs.d.ts +15 -0
- package/dist/cli-balance/unreadableInputs.d.ts.map +1 -0
- package/dist/cli-balance/unreadableInputs.js +100 -0
- package/dist/cli-balance/unreadableInputs.js.map +1 -0
- package/dist/cli-registry.d.ts +16 -71
- package/dist/cli-registry.d.ts.map +1 -1
- package/dist/cli-registry.js +71 -136
- package/dist/cli-registry.js.map +1 -1
- package/dist/cli.d.ts +0 -21
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -85
- package/dist/cli.js.map +1 -1
- package/dist/deferralTags.d.ts +0 -14
- package/dist/deferralTags.d.ts.map +1 -1
- package/dist/deferralTags.js +0 -14
- package/dist/deferralTags.js.map +1 -1
- package/dist/host.d.ts +10 -41
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +99 -50
- package/dist/host.js.map +1 -1
- package/dist/ingest/ciSourcePaths.d.ts +0 -39
- package/dist/ingest/ciSourcePaths.d.ts.map +1 -1
- package/dist/ingest/ciSourcePaths.js +1 -39
- package/dist/ingest/ciSourcePaths.js.map +1 -1
- package/dist/ingest/gherkinValidation.d.ts +0 -80
- package/dist/ingest/gherkinValidation.d.ts.map +1 -1
- package/dist/ingest/gherkinValidation.js +3 -82
- package/dist/ingest/gherkinValidation.js.map +1 -1
- package/dist/ingest/ingestQualityChecks.d.ts +8 -93
- package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
- package/dist/ingest/ingestQualityChecks.js +61 -224
- package/dist/ingest/ingestQualityChecks.js.map +1 -1
- package/dist/ingest/ingestScenarios.d.ts +5 -45
- package/dist/ingest/ingestScenarios.d.ts.map +1 -1
- package/dist/ingest/ingestScenarios.js +50 -118
- package/dist/ingest/ingestScenarios.js.map +1 -1
- package/dist/ingest/inputShapes.d.ts +16 -0
- package/dist/ingest/inputShapes.d.ts.map +1 -0
- package/dist/ingest/inputShapes.js +114 -0
- package/dist/ingest/inputShapes.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +93 -0
- package/dist/main.js.map +1 -0
- package/dist/messages.d.ts +223 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +319 -0
- package/dist/messages.js.map +1 -0
- package/dist/outputLocation.d.ts +23 -0
- package/dist/outputLocation.d.ts.map +1 -0
- package/dist/outputLocation.js +139 -0
- package/dist/outputLocation.js.map +1 -0
- package/dist/run-management/keptRun.d.ts +8 -109
- package/dist/run-management/keptRun.d.ts.map +1 -1
- package/dist/run-management/keptRun.js +49 -89
- package/dist/run-management/keptRun.js.map +1 -1
- package/dist/run-management/resolveRunInputs.d.ts +0 -67
- package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
- package/dist/run-management/resolveRunInputs.js +13 -117
- package/dist/run-management/resolveRunInputs.js.map +1 -1
- package/dist/storedRun.d.ts +6 -0
- package/dist/storedRun.d.ts.map +1 -0
- package/dist/storedRun.js +27 -0
- package/dist/storedRun.js.map +1 -0
- package/package.json +2 -2
- package/dist/corpus/cli.d.ts +0 -34
- package/dist/corpus/cli.d.ts.map +0 -1
- package/dist/corpus/cli.js +0 -125
- package/dist/corpus/cli.js.map +0 -1
package/README.md
CHANGED
|
@@ -11,17 +11,15 @@ Requires Node ≥ 22. ESM only.
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
npm install -g spec-controller
|
|
14
|
+
npm install -g spec-controller
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Or without installing anything:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
npx spec-controller
|
|
20
|
+
npx spec-controller balance --help
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
`@alpha` is not optional until `0.1.0` publishes: a bare install resolves `latest`, which npm set to `0.1.0-alpha.1` on the first publish, and that version has neither `tags` nor `--ci-steps`.
|
|
24
|
-
|
|
25
23
|
## Your first run
|
|
26
24
|
|
|
27
25
|
Point it at your scenarios and give it nothing else:
|
|
@@ -42,7 +40,7 @@ To bring it into a pipeline you already have without redding it on day one, add
|
|
|
42
40
|
spec-controller balance --features ./features --vitest ./vitest-report.json --exit-zero
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
The report is byte for byte the one the gate prints: the same rows, the same out-of-balance count, and the same headline naming the code the gate would give. Only the exit status moves. Out-of-balance (`1`) and pending under `--strict` (`3`) exit `0`. Usage (`2`), unsound (`4`) and nothing to reconcile (`5`) still fail, because each means the run could not give a verdict at all, and a flag that suppresses verdicts does not suppress that.
|
|
43
|
+
The report is byte for byte the one the gate prints: the same rows, the same out-of-balance count, and the same headline naming the code the gate would give. Only the exit status moves. Out-of-balance and scenario code errors (`1`), and pending under `--strict` (`3`), exit `0`. Usage (`2`), unsound (`4`) and nothing to reconcile (`5`) still fail, because each means the run could not give a verdict at all, and a flag that suppresses verdicts does not suppress that.
|
|
46
44
|
|
|
47
45
|
Work the out-of-balance rows down, then delete `--exit-zero`, and the gate is on. Don't wrap the step in `continue-on-error` or `|| true` instead: those swallow the codes that mean the run could not be trusted, and they leave nothing in the command to say the gate is off.
|
|
48
46
|
|
|
@@ -62,25 +60,35 @@ A scenario tagged `@unit` names an obligation — a unit test must exist and pas
|
|
|
62
60
|
| Exit | What it says |
|
|
63
61
|
| --- | --- |
|
|
64
62
|
| `0` | balanced — every obligation has evidence, and it holds |
|
|
65
|
-
| `1` | out-of-balance — the two records disagree, and the report says where |
|
|
63
|
+
| `1` | out-of-balance — the two records disagree, and the report says where; or a scenario code is misfiled, listed under `## Scenario code errors` |
|
|
66
64
|
| `2` | usage — the invocation was wrong |
|
|
67
65
|
| `3` | balanced, but carrying Pending Items, and you asked for `--strict` |
|
|
68
66
|
| `4` | unsound — a proving suite failed to collect, so the ledger could not be trusted to disagree |
|
|
69
|
-
| `5` | nothing to reconcile — no scenario was
|
|
67
|
+
| `5` | nothing to reconcile — no scenario was carried and no evidence was produced, so the run had no basis for a verdict |
|
|
70
68
|
|
|
71
69
|
The whole report is written before the code is set, so a failing run still tells you why.
|
|
72
70
|
|
|
71
|
+
`spec-controller allocate`, which prints the next scenario code for a feature part, reaches no verdict: it exits `0` when it answers and `2` for a usage error or an unknown part. A file or directory it cannot read, whether it reads it itself or through git, is a usage error: it is refused, naming the path and the reason, and no code is given.
|
|
72
|
+
|
|
73
73
|
`--exit-zero` moves `1` and `3` to `0` and leaves every other code alone: see *Report first, gate later*.
|
|
74
74
|
|
|
75
|
+
`balance --render-from-json <saved.json>` re-renders a saved report and exits the code its verdict names, from the same table: a saved run that failed fails again when it is read back. A report saved under `--strict` records it, so its re-render exits `3` too, and `--strict` or `--exit-zero` beside the re-render work as they do live. Any other flag beside it is refused at `2`, because a re-render reads no live input and writes only to stdout.
|
|
76
|
+
|
|
75
77
|
**Node's default is never one of these.** A run that cannot reconcile ends on an enumerated code of
|
|
76
78
|
its own rather than falling out of the process — a crash that exits `1` would be indistinguishable,
|
|
77
79
|
by status, from an honest disagreement. **An input the tool cannot read is part of `2`**: a mistyped
|
|
78
|
-
path,
|
|
79
|
-
|
|
80
|
+
path, a path it is not permitted to read, a file where a directory belongs or the reverse, an
|
|
81
|
+
unparseable report, a report that parses but is not in the shape its runner writes, a saved
|
|
82
|
+
reconciliation it cannot render, or a corpus the Gherkin parser rejects are all the invocation
|
|
83
|
+
being wrong, never a verdict about your code. The refusal names the input, the path, and what was
|
|
84
|
+
wrong with it. A well-formed report that holds nothing, such as a Vitest run that matched no test
|
|
85
|
+
file, is read, not refused. **So is an output location it cannot write**: a `--format` path that is
|
|
86
|
+
read-only, a directory, under a regular file or in a directory that does not exist, and a
|
|
87
|
+
`--store` root the run directory cannot be created under, are refused at `2`, naming the location and the operating system's reason, before any report is printed.
|
|
80
88
|
|
|
81
89
|
**The enumeration is open at the top, and that is the one thing to design your pipeline around.** A
|
|
82
90
|
state that is genuinely none of the above gets a **new** code rather than being folded into the
|
|
83
|
-
nearest one — `5` is the most recent, added when a run over a target that
|
|
91
|
+
nearest one — `5` is the most recent, added when a run over a target that carried no scenario and
|
|
84
92
|
produced nothing was found reporting `0`. So **treat an unrecognised non-zero code as a failure you
|
|
85
93
|
have not seen before**, not as a synonym for `1`. Matching `1` exactly is unaffected by a code being
|
|
86
94
|
added; treating *non-zero* as a red build is already correct, and only imprecise about why.
|
|
@@ -101,7 +109,6 @@ spec-controller balance --features ./features \
|
|
|
101
109
|
## Where to go next
|
|
102
110
|
|
|
103
111
|
- **Full flags, worked examples and CI wiring** — [`doc/how_to_use.md`](https://github.com/3f-consulting/spec-controller/blob/main/doc/how_to_use.md)
|
|
104
|
-
- **Bringing a check you already have under the reconciliation** — [`doc/converting-a-fitness-check.md`](https://github.com/3f-consulting/spec-controller/blob/main/doc/converting-a-fitness-check.md)
|
|
105
112
|
- **Why `0.x` promises nothing, and what changes at `1.0`** — [`doc/compatibility.md`](https://github.com/3f-consulting/spec-controller/blob/main/doc/compatibility.md)
|
|
106
113
|
- **Building your own tooling on the engine instead of running a command** — [`@3f-consulting/spec-controller-core`](https://www.npmjs.com/package/@3f-consulting/spec-controller-core), the same reconciliation logic as a pure library with no CLI and no I/O.
|
|
107
114
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/cli.ts"],"names":[],"mappings":"AAYA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAMhD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { nextScnCode } from "@3f-consulting/spec-controller-core";
|
|
3
|
+
import { allocateCommand, cliRegistry, renderCommandHelp } from "../cli-registry.js";
|
|
4
|
+
import { resolveToolIdentity } from "../run-management/resolveRunInputs.js";
|
|
5
|
+
import { readHeaderCodes } from "./readParts.js";
|
|
6
|
+
import { readRequest } from "./request.js";
|
|
7
|
+
import { AppMessage } from "../messages.js";
|
|
8
|
+
import { readOrRefuse, refusalLine, UnreadableInput } from "./unreadable.js";
|
|
9
|
+
import { historyBoundaryOf, readHistory, repositoryTop } from "./readHistory.js";
|
|
10
|
+
import { readTree, walkTree } from "./readTree.js";
|
|
11
|
+
import { alreadyHeadedNote, highestSeenLine, historyBoundaryLine, unknownPartRefusal } from "./stderr.js";
|
|
12
|
+
export function runAllocate(argv) {
|
|
13
|
+
if (asksForHelp(argv)) {
|
|
14
|
+
process.stdout.write(renderCommandHelp(allocateCommand) + "\n");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
answerOrRefuse(readRequest(argv, cliRegistry, resolveToolIdentity().toolVersion));
|
|
18
|
+
}
|
|
19
|
+
function asksForHelp(argv) {
|
|
20
|
+
return argv.includes("--help") || argv.includes("-h");
|
|
21
|
+
}
|
|
22
|
+
function answerOrRefuse(request) {
|
|
23
|
+
if ("usageError" in request) {
|
|
24
|
+
refuseUsage(request.usageError);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
answerRequest(request);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (!(err instanceof UnreadableInput))
|
|
32
|
+
throw err;
|
|
33
|
+
refuseUsage(refusalLine(err));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function refuseUsage(line) {
|
|
37
|
+
process.stderr.write(line + "\n");
|
|
38
|
+
process.exitCode = 2;
|
|
39
|
+
}
|
|
40
|
+
function answerRequest({ part, isNew }) {
|
|
41
|
+
const cwd = readOrRefuse(AppMessage.WorkingDirectory, "", () => process.cwd());
|
|
42
|
+
const top = repositoryTop(cwd);
|
|
43
|
+
const headerCodes = readHeaderCodes(join(top ?? cwd, "features"));
|
|
44
|
+
const answer = nextScnCode({ part, headerCodes, isNew }, occurrencesFrom(cwd, part, top));
|
|
45
|
+
if (answer.kind === "unknown-part") {
|
|
46
|
+
refuseUsage(unknownPartRefusal(answer));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
writeLineIfAny(historyBoundaryLine(historyBoundaryOf(cwd), answer));
|
|
50
|
+
process.stderr.write(highestSeenLine(answer) + "\n");
|
|
51
|
+
writeLineIfAny(alreadyHeadedNote(answer));
|
|
52
|
+
process.stdout.write(answer.code + "\n");
|
|
53
|
+
}
|
|
54
|
+
function writeLineIfAny(line) {
|
|
55
|
+
if (line !== null)
|
|
56
|
+
process.stderr.write(line + "\n");
|
|
57
|
+
}
|
|
58
|
+
function occurrencesFrom(cwd, part, top) {
|
|
59
|
+
return top !== null ? [...readTree(top, part), ...readHistory(cwd, part)] : walkTree(cwd, part);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli-allocate/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ScnOccurrence } from "@3f-consulting/spec-controller-core";
|
|
2
|
+
export type HistoryBoundary = {
|
|
3
|
+
kind: "complete";
|
|
4
|
+
} | {
|
|
5
|
+
kind: "not-a-repository";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "shallow";
|
|
8
|
+
before: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function readHistory(cwd: string, part: string): ScnOccurrence[];
|
|
11
|
+
export declare function repositoryTop(cwd: string): string | null;
|
|
12
|
+
export declare function historyBoundaryOf(cwd: string): HistoryBoundary;
|
|
13
|
+
export declare function diffLineOccurrences(logOutput: string): ScnOccurrence[];
|
|
14
|
+
//# sourceMappingURL=readHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readHistory.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/readHistory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAKzE,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAMxH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAStE;AAOD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOxD;AAcD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAI9D;AAuBD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAQtE"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { lstatSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { proveRefsReadable } from "./refStore.js";
|
|
5
|
+
import { APP_MESSAGES, AppMessage } from "../messages.js";
|
|
6
|
+
import { firstLine, readOrRefuse, refuse, UnreadableInput } from "./unreadable.js";
|
|
7
|
+
const MAX_OUTPUT_BYTES = 1024 * 1024 * 1024;
|
|
8
|
+
const COMMIT_MARKER = "\u0001";
|
|
9
|
+
export function readHistory(cwd, part) {
|
|
10
|
+
proveRefsReadable(cwd);
|
|
11
|
+
const args = ["log", "--all", "-p", "-U0", "--no-color", "--no-ext-diff", "--format=%x01%h", "-G", `SCN-${part}-`];
|
|
12
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT_BYTES });
|
|
13
|
+
if (result.error !== undefined)
|
|
14
|
+
refuse(AppMessage.History, cwd, result.error);
|
|
15
|
+
if (result.status !== 0) {
|
|
16
|
+
throw new UnreadableInput(AppMessage.History, cwd, APP_MESSAGES[AppMessage.GitExited](args, result.status, firstLine(result.stderr)));
|
|
17
|
+
}
|
|
18
|
+
return diffLineOccurrences(result.stdout);
|
|
19
|
+
}
|
|
20
|
+
function gitAnswer(cwd, args) {
|
|
21
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
22
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
23
|
+
}
|
|
24
|
+
export function repositoryTop(cwd) {
|
|
25
|
+
const args = ["rev-parse", "--show-toplevel"];
|
|
26
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
27
|
+
if (result.status === 0)
|
|
28
|
+
return result.stdout.trim();
|
|
29
|
+
const gitEntry = result.error === undefined ? gitEntryAtOrAbove(cwd) : null;
|
|
30
|
+
if (gitEntry === null)
|
|
31
|
+
return null;
|
|
32
|
+
throw new UnreadableInput(AppMessage.Repository, gitEntry, APP_MESSAGES[AppMessage.GitExited](args, result.status, firstLine(result.stderr)));
|
|
33
|
+
}
|
|
34
|
+
function gitEntryAtOrAbove(dir) {
|
|
35
|
+
for (let at = dir;; at = dirname(at)) {
|
|
36
|
+
const entry = join(at, ".git");
|
|
37
|
+
if (lstatSync(entry, { throwIfNoEntry: false }) !== undefined)
|
|
38
|
+
return entry;
|
|
39
|
+
if (dirname(at) === at)
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isGitRepository(cwd) {
|
|
44
|
+
return gitAnswer(cwd, ["rev-parse", "--git-dir"]) !== null;
|
|
45
|
+
}
|
|
46
|
+
export function historyBoundaryOf(cwd) {
|
|
47
|
+
if (!isGitRepository(cwd))
|
|
48
|
+
return { kind: "not-a-repository" };
|
|
49
|
+
if (gitAnswer(cwd, ["rev-parse", "--is-shallow-repository"]) !== "true")
|
|
50
|
+
return { kind: "complete" };
|
|
51
|
+
return shallowBoundaryOf(cwd);
|
|
52
|
+
}
|
|
53
|
+
function shallowBoundaryOf(cwd) {
|
|
54
|
+
const shallowPath = shallowRecordPath(cwd);
|
|
55
|
+
const record = readOrRefuse(AppMessage.History, shallowPath, () => readFileSync(shallowPath, "utf8"));
|
|
56
|
+
const edge = record.split("\n")[0] ?? "";
|
|
57
|
+
return { kind: "shallow", before: gitAnswer(cwd, ["rev-parse", "--short", edge]) ?? edge };
|
|
58
|
+
}
|
|
59
|
+
function shallowRecordPath(cwd) {
|
|
60
|
+
const shallowFile = gitAnswer(cwd, ["rev-parse", "--git-path", "shallow"]) ?? "";
|
|
61
|
+
return shallowFile.startsWith("/") ? shallowFile : `${cwd}/${shallowFile}`;
|
|
62
|
+
}
|
|
63
|
+
export function diffLineOccurrences(logOutput) {
|
|
64
|
+
const at = { inFileHeader: false, oldPath: "", newPath: "", oldLine: 0, newLine: 0 };
|
|
65
|
+
const occurrences = [];
|
|
66
|
+
for (const line of logOutput.split("\n")) {
|
|
67
|
+
const occurrence = readLine(line, at);
|
|
68
|
+
if (occurrence !== undefined)
|
|
69
|
+
occurrences.push(occurrence);
|
|
70
|
+
}
|
|
71
|
+
return occurrences;
|
|
72
|
+
}
|
|
73
|
+
function readLine(line, at) {
|
|
74
|
+
if (line.startsWith(COMMIT_MARKER))
|
|
75
|
+
at.commit = line.slice(COMMIT_MARKER.length);
|
|
76
|
+
else if (line.startsWith("diff --git "))
|
|
77
|
+
at.inFileHeader = true;
|
|
78
|
+
else if (at.inFileHeader)
|
|
79
|
+
readFileHeader(line, at);
|
|
80
|
+
else if (line.startsWith("-"))
|
|
81
|
+
return occurrenceAt(line, at.oldPath, at.oldLine++, at.commit);
|
|
82
|
+
else if (line.startsWith("+"))
|
|
83
|
+
return occurrenceAt(line, at.newPath, at.newLine++, at.commit);
|
|
84
|
+
else if (line.startsWith("@@ "))
|
|
85
|
+
readHunkHeader(line, at);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function readFileHeader(line, at) {
|
|
89
|
+
if (line.startsWith("--- "))
|
|
90
|
+
at.oldPath = pathOf(line);
|
|
91
|
+
else if (line.startsWith("+++ "))
|
|
92
|
+
at.newPath = pathOf(line);
|
|
93
|
+
else if (line.startsWith("@@ ")) {
|
|
94
|
+
at.inFileHeader = false;
|
|
95
|
+
readHunkHeader(line, at);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function pathOf(header) {
|
|
99
|
+
return header.slice(4).replace(/^[ab]\//, "");
|
|
100
|
+
}
|
|
101
|
+
function readHunkHeader(line, at) {
|
|
102
|
+
const match = /@@ -(\d+)(?:,\d+)? \+(\d+)/.exec(line);
|
|
103
|
+
at.oldLine = Number(match?.[1] ?? 0);
|
|
104
|
+
at.newLine = Number(match?.[2] ?? 0);
|
|
105
|
+
}
|
|
106
|
+
function occurrenceAt(text, path, line, commit) {
|
|
107
|
+
return { text, path, line, commit };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=readHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readHistory.js","sourceRoot":"","sources":["../../src/cli-allocate/readHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAInF,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,aAAa,GAAG,QAAQ,CAAC;AAE/B,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,IAAY;IACnD,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC;IACnH,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC9F,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,eAAe,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACxI,CAAC;IACD,OAAO,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,IAAuB;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,eAAe,CAAC,UAAU,CAAC,UAAU,EAAE,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChJ,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,KAAK,IAAI,EAAE,GAAG,GAAG,GAAI,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/B,IAAI,SAAS,CAAC,KAAK,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC5E,IAAI,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC/D,IAAI,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,yBAAyB,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACrG,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IACtG,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AAC7F,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;IACjF,OAAO,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;AAC7E,CAAC;AAWD,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,MAAM,EAAE,GAAkB,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACpG,MAAM,WAAW,GAAoB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,UAAU,KAAK,SAAS;YAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,EAAiB;IAC/C,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;SAC5E,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,EAAE,CAAC,YAAY,GAAG,IAAI,CAAC;SAC3D,IAAI,EAAE,CAAC,YAAY;QAAE,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;SAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;SACzF,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;SACzF,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,EAAiB;IACrD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,EAAE,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;SAClD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,EAAE,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;SACvD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,EAAE,CAAC,YAAY,GAAG,KAAK,CAAC;QACxB,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,MAAc;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,EAAiB;IACrD,MAAM,KAAK,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,EAAE,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,EAAE,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,MAA0B;IACxF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readParts.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/readParts.ts"],"names":[],"mappings":"AAMA,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAM7D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { extractFeatureCode } from "../ingest/ingestScenarios.js";
|
|
4
|
+
import { AppMessage } from "../messages.js";
|
|
5
|
+
import { readOrRefuse, refuse } from "./unreadable.js";
|
|
6
|
+
export function readHeaderCodes(featuresDir) {
|
|
7
|
+
return featureFilesIn(featuresDir).flatMap((name) => {
|
|
8
|
+
const path = join(featuresDir, name);
|
|
9
|
+
const code = extractFeatureCode(readOrRefuse(AppMessage.FeatureFile, path, () => readFileSync(path, "utf8")));
|
|
10
|
+
return code === null ? [] : [code];
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function featureFilesIn(dir) {
|
|
14
|
+
try {
|
|
15
|
+
return readdirSync(dir).filter((name) => name.endsWith(".feature"));
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
if (err.code === "ENOENT")
|
|
19
|
+
return [];
|
|
20
|
+
return refuse(AppMessage.FeatureCorpus, dir, err);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=readParts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readParts.js","sourceRoot":"","sources":["../../src/cli-allocate/readParts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,OAAO,cAAc,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,kBAAkB,CAAC,YAAY,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9G,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ScnOccurrence } from "@3f-consulting/spec-controller-core";
|
|
2
|
+
export declare function readTree(top: string, part: string): ScnOccurrence[];
|
|
3
|
+
export declare function isWalkedDirectory(name: string): boolean;
|
|
4
|
+
export declare function walkTree(root: string, part: string): ScnOccurrence[];
|
|
5
|
+
//# sourceMappingURL=readTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readTree.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/readTree.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAQzE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAKnE;AA6CD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAKpE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { accessSync, constants, lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join, relative, sep } from "node:path";
|
|
4
|
+
import { APP_MESSAGES, AppMessage } from "../messages.js";
|
|
5
|
+
import { firstLine, readOrRefuse, refuse, UnreadableInput } from "./unreadable.js";
|
|
6
|
+
const MAX_OUTPUT_BYTES = 1024 * 1024 * 1024;
|
|
7
|
+
const BINARY_PROBE_BYTES = 8000;
|
|
8
|
+
export function readTree(top, part) {
|
|
9
|
+
const listed = gitListing(top, ["ls-files", "-z", "--cached", "--others", "--exclude-standard"]);
|
|
10
|
+
const ignored = gitListing(top, ["ls-files", "-z", "--others", "--ignored", "--exclude-standard", "--directory"]);
|
|
11
|
+
proveListable(top, "", new Set(ignored.filter(isDirectoryEntry).map((entry) => entry.slice(0, -1))));
|
|
12
|
+
return listed.flatMap((path) => occurrencesInListed(top, path, `SCN-${part}-`));
|
|
13
|
+
}
|
|
14
|
+
function gitListing(top, args) {
|
|
15
|
+
const result = spawnSync("git", args, { cwd: top, encoding: "utf8", maxBuffer: MAX_OUTPUT_BYTES });
|
|
16
|
+
if (result.error !== undefined)
|
|
17
|
+
refuse(AppMessage.Tree, top, result.error);
|
|
18
|
+
if (result.status !== 0) {
|
|
19
|
+
throw new UnreadableInput(AppMessage.Tree, top, APP_MESSAGES[AppMessage.GitExited](args, result.status, firstLine(result.stderr)));
|
|
20
|
+
}
|
|
21
|
+
return result.stdout.split("\0");
|
|
22
|
+
}
|
|
23
|
+
function isDirectoryEntry(entry) {
|
|
24
|
+
return entry.endsWith("/");
|
|
25
|
+
}
|
|
26
|
+
function proveListable(top, dir, ignored) {
|
|
27
|
+
const path = join(top, dir);
|
|
28
|
+
const entries = readOrRefuse(AppMessage.TreeDirectory, path, () => listedAndEntered(path));
|
|
29
|
+
if (dir !== "" && entries.some((entry) => entry.name === ".git"))
|
|
30
|
+
return;
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const child = dir === "" ? entry.name : `${dir}/${entry.name}`;
|
|
33
|
+
if (entry.isDirectory() && entry.name !== ".git" && !ignored.has(child))
|
|
34
|
+
proveListable(top, child, ignored);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function listedAndEntered(path) {
|
|
38
|
+
accessSync(path, constants.R_OK | constants.X_OK);
|
|
39
|
+
return readdirSync(path, { withFileTypes: true });
|
|
40
|
+
}
|
|
41
|
+
function occurrencesInListed(top, path, needle) {
|
|
42
|
+
const file = join(top, path);
|
|
43
|
+
const kind = readOrRefuse(AppMessage.TreeFile, file, () => lstatSync(file, { throwIfNoEntry: false }));
|
|
44
|
+
if (kind === undefined || !kind.isFile())
|
|
45
|
+
return [];
|
|
46
|
+
return linesCarrying(path, readOrRefuse(AppMessage.TreeFile, file, () => readFileSync(file)), needle);
|
|
47
|
+
}
|
|
48
|
+
function linesCarrying(path, content, needle) {
|
|
49
|
+
if (content.subarray(0, BINARY_PROBE_BYTES).includes(0))
|
|
50
|
+
return [];
|
|
51
|
+
return content
|
|
52
|
+
.toString("utf8")
|
|
53
|
+
.split("\n")
|
|
54
|
+
.flatMap((line, i) => (line.includes(needle) ? [{ path, line: i + 1, text: line }] : []));
|
|
55
|
+
}
|
|
56
|
+
export function isWalkedDirectory(name) {
|
|
57
|
+
return name !== "node_modules" && !name.startsWith(".");
|
|
58
|
+
}
|
|
59
|
+
export function walkTree(root, part) {
|
|
60
|
+
return filesUnder(root).flatMap((file) => {
|
|
61
|
+
const content = readOrRefuse(AppMessage.TreeFile, file, () => readFileSync(file));
|
|
62
|
+
return linesCarrying(relative(root, file).split(sep).join("/"), content, `SCN-${part}-`);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function filesUnder(dir) {
|
|
66
|
+
const entries = readOrRefuse(AppMessage.TreeDirectory, dir, () => readdirSync(dir, { withFileTypes: true }));
|
|
67
|
+
return entries.flatMap((entry) => {
|
|
68
|
+
const path = join(dir, entry.name);
|
|
69
|
+
if (entry.isDirectory())
|
|
70
|
+
return isWalkedDirectory(entry.name) ? filesUnder(path) : [];
|
|
71
|
+
return entry.isFile() ? [path] : [];
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=readTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readTree.js","sourceRoot":"","sources":["../../src/cli-allocate/readTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refStore.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/refStore.ts"],"names":[],"mappings":"AAQA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAInD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { lstatSync, readdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { AppMessage } from "../messages.js";
|
|
5
|
+
import { readOrRefuse } from "./unreadable.js";
|
|
6
|
+
const REF_STORES = ["refs", "packed-refs", "reftable"];
|
|
7
|
+
export function proveRefsReadable(cwd) {
|
|
8
|
+
for (const gitDir of gitDirsOf(cwd)) {
|
|
9
|
+
for (const store of REF_STORES)
|
|
10
|
+
readEveryEntry(join(gitDir, store));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function gitDirsOf(cwd) {
|
|
14
|
+
const result = spawnSync("git", ["rev-parse", "--path-format=absolute", "--git-common-dir", "--git-dir"], {
|
|
15
|
+
cwd,
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
});
|
|
18
|
+
if (result.status !== 0)
|
|
19
|
+
return [];
|
|
20
|
+
return [...new Set(result.stdout.split("\n").filter((line) => line !== ""))];
|
|
21
|
+
}
|
|
22
|
+
function readEveryEntry(path) {
|
|
23
|
+
const kind = readOrRefuse(AppMessage.History, path, () => lstatSync(path, { throwIfNoEntry: false }));
|
|
24
|
+
if (kind === undefined)
|
|
25
|
+
return;
|
|
26
|
+
if (kind.isDirectory()) {
|
|
27
|
+
const names = readOrRefuse(AppMessage.History, path, () => readdirSync(path));
|
|
28
|
+
for (const name of names)
|
|
29
|
+
readEveryEntry(join(path, name));
|
|
30
|
+
}
|
|
31
|
+
else if (kind.isFile()) {
|
|
32
|
+
readOrRefuse(AppMessage.History, path, () => readFileSync(path));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=refStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refStore.js","sourceRoot":"","sources":["../../src/cli-allocate/refStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,CAAU,CAAC;AAEhE,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,KAAK,MAAM,MAAM,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,UAAU;YAAE,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,WAAW,CAAC,EAAE;QACxG,GAAG;QACH,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACtG,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9E,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;SAAM,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACzB,YAAY,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CliRegistry } from "../cli-registry.js";
|
|
2
|
+
export interface AllocateRequest {
|
|
3
|
+
readonly part: string;
|
|
4
|
+
readonly isNew: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function readRequest(argv: readonly string[], registry: CliRegistry, toolVersion: string): AllocateRequest | {
|
|
7
|
+
readonly usageError: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/request.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,QAAQ,EAAE,WAAW,EACrB,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAInD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isFeaturePart } from "@3f-consulting/spec-controller-core";
|
|
2
|
+
import { checkArgvShape, checkMisplacedHostModifiers, checkUnknownFlags, parseArgs, positionalArguments, } from "../cli-args.js";
|
|
3
|
+
import { APP_MESSAGES, AppMessage } from "../messages.js";
|
|
4
|
+
export function readRequest(argv, registry, toolVersion) {
|
|
5
|
+
const why = argvRefusal(argv, registry, toolVersion) ?? partRefusal(positionalArguments(argv, registry, "allocate")[0]);
|
|
6
|
+
if (why !== null)
|
|
7
|
+
return { usageError: APP_MESSAGES[AppMessage.UsageError]("allocate", why) };
|
|
8
|
+
return { part: positionalArguments(argv, registry, "allocate")[0] ?? "", isNew: argv.includes("--new") };
|
|
9
|
+
}
|
|
10
|
+
function argvRefusal(argv, registry, toolVersion) {
|
|
11
|
+
const args = parseArgs(argv);
|
|
12
|
+
return (checkMisplacedHostModifiers(args, registry, "allocate") ??
|
|
13
|
+
checkArgvShape(argv, registry, "allocate") ??
|
|
14
|
+
checkUnknownFlags(args, registry, "allocate", toolVersion));
|
|
15
|
+
}
|
|
16
|
+
function partRefusal(part) {
|
|
17
|
+
if (part === undefined)
|
|
18
|
+
return APP_MESSAGES[AppMessage.NoFeaturePartGiven]();
|
|
19
|
+
if (isFeaturePart(part))
|
|
20
|
+
return null;
|
|
21
|
+
return APP_MESSAGES[AppMessage.NotAFeaturePart](part);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/cli-allocate/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,iBAAiB,EACjB,SAAS,EACT,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAO1D,MAAM,UAAU,WAAW,CACzB,IAAuB,EACvB,QAAqB,EACrB,WAAmB;IAEnB,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,IAAI,WAAW,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxH,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;IAC9F,OAAO,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;AAC3G,CAAC;AAED,SAAS,WAAW,CAAC,IAAuB,EAAE,QAAqB,EAAE,WAAmB;IACtF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CACL,2BAA2B,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC;QACvD,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC;QAC1C,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAC3D,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAwB;IAC3C,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;IAC7E,IAAI,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Allocation, type UnknownPart } from "@3f-consulting/spec-controller-core";
|
|
2
|
+
import type { HistoryBoundary } from "./readHistory.js";
|
|
3
|
+
export declare function historyBoundaryLine(boundary: HistoryBoundary, allocation: Allocation): string | null;
|
|
4
|
+
export declare function highestSeenLine(allocation: Allocation): string;
|
|
5
|
+
export declare function unknownPartRefusal(refusal: UnknownPart): string;
|
|
6
|
+
export declare function alreadyHeadedNote(allocation: Allocation): string | null;
|
|
7
|
+
//# sourceMappingURL=stderr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stderr.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/stderr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAEvG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAWpG;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAO9D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAG/D;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAGvE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { featureCodeOf } from "@3f-consulting/spec-controller-core";
|
|
2
|
+
import { APP_MESSAGES, AppMessage } from "../messages.js";
|
|
3
|
+
export function historyBoundaryLine(boundary, allocation) {
|
|
4
|
+
if (boundary.kind === "complete")
|
|
5
|
+
return null;
|
|
6
|
+
const unread = boundary.kind === "shallow"
|
|
7
|
+
? APP_MESSAGES[AppMessage.ShallowHistoryUnread](boundary.before)
|
|
8
|
+
: APP_MESSAGES[AppMessage.NoRepositoryHistoryRead]();
|
|
9
|
+
const risk = allocation.highest === null
|
|
10
|
+
? APP_MESSAGES[AppMessage.RiskOfPartCode](featureCodeOf(allocation.code) ?? "")
|
|
11
|
+
: APP_MESSAGES[AppMessage.RiskAboveCode](allocation.highest.code);
|
|
12
|
+
return APP_MESSAGES[AppMessage.HistoryBoundary](unread, risk);
|
|
13
|
+
}
|
|
14
|
+
export function highestSeenLine(allocation) {
|
|
15
|
+
const highest = allocation.highest;
|
|
16
|
+
if (highest === null)
|
|
17
|
+
return APP_MESSAGES[AppMessage.HighestSeenNone]();
|
|
18
|
+
const { path, line, commit } = highest.occurrence;
|
|
19
|
+
return commit === undefined
|
|
20
|
+
? APP_MESSAGES[AppMessage.HighestSeenInTree](highest.code, path, line)
|
|
21
|
+
: APP_MESSAGES[AppMessage.HighestSeenInCommit](highest.code, path, line, commit);
|
|
22
|
+
}
|
|
23
|
+
export function unknownPartRefusal(refusal) {
|
|
24
|
+
const parts = refusal.headerCodes.length === 0 ? APP_MESSAGES[AppMessage.NoPartsCarried]() : refusal.headerCodes.join(", ");
|
|
25
|
+
return APP_MESSAGES[AppMessage.UnknownPartRefused](refusal.part, parts);
|
|
26
|
+
}
|
|
27
|
+
export function alreadyHeadedNote(allocation) {
|
|
28
|
+
if (allocation.alreadyHeaded !== true)
|
|
29
|
+
return null;
|
|
30
|
+
return APP_MESSAGES[AppMessage.PartAlreadyHeaded](featureCodeOf(allocation.code) ?? "");
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=stderr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stderr.js","sourceRoot":"","sources":["../../src/cli-allocate/stderr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAqC,MAAM,qCAAqC,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,UAAU,mBAAmB,CAAC,QAAyB,EAAE,UAAsB;IACnF,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC9C,MAAM,MAAM,GACV,QAAQ,CAAC,IAAI,KAAK,SAAS;QACzB,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAChE,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,CAAC;IACzD,MAAM,IAAI,GACR,UAAU,CAAC,OAAO,KAAK,IAAI;QACzB,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/E,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,OAAO,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAsB;IACpD,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;IACnC,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;IACxE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAClD,OAAO,MAAM,KAAK,SAAS;QACzB,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QACtE,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAoB;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5H,OAAO,YAAY,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,UAAsB;IACtD,IAAI,UAAU,CAAC,aAAa,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,YAAY,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Unreadable } from "../messages.js";
|
|
2
|
+
export declare class UnreadableInput extends Error {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly reason: string;
|
|
5
|
+
readonly name = "UnreadableInput";
|
|
6
|
+
readonly subject: string;
|
|
7
|
+
constructor(what: Unreadable, path: string, reason: string);
|
|
8
|
+
}
|
|
9
|
+
export declare function readOrRefuse<T>(what: Unreadable, path: string, read: () => T): T;
|
|
10
|
+
export declare function refuse(what: Unreadable, path: string, err: unknown): never;
|
|
11
|
+
export declare function refusalLine(refusal: UnreadableInput): string;
|
|
12
|
+
export declare function firstLine(text: string): string;
|
|
13
|
+
//# sourceMappingURL=unreadable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unreadable.d.ts","sourceRoot":"","sources":["../../src/cli-allocate/unreadable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEhG,qBAAa,eAAgB,SAAQ,KAAK;IAMtC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IANzB,SAAkB,IAAI,qBAAqB;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAGvB,IAAI,EAAE,UAAU,EACP,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAU1B;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAMhF;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,KAAK,CAI1E;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAE5D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|