@design-parity/action 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -0
- package/dist/baseline.d.ts +48 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +126 -0
- package/dist/baseline.js.map +1 -0
- package/dist/candidate.d.ts +48 -0
- package/dist/candidate.d.ts.map +1 -0
- package/dist/candidate.js +109 -0
- package/dist/candidate.js.map +1 -0
- package/dist/cli/action.d.ts +3 -0
- package/dist/cli/action.d.ts.map +1 -0
- package/dist/cli/action.js +222 -0
- package/dist/cli/action.js.map +1 -0
- package/dist/cli/run.d.ts +3 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +123 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/github/changed-components.d.ts +15 -0
- package/dist/github/changed-components.d.ts.map +1 -0
- package/dist/github/changed-components.js +18 -0
- package/dist/github/changed-components.js.map +1 -0
- package/dist/github/conclusion.d.ts +16 -0
- package/dist/github/conclusion.d.ts.map +1 -0
- package/dist/github/conclusion.js +17 -0
- package/dist/github/conclusion.js.map +1 -0
- package/dist/github/publish.d.ts +50 -0
- package/dist/github/publish.d.ts.map +1 -0
- package/dist/github/publish.js +91 -0
- package/dist/github/publish.js.map +1 -0
- package/dist/github/rest.d.ts +29 -0
- package/dist/github/rest.d.ts.map +1 -0
- package/dist/github/rest.js +64 -0
- package/dist/github/rest.js.map +1 -0
- package/dist/github/surface.d.ts +17 -0
- package/dist/github/surface.d.ts.map +1 -0
- package/dist/github/surface.js +21 -0
- package/dist/github/surface.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mode.d.ts +35 -0
- package/dist/mode.d.ts.map +1 -0
- package/dist/mode.js +25 -0
- package/dist/mode.js.map +1 -0
- package/dist/orchestrate.d.ts +80 -0
- package/dist/orchestrate.d.ts.map +1 -0
- package/dist/orchestrate.js +100 -0
- package/dist/orchestrate.js.map +1 -0
- package/dist/pushback.d.ts +81 -0
- package/dist/pushback.d.ts.map +1 -0
- package/dist/pushback.js +106 -0
- package/dist/pushback.js.map +1 -0
- package/dist/registry.d.ts +24 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +14 -0
- package/dist/registry.js.map +1 -0
- package/dist/report.d.ts +29 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +72 -0
- package/dist/report.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-to-Canvas push-back (issue #9) — the `code-led`, Figma-only stretch.
|
|
3
|
+
*
|
|
4
|
+
* After a parity run, optionally push each candidate render back into the
|
|
5
|
+
* design tool so the design file reflects what shipped. This is **gated** three
|
|
6
|
+
* ways (docs/PRINCIPLES.md, Principle 5):
|
|
7
|
+
*
|
|
8
|
+
* 1. an explicit opt-in flag, **and**
|
|
9
|
+
* 2. the resolved direction is `code-led` (in `design-led` the design stays
|
|
10
|
+
* canonical and code is never pushed back), **and**
|
|
11
|
+
* 3. the component's `source` is `figma`.
|
|
12
|
+
*
|
|
13
|
+
* Anything short of all three is a **no-op with a clear log line**. The actual
|
|
14
|
+
* write goes through an injected {@link CanvasWriter}; with no writer configured
|
|
15
|
+
* the run also no-ops (the Figma REST API is read-only, so a real writer needs a
|
|
16
|
+
* companion plugin / Dev Mode bridge). This module is otherwise pure: it makes
|
|
17
|
+
* no network or model calls itself.
|
|
18
|
+
*/
|
|
19
|
+
import type { AdapterContext, CanvasWriteResult, CanvasWriter, ResolvedDirection } from "@design-parity/core";
|
|
20
|
+
import type { ParityReport } from "./orchestrate.js";
|
|
21
|
+
/** Whether a run, as a whole, is eligible to push candidates back. */
|
|
22
|
+
export interface PushBackGate {
|
|
23
|
+
eligible: boolean;
|
|
24
|
+
/** A clear, human-readable reason when not eligible (the no-op log line). */
|
|
25
|
+
reason?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The overall gate: push-back runs only when explicitly opted in **and** the
|
|
29
|
+
* direction is `code-led`. Pure and deterministic — the per-component
|
|
30
|
+
* `source === "figma"` check happens during {@link pushBack}.
|
|
31
|
+
*/
|
|
32
|
+
export declare function decidePushBack(input: {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
direction: ResolvedDirection;
|
|
35
|
+
}): PushBackGate;
|
|
36
|
+
export interface PushedImage {
|
|
37
|
+
/** `state/theme/size` key of the pushed image. */
|
|
38
|
+
key: string;
|
|
39
|
+
result: CanvasWriteResult;
|
|
40
|
+
}
|
|
41
|
+
export interface PushBackComponent {
|
|
42
|
+
code: string;
|
|
43
|
+
pushed: PushedImage[];
|
|
44
|
+
}
|
|
45
|
+
export interface PushBackSkip {
|
|
46
|
+
code: string;
|
|
47
|
+
reason: string;
|
|
48
|
+
}
|
|
49
|
+
export interface PushBackError {
|
|
50
|
+
code: string;
|
|
51
|
+
message: string;
|
|
52
|
+
}
|
|
53
|
+
/** The outcome of a push-back pass over a {@link ParityReport}. */
|
|
54
|
+
export interface PushBackReport {
|
|
55
|
+
/** True only when the gate let the run write at all (flag on, `code-led`, a writer). */
|
|
56
|
+
attempted: boolean;
|
|
57
|
+
/** Why the run did not attempt any write (the overall no-op log line). */
|
|
58
|
+
reason?: string;
|
|
59
|
+
pushed: PushBackComponent[];
|
|
60
|
+
skipped: PushBackSkip[];
|
|
61
|
+
/** Per-component write failures (fail-soft: never thrown). */
|
|
62
|
+
errors: PushBackError[];
|
|
63
|
+
}
|
|
64
|
+
export interface PushBackOptions {
|
|
65
|
+
report: ParityReport;
|
|
66
|
+
/** The explicit opt-in flag — push-back only runs when this is `true`. */
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
/** Writer for the design tool; absent means no-op (no transport configured). */
|
|
69
|
+
writer?: CanvasWriter;
|
|
70
|
+
/** Context the writer resolves image paths / credentials against. */
|
|
71
|
+
ctx: AdapterContext;
|
|
72
|
+
/** Sink for the clear log lines the acceptance criteria call for. */
|
|
73
|
+
log?: (message: string) => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run Code-to-Canvas push-back for a completed parity report. Honors the
|
|
77
|
+
* three-way gate, fails soft per component, and emits a clear log line in every
|
|
78
|
+
* branch (no-op or not). Never throws.
|
|
79
|
+
*/
|
|
80
|
+
export declare function pushBack(opts: PushBackOptions): Promise<PushBackReport>;
|
|
81
|
+
//# sourceMappingURL=pushback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pushback.d.ts","sourceRoot":"","sources":["../src/pushback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EACV,cAAc,EAEd,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAmB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtE,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;CAC9B,GAAG,YAAY,CAcf;AA2CD,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,8DAA8D;IAC9D,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,YAAY,CAAC;IACrB,0EAA0E;IAC1E,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,qEAAqE;IACrE,GAAG,EAAE,cAAc,CAAC;IACpB,qEAAqE;IACrE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAkD7E"}
|
package/dist/pushback.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overall gate: push-back runs only when explicitly opted in **and** the
|
|
3
|
+
* direction is `code-led`. Pure and deterministic — the per-component
|
|
4
|
+
* `source === "figma"` check happens during {@link pushBack}.
|
|
5
|
+
*/
|
|
6
|
+
export function decidePushBack(input) {
|
|
7
|
+
if (!input.enabled) {
|
|
8
|
+
return {
|
|
9
|
+
eligible: false,
|
|
10
|
+
reason: "Code-to-Canvas push-back is off (opt-in flag not set).",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
if (input.direction !== "code-led") {
|
|
14
|
+
return {
|
|
15
|
+
eligible: false,
|
|
16
|
+
reason: `Code-to-Canvas push-back skipped: direction is '${input.direction}', not 'code-led' (design stays canonical).`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return { eligible: true };
|
|
20
|
+
}
|
|
21
|
+
/** A short, stable key for one candidate image (state/theme/size). */
|
|
22
|
+
function imageKey(target) {
|
|
23
|
+
const { state, theme, size } = target.image;
|
|
24
|
+
return `${state}/${theme ?? "-"}/${size ?? "-"}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The candidate images to push back for one component, or `[]` with the reason
|
|
28
|
+
* it was skipped. A component is eligible only when it diffed cleanly against a
|
|
29
|
+
* matching-source reference and carries a candidate render.
|
|
30
|
+
*/
|
|
31
|
+
function targetsFor(result, source) {
|
|
32
|
+
if (result.source !== source) {
|
|
33
|
+
return {
|
|
34
|
+
targets: [],
|
|
35
|
+
reason: `source is '${result.source ?? "unknown"}', not '${source}' — nothing to push back`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (result.status !== "ok") {
|
|
39
|
+
return { targets: [], reason: `component was ${result.status}, no candidate to push back` };
|
|
40
|
+
}
|
|
41
|
+
const ref = result.reference?.ref;
|
|
42
|
+
if (!ref) {
|
|
43
|
+
return { targets: [], reason: "no resolved design reference to write to" };
|
|
44
|
+
}
|
|
45
|
+
const images = result.candidate?.images ?? [];
|
|
46
|
+
if (images.length === 0) {
|
|
47
|
+
return { targets: [], reason: "no candidate render to push back" };
|
|
48
|
+
}
|
|
49
|
+
const targets = images.map((image) => ({
|
|
50
|
+
componentId: result.code,
|
|
51
|
+
source,
|
|
52
|
+
ref,
|
|
53
|
+
image,
|
|
54
|
+
}));
|
|
55
|
+
return { targets };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Run Code-to-Canvas push-back for a completed parity report. Honors the
|
|
59
|
+
* three-way gate, fails soft per component, and emits a clear log line in every
|
|
60
|
+
* branch (no-op or not). Never throws.
|
|
61
|
+
*/
|
|
62
|
+
export async function pushBack(opts) {
|
|
63
|
+
const log = opts.log ?? (() => { });
|
|
64
|
+
const gate = decidePushBack({
|
|
65
|
+
enabled: opts.enabled,
|
|
66
|
+
direction: opts.report.direction,
|
|
67
|
+
});
|
|
68
|
+
if (!gate.eligible) {
|
|
69
|
+
log(`design-parity: ${gate.reason}`);
|
|
70
|
+
return { attempted: false, reason: gate.reason, pushed: [], skipped: [], errors: [] };
|
|
71
|
+
}
|
|
72
|
+
if (!opts.writer) {
|
|
73
|
+
const reason = "Code-to-Canvas push-back is enabled (code-led), but no canvas writer is " +
|
|
74
|
+
"configured — set up a Figma bridge endpoint to push candidates back.";
|
|
75
|
+
log(`design-parity: ${reason}`);
|
|
76
|
+
return { attempted: false, reason, pushed: [], skipped: [], errors: [] };
|
|
77
|
+
}
|
|
78
|
+
const writer = opts.writer;
|
|
79
|
+
const pushed = [];
|
|
80
|
+
const skipped = [];
|
|
81
|
+
const errors = [];
|
|
82
|
+
for (const result of opts.report.results) {
|
|
83
|
+
const { targets, reason } = targetsFor(result, writer.source);
|
|
84
|
+
if (targets.length === 0) {
|
|
85
|
+
skipped.push({ code: result.code, reason: reason ?? "not eligible" });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const images = [];
|
|
89
|
+
for (const target of targets) {
|
|
90
|
+
try {
|
|
91
|
+
const written = await writer.write(target, opts.ctx);
|
|
92
|
+
images.push({ key: imageKey(target), result: written });
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
// Fail soft: one bad write must not abort the rest or throw.
|
|
96
|
+
errors.push({ code: result.code, message: err.message });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (images.length > 0)
|
|
100
|
+
pushed.push({ code: result.code, pushed: images });
|
|
101
|
+
}
|
|
102
|
+
log(`design-parity: Code-to-Canvas pushed ${pushed.length} component(s) back to ` +
|
|
103
|
+
`'${writer.source}' (${skipped.length} skipped, ${errors.length} error(s)).`);
|
|
104
|
+
return { attempted: true, pushed, skipped, errors };
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=pushback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pushback.js","sourceRoot":"","sources":["../src/pushback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `source → adapter` registry.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter only declares a const `source`; nothing maps a {@link DesignSource}
|
|
5
|
+
* to a concrete {@link ReferenceAdapter}. That map can't live in `core` (core must
|
|
6
|
+
* not depend on adapters), so it lives here — the one place that imports all the
|
|
7
|
+
* drivers. Per-adapter options are injectable so tests and the CLI can supply
|
|
8
|
+
* credentials, output dirs, or fakes.
|
|
9
|
+
*/
|
|
10
|
+
import type { DesignSource, ReferenceAdapter } from "@design-parity/core";
|
|
11
|
+
import { createFigmaAdapter } from "@design-parity/adapter-figma";
|
|
12
|
+
import { createStitchAdapter } from "@design-parity/adapter-stitch";
|
|
13
|
+
import { ClaudeDesignAdapter } from "@design-parity/adapter-claude-design";
|
|
14
|
+
import { createBundleAdapter } from "@design-parity/adapter-bundle";
|
|
15
|
+
export type AdapterRegistry = Record<DesignSource, ReferenceAdapter>;
|
|
16
|
+
export interface RegistryOptions {
|
|
17
|
+
figma?: Parameters<typeof createFigmaAdapter>[0];
|
|
18
|
+
stitch?: Parameters<typeof createStitchAdapter>[0];
|
|
19
|
+
claudeDesign?: ConstructorParameters<typeof ClaudeDesignAdapter>[0];
|
|
20
|
+
bundle?: Parameters<typeof createBundleAdapter>[0];
|
|
21
|
+
}
|
|
22
|
+
/** Build the default registry wiring all reference drivers. */
|
|
23
|
+
export declare function createAdapterRegistry(opts?: RegistryOptions): AdapterRegistry;
|
|
24
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEpE,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,YAAY,CAAC,EAAE,qBAAqB,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;CACpD;AAED,+DAA+D;AAC/D,wBAAgB,qBAAqB,CAAC,IAAI,GAAE,eAAoB,GAAG,eAAe,CAOjF"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createFigmaAdapter } from "@design-parity/adapter-figma";
|
|
2
|
+
import { createStitchAdapter } from "@design-parity/adapter-stitch";
|
|
3
|
+
import { ClaudeDesignAdapter } from "@design-parity/adapter-claude-design";
|
|
4
|
+
import { createBundleAdapter } from "@design-parity/adapter-bundle";
|
|
5
|
+
/** Build the default registry wiring all reference drivers. */
|
|
6
|
+
export function createAdapterRegistry(opts = {}) {
|
|
7
|
+
return {
|
|
8
|
+
figma: createFigmaAdapter(opts.figma),
|
|
9
|
+
stitch: createStitchAdapter(opts.stitch),
|
|
10
|
+
"claude-design": new ClaudeDesignAdapter(opts.claudeDesign),
|
|
11
|
+
bundle: createBundleAdapter(opts.bundle),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAWpE,+DAA+D;AAC/D,MAAM,UAAU,qBAAqB,CAAC,OAAwB,EAAE;IAC9D,OAAO;QACL,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;QACrC,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;QACxC,eAAe,EAAE,IAAI,mBAAmB,CAAC,IAAI,CAAC,YAAY,CAAC;QAC3D,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;KACzC,CAAC;AACJ,CAAC"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a {@link ParityReport} as the single markdown comment the bot posts on
|
|
3
|
+
* a PR (and the CLI prints). a11y + i18n lead each component's section (that
|
|
4
|
+
* ordering is owned by the diff summary); this layer adds the overall verdict,
|
|
5
|
+
* the direction-driven blocking note, and the per-component roll-up.
|
|
6
|
+
*/
|
|
7
|
+
import type { ParityReport } from "./orchestrate.js";
|
|
8
|
+
/** Stable marker so the GitHub surface can find and update its own comment. */
|
|
9
|
+
export declare const REPORT_MARKER = "<!-- design-parity-report -->";
|
|
10
|
+
/**
|
|
11
|
+
* The comment posted when a PR runs against a repo that has **no committed
|
|
12
|
+
* parity setup** — no (or an empty) `design-map.json`. The unattended Action
|
|
13
|
+
* enforces committed deterministic artifacts; it never generates them at run
|
|
14
|
+
* time (Principle 1), so instead of silently guessing it points the user at the
|
|
15
|
+
* interactive bootstrap (issue #11 / the `design-parity-bootstrap` CLI).
|
|
16
|
+
*
|
|
17
|
+
* Carries the same {@link REPORT_MARKER} as a verdict comment, so it updates in
|
|
18
|
+
* place and is replaced by a real verdict on the first run after setup lands.
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderBootstrapNotice(): string;
|
|
21
|
+
/**
|
|
22
|
+
* The non-blocking Compose Multiplatform promotion shown on Android-only repos
|
|
23
|
+
* (docs/PRINCIPLES.md, Principle 6). Surfaced only when the committed
|
|
24
|
+
* `cmpCapable` flag is `false`; phrased for the PR comment (the bootstrap output
|
|
25
|
+
* has its own, longer wording). Advisory — it never changes the verdict.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CMP_PROMOTION: string;
|
|
28
|
+
export declare function renderReport(report: ParityReport): string;
|
|
29
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,+EAA+E;AAC/E,eAAO,MAAM,aAAa,kCAAkC,CAAC;AAE7D;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAgB9C;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QAK6C,CAAC;AAExE,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAkDzD"}
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const STATUS_ICON = { pass: "✅", warn: "⚠️", fail: "❌" };
|
|
2
|
+
/** Stable marker so the GitHub surface can find and update its own comment. */
|
|
3
|
+
export const REPORT_MARKER = "<!-- design-parity-report -->";
|
|
4
|
+
/**
|
|
5
|
+
* The comment posted when a PR runs against a repo that has **no committed
|
|
6
|
+
* parity setup** — no (or an empty) `design-map.json`. The unattended Action
|
|
7
|
+
* enforces committed deterministic artifacts; it never generates them at run
|
|
8
|
+
* time (Principle 1), so instead of silently guessing it points the user at the
|
|
9
|
+
* interactive bootstrap (issue #11 / the `design-parity-bootstrap` CLI).
|
|
10
|
+
*
|
|
11
|
+
* Carries the same {@link REPORT_MARKER} as a verdict comment, so it updates in
|
|
12
|
+
* place and is replaced by a real verdict on the first run after setup lands.
|
|
13
|
+
*/
|
|
14
|
+
export function renderBootstrapNotice() {
|
|
15
|
+
return [
|
|
16
|
+
REPORT_MARKER,
|
|
17
|
+
"",
|
|
18
|
+
"# Design parity",
|
|
19
|
+
"",
|
|
20
|
+
"ℹ️ **Not set up yet** — this repo has no committed `design-map.json`, so there's nothing to check parity against (no PR is blocked).",
|
|
21
|
+
"",
|
|
22
|
+
"design-parity runs unattended on committed, deterministic artifacts and never guesses your design ↔ code mapping at run time. To set it up, run the interactive bootstrap once and commit what it generates:",
|
|
23
|
+
"",
|
|
24
|
+
"```sh",
|
|
25
|
+
"npx design-parity-bootstrap",
|
|
26
|
+
"```",
|
|
27
|
+
"",
|
|
28
|
+
"It detects your design-system maturity and seeds a starter `design-map.json`, check config, and parity direction (`.design-parity.json`). See [issue #11](https://github.com/yschimke/design-parity/issues/11) for the setup flow.",
|
|
29
|
+
].join("\n");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The non-blocking Compose Multiplatform promotion shown on Android-only repos
|
|
33
|
+
* (docs/PRINCIPLES.md, Principle 6). Surfaced only when the committed
|
|
34
|
+
* `cmpCapable` flag is `false`; phrased for the PR comment (the bootstrap output
|
|
35
|
+
* has its own, longer wording). Advisory — it never changes the verdict.
|
|
36
|
+
*/
|
|
37
|
+
export const CMP_PROMOTION = "💡 **Tip — Compose Multiplatform.** This project looks Android-only " +
|
|
38
|
+
"(Jetpack Compose). On Compose Multiplatform it could run parity faster: the " +
|
|
39
|
+
"candidate renders on the JVM/desktop with **no Android emulator**, which is " +
|
|
40
|
+
"cheaper and easier to run unattended. Advisory only — plain Jetpack Compose " +
|
|
41
|
+
"stays fully supported. See [adopting-cmp.md](docs/adopting-cmp.md).";
|
|
42
|
+
export function renderReport(report) {
|
|
43
|
+
const lines = [REPORT_MARKER];
|
|
44
|
+
const headline = report.blocked
|
|
45
|
+
? `${STATUS_ICON.fail} **Parity check failed** — blocking (\`${report.direction}\`)`
|
|
46
|
+
: `${STATUS_ICON[report.status]} **Parity ${report.status}** (\`${report.direction}\`${report.status === "fail" ? ", advisory" : ""})`;
|
|
47
|
+
lines.push("", `# Design parity`, "", headline);
|
|
48
|
+
const checked = report.results.filter((r) => r.verdict);
|
|
49
|
+
if (checked.length === 0) {
|
|
50
|
+
lines.push("", "_No components were checked._");
|
|
51
|
+
}
|
|
52
|
+
for (const r of report.results) {
|
|
53
|
+
if (r.summary) {
|
|
54
|
+
lines.push("", "---", "", r.summary);
|
|
55
|
+
}
|
|
56
|
+
else if (r.status === "skipped") {
|
|
57
|
+
lines.push("", "---", "", `### \`${r.code}\` — skipped`, `_${r.note}._`);
|
|
58
|
+
}
|
|
59
|
+
else if (r.status === "error") {
|
|
60
|
+
lines.push("", "---", "", `### \`${r.code}\` — ⚠️ not checked`, `_Adapter/diff error (failed soft): ${r.note}._`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Promote CMP to Android-only repos (Principle 6) — non-blocking, never a gate.
|
|
64
|
+
if (report.cmpCapable === false) {
|
|
65
|
+
lines.push("", "---", "", CMP_PROMOTION);
|
|
66
|
+
}
|
|
67
|
+
if (report.warnings.length > 0) {
|
|
68
|
+
lines.push("", "---", "", "<details><summary>Warnings</summary>", "", ...report.warnings.map((w) => `- ${w}`), "", "</details>");
|
|
69
|
+
}
|
|
70
|
+
return lines.join("\n");
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@design-parity/action",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Integration layer: wires resolver, adapters, candidate, checks, diff, and policy into a parity run, and surfaces the verdict (CLI now; GitHub Action surface to follow).",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js",
|
|
11
|
+
"./run": "./dist/cli/run.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc --build",
|
|
18
|
+
"test": "vitest run"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@design-parity/core": "^0.1.0",
|
|
22
|
+
"@design-parity/resolver": "^0.1.0",
|
|
23
|
+
"@design-parity/policy": "^0.1.0",
|
|
24
|
+
"@design-parity/diff": "^0.1.0",
|
|
25
|
+
"@design-parity/report-html": "^0.1.0",
|
|
26
|
+
"@design-parity/checks": "^0.1.0",
|
|
27
|
+
"@design-parity/candidate": "^0.1.0",
|
|
28
|
+
"@design-parity/adapter-figma": "^0.1.0",
|
|
29
|
+
"@design-parity/adapter-stitch": "^0.1.0",
|
|
30
|
+
"@design-parity/adapter-claude-design": "^0.1.0",
|
|
31
|
+
"@design-parity/adapter-bundle": "^0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/yschimke/design-parity.git",
|
|
36
|
+
"directory": "packages/action"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/yschimke/design-parity/tree/main/packages/action#readme",
|
|
39
|
+
"bugs": "https://github.com/yschimke/design-parity/issues"
|
|
40
|
+
}
|