halfcycle 0.4.5 → 0.4.7

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.
@@ -38,7 +38,7 @@
38
38
  * note. The service freezes both into the phase's Build Record; the caller fetches
39
39
  * that record afterwards (`build-record/obtain.ts`).
40
40
  */
41
- import { type AcceptanceOutcome, type PhaseCloseDecision } from '@halfcycle/events';
41
+ import { type AcceptanceOutcome, type MethodUpdate, type PhaseCloseDecision } from '@halfcycle/events';
42
42
  import { type PhaseStampFailure, type RepoCredential } from './open-phase.js';
43
43
  /**
44
44
  * Whether the commit this phase closed at could be read, and if so the full hash
@@ -76,6 +76,13 @@ export interface ClosedPhase {
76
76
  stampFailure: PhaseStampFailure | null;
77
77
  /** The commit sent with the close, or why none could be read. */
78
78
  closeCommit: CloseCommitOutcome;
79
+ /**
80
+ * The method version this close moved the project to (`existing-projects-carry-on`
81
+ * AC2), or `null` when it did not move. An older control's answer carries no
82
+ * field at all, which reads the same as `null` here — this CLI then prints
83
+ * and writes nothing about a move, exactly as it did before this field existed.
84
+ */
85
+ methodUpdated: MethodUpdate | null;
79
86
  }
80
87
  /**
81
88
  * Read the full HEAD commit of the NAMED repository, before the close is sent.
@@ -1 +1 @@
1
- {"version":3,"file":"close-phase.d.ts","sourceRoot":"","sources":["../src/close-phase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG/F;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa,EAAE,gBAAkE,CAAC;AAE/F,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvC,iEAAiE;IACjE,WAAW,EAAE,kBAAkB,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CA4BhF;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,MAAM,EAAE,MAAM;IAE9B;;;;;OAKG;aACa,OAAO,CAAC,EAAE,MAAM;IAChC;;;;;;;;;;OAUG;aACa,IAAI,CAAC,EAAE,MAAM;gBApBb,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;IACf;;;;;OAKG;IACa,OAAO,CAAC,EAAE,MAAM,YAAA;IAChC;;;;;;;;;;OAUG;IACa,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,cAAc,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,kBAAkB,EACzB,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,GAAE,gBAAgC,GACvC,OAAO,CAAC,WAAW,CAAC,CAyEtB"}
1
+ {"version":3,"file":"close-phase.d.ts","sourceRoot":"","sources":["../src/close-phase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG/F;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa,EAAE,gBAAkE,CAAC;AAE/F,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvC,iEAAiE;IACjE,WAAW,EAAE,kBAAkB,CAAC;IAChC;;;;;OAKG;IACH,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC;AAcD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CA4BhF;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,MAAM,EAAE,MAAM;IAE9B;;;;;OAKG;aACa,OAAO,CAAC,EAAE,MAAM;IAChC;;;;;;;;;;OAUG;aACa,IAAI,CAAC,EAAE,MAAM;gBApBb,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;IACf;;;;;OAKG;IACa,OAAO,CAAC,EAAE,MAAM,YAAA;IAChC;;;;;;;;;;OAUG;IACa,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,cAAc,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,kBAAkB,EACzB,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,GAAE,gBAAgC,GACvC,OAAO,CAAC,WAAW,CAAC,CAiFtB"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The client half of `npx halfcycle@latest draw architecture` (System view · E1,
3
+ * feature `diagram-files-for-docs`, AC1, AC4, AC5, AC6 and AC8's missing route) and of
4
+ * `draw phase <phase>` (System view · E2, feature `draw-phase-picture`, AC1 and AC5).
5
+ *
6
+ * THE ORDER IS THE SPEC'S. (1) read and check `docs/system.json`; for a phase, read and
7
+ * check its plan in the same stage's `beforeSend`, through `plan`'s own
8
+ * `readAndCheckPlan` (`../plan.ts`), never a copy of it; then the place and the files in
9
+ * the way; (2) report the description and get its version — both through `system`'s
10
+ * own first stage, `checkAndReportDescription` (`../system-report.ts`), never a copy of
11
+ * it; for a phase, then report the plan through `DrawDeps.reportPlan`, `plan`'s own
12
+ * request (`reportPhasePlan`), sending the very plan `beforeSend` checked, never a
13
+ * second read of the file; (3) ask the service to draw that version; (4) check all five
14
+ * files, every look's picture and the Mermaid, then write them; (5) print the
15
+ * Markdown, whose image line is the embedded look's PNG (`embedImageLink`,
16
+ * `./write.ts`, composed from the same table as that file's path). The place and the
17
+ * files already there are checked on the machine before anything is sent, and again
18
+ * just before writing, so a refusal this command can make locally never costs a
19
+ * request, and a change made while it waited is still seen.
20
+ *
21
+ * A PHASE'S FILES. The base name is `phaseDiagramBase(phase)`, `renderPhaseSegment`'s
22
+ * segment. A phase that is not a valid identity is refused naming it, before anything
23
+ * is read; so is one whose base name ends in the Flight Deck word, in any case, whose
24
+ * Broadsheet files would take another phase's Flight Deck names.
25
+ *
26
+ * ONE RESPONSE-HANDLING RULE, the Build Record path's. A body that parses under
27
+ * `systemDrawResultSchema` (`@halfcycle/events`, the one home of the shape) is
28
+ * authoritative, whatever its status. Otherwise the service's missing-route answer to
29
+ * this POST means it predates drawing — asked of `isMissingRoute`
30
+ * (`../missing-route.ts`), the one predicate, never a copy of its expression; a
31
+ * missing report route says the same, because either way this service cannot draw.
32
+ * For a phase, the plan route and the draw route's phase arm ship in one service
33
+ * release, so a missing plan route is the one signal that this service cannot draw
34
+ * phase pictures, and the draw route is then never asked. Anything else is reported by
35
+ * its status and the service's own sentence.
36
+ *
37
+ * NO BYTE OF THE RESPONSE DECIDES A PATH (INV-023): the response gives contents only;
38
+ * where they go is `./write.ts`'s constants and the base name this module chose from
39
+ * the arguments.
40
+ *
41
+ * WHAT LEAVES THE MACHINE. The checked description (through the shared stage); for a
42
+ * phase, the checked plan (through `plan`'s request); then only the draw request,
43
+ * `{ version, picture: 'architecture' }` or `{ picture: 'phase', phase, planVersion }`.
44
+ *
45
+ * INV-001: Node builtins, the global `fetch`, `@halfcycle/events` and `@halfcycle/core`
46
+ * only. SHIPS TO CLIENT DISK inside the CLI: every string here is a sentence a person
47
+ * reads, so none names an internal register, route or setting; no comment sits beside
48
+ * an object member.
49
+ */
50
+ import { type SystemDrawDrawn, type SystemDrawRequest } from '@halfcycle/events';
51
+ import type { RepoCredential } from '../open-phase.js';
52
+ import { type PlanDeps } from '../plan.js';
53
+ import { type SystemDeps, type SystemRun } from '../system-report.js';
54
+ import { type DiagramBaseName, type DiagramSet, type DiagramWriteResult, type EmbeddingDoc } from './write.js';
55
+ export { ARCHITECTURE_BASE, ARCHITECTURE_NAME, DIAGRAM_DIR_REL, DIAGRAM_FILES, DIAGRAM_MARKER_LINE, EMBEDDED_LOOK, baseTakesFlightDeckNames, checkPictures, diagramRel, embedImageLink, embedImageName, markdownLinkName, phaseDiagramBase, pictureNames, pngOf, svgOf, diagramPaths, writeDiagramSet, type DiagramBaseName, } from './write.js';
56
+ /** The usage line, printed for anything but `architecture` or `phase <phase>`. */
57
+ export declare const DRAW_USAGE = "npx halfcycle@latest draw (architecture | phase <phase>) [--repo <root>]";
58
+ /** Which picture: the whole system's, or one phase's plan on it. */
59
+ export type DrawPicture = {
60
+ kind: 'architecture';
61
+ } | {
62
+ kind: 'phase';
63
+ phase: string;
64
+ };
65
+ /**
66
+ * What the arguments after `draw` came to: the picture and the repository root to work
67
+ * in, or usage. `architecture` alone, or `phase` followed by exactly one phase, plus at
68
+ * most one `--repo <root>`; anything else, including no argument and `phase` with no
69
+ * name, is usage. The phase is not checked here: a name that cannot be a phase is the
70
+ * verb's to refuse, by name.
71
+ */
72
+ export type DrawArgs = {
73
+ ok: true;
74
+ picture: DrawPicture;
75
+ repoRoot: string | undefined;
76
+ } | {
77
+ ok: false;
78
+ };
79
+ export declare function parseDrawArgs(argv: readonly string[]): DrawArgs;
80
+ /**
81
+ * What came of asking for the drawing. `drawn`: the Mermaid and every look's picture,
82
+ * parsed under the strict result schema (so no look is missing and none is extra) but
83
+ * not yet checked. `refused`: the service's reason. `no-route`: this service cannot draw yet.
84
+ * `unavailable`: it could not be drawn, and `why` says so.
85
+ */
86
+ export type DrawOutcome = {
87
+ kind: 'drawn';
88
+ drawn: SystemDrawDrawn;
89
+ } | {
90
+ kind: 'refused';
91
+ reason: string;
92
+ } | {
93
+ kind: 'no-route';
94
+ } | {
95
+ kind: 'unavailable';
96
+ why: string;
97
+ };
98
+ /** The address the drawing is asked of: the engagement is one path segment, encoded once. */
99
+ export declare function systemDrawUrl(credential: RepoCredential): string;
100
+ /**
101
+ * Ask the service to draw the picture `request` names. Never throws: the network, the
102
+ * service and an answer this CLI cannot read are each an outcome the caller prints.
103
+ */
104
+ export declare function requestDrawing(credential: RepoCredential, request: SystemDrawRequest): Promise<DrawOutcome>;
105
+ /**
106
+ * The pieces `runDraw` reaches outside itself through; replaced in tests. `reportPlan`
107
+ * is `plan`'s own request, used only for a phase.
108
+ */
109
+ export interface DrawDeps extends SystemDeps {
110
+ readonly reportPlan: PlanDeps['reportPlan'];
111
+ readonly draw: (credential: RepoCredential, request: SystemDrawRequest) => Promise<DrawOutcome>;
112
+ readonly write: (repoRoot: string, base: DiagramBaseName, set: DiagramSet) => DiagramWriteResult;
113
+ }
114
+ /**
115
+ * What a picture is pasted as: the document it goes in, and the image's alt text.
116
+ * The architecture's goes directly under `docs/`; a phase's in its own document in
117
+ * `docs/phases/`.
118
+ */
119
+ export type PasteTarget = {
120
+ doc: EmbeddingDoc;
121
+ alt: string;
122
+ base: DiagramBaseName;
123
+ };
124
+ /** The architecture's paste target. */
125
+ export declare const ARCHITECTURE_PASTE: PasteTarget;
126
+ /** A phase's paste target: `Phase <name>`, in `docs/phases/`. */
127
+ export declare function phasePaste(phase: string): PasteTarget;
128
+ /** The Markdown to paste into the document `target` names, and the line before it. */
129
+ export declare function pasteLines(mermaid: string, target: PasteTarget): string;
130
+ /**
131
+ * The whole verb, in the order the module header gives. Exit 0 only when the five
132
+ * files are written or already up to date and the Markdown is printed.
133
+ */
134
+ export declare function runDraw(repoRoot: string, picture: DrawPicture, deps: DrawDeps): Promise<SystemRun>;
135
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/draw/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * The pictures writer — what `draw architecture` and `draw phase` write into the
3
+ * person's repository (System view · E1, feature `diagram-files-for-docs`, AC4, AC5,
4
+ * AC6 and the "someone else's file in the way" behaviour; widened to a base name by
5
+ * E2, feature `draw-phase-picture` AC5).
6
+ *
7
+ * NO BYTE OF THE RESPONSE DECIDES A PATH (INV-023). Every path here is composed from
8
+ * `repoRoot` (the caller's `--repo` or the working directory), the constant directory
9
+ * `docs/diagrams` and a BASE NAME with a constant extension. A base name is a
10
+ * `DiagramBaseName`, and only two things make one: `ARCHITECTURE_BASE` (the constant
11
+ * `architecture`) and `phaseDiagramBase(phase)` (`renderPhaseSegment`'s segment, the
12
+ * one home of a phase's file segment). The type is branded, so a string from anywhere
13
+ * else, a response included, does not compile where a base name is asked for. The
14
+ * response contributes file CONTENTS only; nothing in it is ever joined, resolved or
15
+ * compared as a path. `DiagramPaths` is built by `diagramPaths(repoRoot, base)` alone.
16
+ *
17
+ * Every rule below is stated for the architecture's names, which are the base name
18
+ * `architecture`; a phase's are the same with its base name in their place.
19
+ *
20
+ * FIVE FILES, ONE TABLE. Each look in `SYSTEM_PICTURE_THEMES` (`@halfcycle/events`, the
21
+ * one list of looks) has a PNG and an SVG; the Mermaid is one file, because Mermaid has
22
+ * no look. A look selects its file name from `pictureNames(base)`, a table typed against
23
+ * `SystemPictureTheme`, so a look the list does not hold has no name and the compiler
24
+ * refuses a look the table forgets. The looks are iterated from the list, never from
25
+ * the response's keys: the strict result schema already refused any other key, and
26
+ * this module would not read one if it came. Which look documents embed is
27
+ * `EMBEDDED_LOOK`, and only there: the printed image line (`embedImageLink`) is
28
+ * composed from the same file-name table as that look's path, so the line and the file
29
+ * cannot name different pictures.
30
+ *
31
+ * THE REALPATH CHECK (AC5). Before anything is made or written, the realpath of the
32
+ * nearest existing ancestor of `docs/diagrams` must lie inside the realpath of the
33
+ * repository. "Exists" is asked with `lstat`, so a dangling link is the ancestor and
34
+ * its failed realpath refuses, rather than being stepped over as absent. A planted
35
+ * `docs` link pointing out of the repository therefore refuses before `mkdir`. The
36
+ * same check runs again on `docs/diagrams` itself after `mkdir`, before the first file
37
+ * is created, so a directory made through a link cannot be written into. RESIDUAL: a
38
+ * process racing this one, swapping a directory for a link between that second check
39
+ * and a rename, is not closed by a userspace check; the window is a few syscalls.
40
+ *
41
+ * IN THE WAY (the spec's ownership rule). The command writes only files it recognises
42
+ * as its own: an SVG whose first line is the marker. Any SVG without the marker is
43
+ * named and nothing is written. Each PNG is ours only beside ITS OWN marked SVG
44
+ * (`architecture.png` with `architecture.svg`, `architecture.flightdeck.png` with
45
+ * `architecture.flightdeck.svg`), never another look's. The Mermaid file is ours only
46
+ * beside the embedded look's marked SVG, `architecture.svg`, the one whose name it
47
+ * shares. Anything at one of the five paths that is not a regular file (a link, a
48
+ * folder) is in the way too: replacing a link would silently turn it into a file, and
49
+ * following one would write somewhere this check never looked.
50
+ *
51
+ * LEFTOVER TEMPORARIES, BY THE SAME RULE. A run that dies (killed, power cut) between
52
+ * staging and its last rename leaves `<name>.tmp` files with no chance to clear them.
53
+ * Each one is judged by the rule its final file is judged by, one rule for both: an
54
+ * SVG temporary is ours if its first line is the marker; a PNG temporary is ours only
55
+ * beside its own look's marked SVG, at the final path or as that SVG's own marked
56
+ * temporary; the Mermaid temporary likewise only beside the embedded look's marked SVG
57
+ * or its marked temporary. Anything else at a temporary path (a person's own file,
58
+ * unmarked or unpaired, or anything that is not a regular file) is in the way, named,
59
+ * and never deleted. Ours are removed just before staging, so the exclusive create
60
+ * below never meets one and never has to delete a file it did not create. They are
61
+ * not removed on an up-to-date run, which touches no file (AC6); a dead run's
62
+ * temporaries always sit beside a final file that differs from them, so the same
63
+ * description run again is never up to date while they remain. RESIDUAL: a death
64
+ * between the create and the first byte written leaves an empty SVG temporary, which
65
+ * carries no marker and so is named as in the way; the window is one syscall.
66
+ *
67
+ * ALL OR NOTHING (AC4). Every check on the five files runs before any file is touched.
68
+ * Then each changed file is written to `<name>.tmp` beside it, every temporary first,
69
+ * and renamed into place one by one. If a rename fails, every file already renamed
70
+ * gets its previous bytes back, or is removed if it did not exist before; a file that
71
+ * cannot be put back is removed and named. The SVGs are renamed FIRST on purpose, then
72
+ * the PNGs, then the Mermaid (`DIAGRAM_FILES`'s order), and every SVG temporary is
73
+ * staged before any PNG or Mermaid one: if the process dies at any point, every PNG
74
+ * and Mermaid file or temporary it left has its owning marked SVG (final or temporary)
75
+ * already there, so the next run recognises all of it as its own, clears the
76
+ * temporaries and writes.
77
+ *
78
+ * UP TO DATE (AC6). Each of the five files' bytes is compared with the new bytes first,
79
+ * and an equal file is not written at all, so an unchanged description leaves every
80
+ * modification time as it was.
81
+ *
82
+ * ONE SEAM. The file operations go through `RecordPairIo`, the Build Record writer's
83
+ * seam (`../build-record/write.ts`), widened to take bytes, so the exclusive create
84
+ * has one implementation and a test can fail any one rename.
85
+ *
86
+ * INV-001: Node builtins, `@halfcycle/events` and this package only. SHIPS TO CLIENT
87
+ * DISK inside the CLI: every string here is a sentence a person reads, and no comment
88
+ * sits beside an object member.
89
+ */
90
+ import { type PhaseIdentity, type SystemDrawDrawn, type SystemPictureTheme } from '@halfcycle/events';
91
+ import { type RecordPairIo } from '../build-record/write.js';
92
+ /** The one directory the pictures go in, relative to the repository root, `/`-separated. */
93
+ export declare const DIAGRAM_DIR_REL = "docs/diagrams";
94
+ /** The architecture picture's name; also its Mermaid file's name. */
95
+ export declare const ARCHITECTURE_NAME = "architecture";
96
+ declare const diagramBaseBrand: unique symbol;
97
+ /**
98
+ * The name a set of five files is built from. Branded so only the two makers below
99
+ * produce one: a plain string, a response's included, is a compile error where a base
100
+ * name is asked for (INV-023).
101
+ */
102
+ export type DiagramBaseName = string & {
103
+ readonly [diagramBaseBrand]: true;
104
+ };
105
+ /** The architecture's base name. */
106
+ export declare const ARCHITECTURE_BASE: DiagramBaseName;
107
+ /**
108
+ * A phase's base name: `renderPhaseSegment(phase)`, so `notifications` gives
109
+ * `phase-notifications`. Throws on an invalid identity, as that function does; the
110
+ * verb checks the identity first and reports it rather than throwing.
111
+ */
112
+ export declare function phaseDiagramBase(phase: PhaseIdentity): DiagramBaseName;
113
+ /**
114
+ * Would this base name's Broadsheet files take another set's Flight Deck names?
115
+ * `phase-a.flightdeck.png` is phase `a`'s Flight Deck picture, so a base name ending in
116
+ * the Flight Deck word, in any case (a case-insensitive file system would collide
117
+ * too), is refused before anything is sent.
118
+ */
119
+ export declare function baseTakesFlightDeckNames(base: DiagramBaseName): boolean;
120
+ /**
121
+ * Each look's file name, before its extension: Broadsheet takes the bare base name,
122
+ * Flight Deck the base name with its look after it. Typed against the one list of
123
+ * looks, so the table cannot hold a look the list does not, or miss one it does.
124
+ */
125
+ export declare function pictureNames(base: DiagramBaseName): Readonly<Record<SystemPictureTheme, string>>;
126
+ /**
127
+ * The look documents embed, and the only place that choice is made. Its PNG is the
128
+ * printed image line, and its SVG is the one the Mermaid file sits beside.
129
+ */
130
+ export declare const EMBEDDED_LOOK: SystemPictureTheme;
131
+ /**
132
+ * The first line of every SVG this command writes, and the only thing that makes an
133
+ * existing SVG ours. The service prepends it; the CLI checks it before writing and
134
+ * reads it on the next run. Its one home is the description contract.
135
+ */
136
+ export declare const DIAGRAM_MARKER_LINE = "<!-- drawn by Halfcycle from docs/system.json -->";
137
+ /** One look's SVG or PNG. */
138
+ export type PictureFile = `${SystemPictureTheme}.svg` | `${SystemPictureTheme}.png`;
139
+ /** Which of the five files: a look's SVG or PNG, or the one Mermaid file. */
140
+ export type DiagramFile = PictureFile | 'mmd';
141
+ /** A look's SVG. */
142
+ export declare function svgOf(look: SystemPictureTheme): PictureFile;
143
+ /** A look's PNG. */
144
+ export declare function pngOf(look: SystemPictureTheme): PictureFile;
145
+ /**
146
+ * The five files, in the order they are renamed: every SVG, then every PNG, then the
147
+ * Mermaid, as the module header says why.
148
+ */
149
+ export declare const DIAGRAM_FILES: readonly DiagramFile[];
150
+ /**
151
+ * The embedded picture's file name in `docs/diagrams`: `architecture.png`. Composed
152
+ * from the same table as that file's path, so the printed image line and the file
153
+ * cannot name different pictures.
154
+ */
155
+ export declare function embedImageName(base: DiagramBaseName): string;
156
+ /**
157
+ * Where the document the picture is pasted into sits: directly under `docs/` (the
158
+ * architecture's), or in `docs/phases/` (a phase's).
159
+ */
160
+ export type EmbeddingDoc = 'docs' | 'docs/phases';
161
+ /**
162
+ * A file name as a Markdown link target: percent-encoded (`encodeURIComponent`), and
163
+ * `(` and `)` too, which would otherwise end the link.
164
+ */
165
+ export declare function markdownLinkName(name: string): string;
166
+ /**
167
+ * The embedded picture as a document at `doc` links it: `diagrams/architecture.png`
168
+ * from `docs/`, `../diagrams/phase-notifications.png` from `docs/phases/`. The file
169
+ * name is the one `embedImageName` gives, encoded for a link.
170
+ */
171
+ export declare function embedImageLink(base: DiagramBaseName, doc: EmbeddingDoc): string;
172
+ /** The fixed paths, composed from `repoRoot` and constants only. */
173
+ export interface DiagramPaths {
174
+ readonly repoRoot: string;
175
+ readonly dir: string;
176
+ readonly file: Readonly<Record<DiagramFile, string>>;
177
+ }
178
+ export declare function diagramPaths(repoRoot: string, base: DiagramBaseName): DiagramPaths;
179
+ /** A file's place as a person finds it: `docs/diagrams/architecture.svg`. */
180
+ export declare function diagramRel(base: DiagramBaseName, which: DiagramFile): string;
181
+ /**
182
+ * The five files in the order a person reads them: each look's PNG then its SVG, then
183
+ * the Mermaid file.
184
+ */
185
+ export declare const DIAGRAM_FILES_AS_LISTED: readonly DiagramFile[];
186
+ /** `a`, `a and b`, `a, b and c`: a list as a sentence says it. */
187
+ export declare function spokenList(items: readonly string[]): string;
188
+ /**
189
+ * What the place the pictures go came to. `ok`: safe to write there. Otherwise the
190
+ * sentence to print, already naming the remedy.
191
+ */
192
+ export type PlaceCheck = {
193
+ ok: true;
194
+ } | {
195
+ ok: false;
196
+ why: string;
197
+ };
198
+ /**
199
+ * THE REALPATH CHECK (AC5), as the module header states it: the nearest ancestor of
200
+ * `docs/diagrams` that `lstat` finds must resolve inside the repository and be a
201
+ * folder. Run before anything is sent and again before anything is made.
202
+ */
203
+ export declare function checkDiagramPlace(paths: DiagramPaths): PlaceCheck;
204
+ /** What is at the five paths now. `null`: nothing. Bytes: a regular file's contents. */
205
+ export type ExistingSet = Readonly<Record<DiagramFile, Uint8Array | null>>;
206
+ /**
207
+ * What reading the existing set came to: the set and which leftover temporaries are
208
+ * ours to clear, or the first file in the way (`temp`: the temporary beside it).
209
+ */
210
+ export type ExistingRead = {
211
+ ok: true;
212
+ existing: ExistingSet;
213
+ ourTemps: readonly DiagramFile[];
214
+ } | {
215
+ ok: false;
216
+ inTheWay: DiagramFile;
217
+ temp: boolean;
218
+ };
219
+ /**
220
+ * Read what is at the five paths and at their five temporaries, and apply the one
221
+ * ownership rule to both, as the module header states it. The final files are judged
222
+ * first, in the order that names the deciding file: every SVG, then each PNG against
223
+ * its own look's SVG, then the Mermaid file against the embedded look's SVG. Then the
224
+ * temporaries in the same order, where a PNG or Mermaid temporary's owner may be the
225
+ * marked SVG at its final path or that SVG's own marked temporary. Anything that is not
226
+ * a regular file, final or temporary, is in the way.
227
+ */
228
+ export declare function readExistingSet(paths: DiagramPaths): ExistingRead;
229
+ /** The sentence for a file in the way, or for the temporary file beside it when `temp`. */
230
+ export declare function inTheWayLine(base: DiagramBaseName, which: DiagramFile, temp?: boolean): string;
231
+ /** The five files as bytes, checked and ready to write. */
232
+ export type DiagramSet = Readonly<Record<DiagramFile, Uint8Array>>;
233
+ /** What checking the drawn pictures came to: the bytes, or what was wrong, in plain words. */
234
+ export type PictureCheck = {
235
+ ok: true;
236
+ set: DiagramSet;
237
+ } | {
238
+ ok: false;
239
+ why: string;
240
+ };
241
+ /**
242
+ * AC4's checks on what the service drew, all before anything is written, for each look
243
+ * in the list: the PNG's signature and decoded size; the SVG's marker line, its `<svg`
244
+ * start and `</svg>` end (one newline allowed after), and its size. Then the Mermaid's
245
+ * `flowchart` start and its size, once. The sizes are the events package's bounds,
246
+ * checked again on the bytes about to be written rather than trusted from the parse.
247
+ * Each sentence names the file the bad bytes were for, so a person reading it knows
248
+ * which picture was wrong.
249
+ */
250
+ export declare function checkPictures(drawn: SystemDrawDrawn, base: DiagramBaseName): PictureCheck;
251
+ /**
252
+ * What writing came to. `up-to-date`: every file already held these bytes and none
253
+ * was touched. `written`: the files in `changed` were replaced or created.
254
+ * `in-the-way` / `unsafe`: refused before anything was made, with the sentence.
255
+ * `failed`: a write failed; every file is as it was, except those in `removed`, which
256
+ * could not be put back and were removed.
257
+ */
258
+ export type DiagramWriteResult = {
259
+ kind: 'up-to-date';
260
+ } | {
261
+ kind: 'written';
262
+ changed: DiagramFile[];
263
+ } | {
264
+ kind: 'in-the-way';
265
+ file: DiagramFile;
266
+ temp: boolean;
267
+ } | {
268
+ kind: 'unsafe';
269
+ why: string;
270
+ } | {
271
+ kind: 'failed';
272
+ file: DiagramFile;
273
+ removed: DiagramFile[];
274
+ };
275
+ /**
276
+ * Write the checked pictures into `docs/diagrams`, all or nothing, as the module
277
+ * header states. Never throws for a file-system failure: it is a `failed` result,
278
+ * and the set on disk is the old one.
279
+ */
280
+ export declare function writeDiagramSet(repoRoot: string, base: DiagramBaseName, set: DiagramSet, io?: RecordPairIo): DiagramWriteResult;
281
+ export {};
282
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/draw/write.ts"],"names":[],"mappings":"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"}