@smallpen/cli 0.1.0-alpha.13 → 0.1.0-alpha.14
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/bin/command-contract.mjs +6 -1
- package/bin/design-output.mjs +3 -2
- package/bin/schema.mjs +2 -2
- package/bin/smallpen.mjs +88 -73
- package/bin/validation-runner.mjs +62 -0
- package/bin/validation-worker.mjs +29 -0
- package/package.json +3 -3
package/bin/command-contract.mjs
CHANGED
|
@@ -28,6 +28,11 @@ const integer = (option, description, extra = {}) =>
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
const PARAMETERS = {
|
|
31
|
+
targetTimeout: integer(
|
|
32
|
+
"--target-timeout",
|
|
33
|
+
"Maximum milliseconds per validation target, including native layout; progress uses JSON lines on stderr and interruption returns partial coverage",
|
|
34
|
+
{ minimum: 1, maximum: 600_000, default: 30_000 },
|
|
35
|
+
),
|
|
31
36
|
stdout: flag(
|
|
32
37
|
"--stdout",
|
|
33
38
|
"Print large results to stdout instead of saving a temporary result file",
|
|
@@ -488,7 +493,7 @@ export const COMMAND_CONTRACTS = {
|
|
|
488
493
|
),
|
|
489
494
|
validate: command(
|
|
490
495
|
"Validate canonical data and report text/layout/contrast issues and coverage; a page checks every version and a component every variant unless one is named",
|
|
491
|
-
[...TARGET, ...VIEW, "designSystem", "limit", "offset"],
|
|
496
|
+
[...TARGET, ...VIEW, "designSystem", "limit", "offset", "targetTimeout"],
|
|
492
497
|
{ conflicts: { designSystem: ["page", "component"] } },
|
|
493
498
|
),
|
|
494
499
|
inspect: command("Read package identity, revision and counts"),
|
package/bin/design-output.mjs
CHANGED
|
@@ -261,7 +261,7 @@ export function componentLookup(workspace) {
|
|
|
261
261
|
}
|
|
262
262
|
return (reference) =>
|
|
263
263
|
reference
|
|
264
|
-
? (sets.get(`${reference.packageId}\0${reference.assetId}`)
|
|
264
|
+
? (reference.packageId ? sets.get(`${reference.packageId}\0${reference.assetId}`) : sets.get(reference.assetId))
|
|
265
265
|
: undefined;
|
|
266
266
|
}
|
|
267
267
|
|
|
@@ -468,7 +468,8 @@ function variantPairs(selection, set) {
|
|
|
468
468
|
// Node IDs show only with full: agents read and edit by name.
|
|
469
469
|
export function outlineTree(tree, projection, { full = false, components, ids = full } = {}) {
|
|
470
470
|
const lines = [];
|
|
471
|
-
const
|
|
471
|
+
const dimension = value => Number.isFinite(value) ? Math.round(value) : "?";
|
|
472
|
+
const size = (node) => `${dimension(node.bounds?.width)}×${dimension(node.bounds?.height)}`;
|
|
472
473
|
const describe = (node) => {
|
|
473
474
|
const raw = projection.nodes[node.id];
|
|
474
475
|
const reference = instanceReference(node, projection);
|
package/bin/schema.mjs
CHANGED
|
@@ -765,8 +765,8 @@ function setTopic(command) {
|
|
|
765
765
|
command,
|
|
766
766
|
fields: {
|
|
767
767
|
set: "FIELD=VALUE, repeatable; VALUE is JSON (320, [8,16], {\"Style\":\"ghost\"}, true) or plain text; {token.path} binds a Token",
|
|
768
|
-
element: "fields: width, height (number, fill, hug), fill, stroke, radius, opacity, shadow, visible, rotation, margin, min/max sizes; texts: text, color, font, fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, textTransform, textDecoration, textAlign; containers: layout (row|column|none), gap, padding, align, justify",
|
|
769
|
-
copy: "a copy of a component: props, text {\"Element\": \"text\"}, set {\"Element.field\": value}, width
|
|
768
|
+
element: "fields: width, height (number, px, Token, fill, hug), fill, stroke, radius, opacity, shadow, visible, rotation, margin, min/max sizes; texts: text, color, font, fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, textTransform, textDecoration, textAlign; containers: layout (row|column|none), gap, padding, align, justify",
|
|
769
|
+
copy: "a copy of a component: props, text {\"Element\": \"text\"}, set {\"Element.field\": value}, width/height (numbers, px, Tokens, hug, or fill in a row/column parent), visible, opacity. Sizes inside set (Element.width/height) take numbers or Tokens",
|
|
770
770
|
itself: "without --element: the page version (or the variant) itself, for example its width and height",
|
|
771
771
|
},
|
|
772
772
|
example: [
|
package/bin/smallpen.mjs
CHANGED
|
@@ -169,6 +169,8 @@ import {
|
|
|
169
169
|
viewSummary,
|
|
170
170
|
} from "./read-output.mjs";
|
|
171
171
|
|
|
172
|
+
import { runValidationJobs } from "./validation-runner.mjs";
|
|
173
|
+
|
|
172
174
|
let writeState = "not-applied";
|
|
173
175
|
async function trackedWrite(action) {
|
|
174
176
|
writeState = "unknown";
|
|
@@ -1973,8 +1975,11 @@ async function designCommand(packagePath, args, override) {
|
|
|
1973
1975
|
};
|
|
1974
1976
|
}
|
|
1975
1977
|
|
|
1976
|
-
async function
|
|
1977
|
-
if (!flag(args, "--all"))
|
|
1978
|
+
async function validationJobs(workspace, args) {
|
|
1979
|
+
if (!flag(args, "--all")) {
|
|
1980
|
+
const design = await designForCommand(workspace, args);
|
|
1981
|
+
return [{ design, selection: design.selection }];
|
|
1982
|
+
}
|
|
1978
1983
|
const componentId = option(args, "--component-id"),
|
|
1979
1984
|
screenId = option(args, "--screen-id");
|
|
1980
1985
|
if (!componentId && !screenId)
|
|
@@ -1992,11 +1997,9 @@ async function validationDesigns(workspace, args) {
|
|
|
1992
1997
|
(snapshot) => snapshot?.manifest.packageId === first.selection.packageId,
|
|
1993
1998
|
);
|
|
1994
1999
|
return owner.domain.componentSets.get(componentId).variants.map((variant) =>
|
|
1995
|
-
|
|
1996
|
-
componentId,
|
|
1997
|
-
packageId: first.selection.packageId,
|
|
1998
|
-
variantId: variant.id,
|
|
1999
|
-
}),
|
|
2000
|
+
({ selector: designSelector(args),
|
|
2001
|
+
target: { componentId, packageId: first.selection.packageId, variantId: variant.id },
|
|
2002
|
+
selection: { componentId, packageId: first.selection.packageId, variantId: variant.id } }),
|
|
2000
2003
|
);
|
|
2001
2004
|
}
|
|
2002
2005
|
const screen = workspace.product.manifest.entries.screens
|
|
@@ -2005,11 +2008,8 @@ async function validationDesigns(workspace, args) {
|
|
|
2005
2008
|
if (!screen)
|
|
2006
2009
|
throw new SmallPenError("missing_screen", `No Screen ${screenId}`);
|
|
2007
2010
|
return screen.presentations.map((presentation) =>
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
screenId,
|
|
2011
|
-
presentationId: presentation.id,
|
|
2012
|
-
}),
|
|
2011
|
+
({ selector: { ...designSelector(args), screenId, presentationId: presentation.id },
|
|
2012
|
+
selection: { screenId, presentationId: presentation.id } }),
|
|
2013
2013
|
);
|
|
2014
2014
|
}
|
|
2015
2015
|
|
|
@@ -3570,29 +3570,26 @@ async function validateWholePackage(packagePath, args, workspace, resolution, on
|
|
|
3570
3570
|
};
|
|
3571
3571
|
const issues = [], checked = [], skipped = [], hints = [];
|
|
3572
3572
|
let unreadable = 0;
|
|
3573
|
+
const jobs = [];
|
|
3573
3574
|
for (const target of targets) {
|
|
3574
3575
|
try {
|
|
3575
|
-
|
|
3576
|
-
for (const issue of report.issues ?? []) {
|
|
3577
|
-
const named = selectionNames(workspace, issue.target ?? {});
|
|
3578
|
-
const at = [named.page ?? named.component ?? target.where, named.platform ?? named.variant].filter(Boolean);
|
|
3579
|
-
const { target: _target, ...rest } = issue;
|
|
3580
|
-
issues.push({ target: at.length > 1 ? `${at[0]} (${at[1]})` : at[0], ...rest });
|
|
3581
|
-
}
|
|
3582
|
-
checked.push(...(report.coverage?.targets ?? []));
|
|
3583
|
-
skipped.push(...(report.coverage?.skipped ?? []).map((skip) => ({ ...skip, label: targetLabel(skip.target) })));
|
|
3584
|
-
for (const hint of report.hints ?? [])
|
|
3585
|
-
if (!hints.some((other) => JSON.stringify(other) === JSON.stringify(hint))) hints.push(hint);
|
|
3576
|
+
jobs.push(...await validationJobs(workspace, ["validate", packagePath, ...target.ids, ...pass]));
|
|
3586
3577
|
} catch (error) {
|
|
3587
3578
|
unreadable += 1;
|
|
3588
|
-
issues.push({
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3579
|
+
issues.push({ target: target.where, code: error.code ?? "unreadable_target", severity: "error", check: "read", message: error.message });
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
const outcome = await runChecks(workspace, jobs, args);
|
|
3583
|
+
for (const result of outcome.results) {
|
|
3584
|
+
const report = validationResult(result);
|
|
3585
|
+
for (const issue of report.issues ?? []) {
|
|
3586
|
+
const { target: _target, ...rest } = issue;
|
|
3587
|
+
issues.push({ target: validationLabel(workspace, report.selection), ...rest });
|
|
3595
3588
|
}
|
|
3589
|
+
if (result.report) checked.push(report.selection);
|
|
3590
|
+
skipped.push(...(report.coverage?.skipped ?? []).map(skip => ({ ...skip, target: report.selection, label: validationLabel(workspace, report.selection) })));
|
|
3591
|
+
for (const hint of report.hints ?? [])
|
|
3592
|
+
if (!hints.some(other => JSON.stringify(other) === JSON.stringify(hint))) hints.push(hint);
|
|
3596
3593
|
}
|
|
3597
3594
|
// Layout limits belong to the tool, with full diagnostics kept separately
|
|
3598
3595
|
// from design issues and every skipped layout check counted in coverage.
|
|
@@ -3604,9 +3601,9 @@ async function validateWholePackage(packagePath, args, workspace, resolution, on
|
|
|
3604
3601
|
return {
|
|
3605
3602
|
packageId: product.manifest.packageId,
|
|
3606
3603
|
...workspaceRevisions(product, workspace.foundation, workspace.libraries),
|
|
3607
|
-
status: unreadable ? "invalid" : "valid",
|
|
3604
|
+
status: outcome.interrupted ? "interrupted" : outcome.results.some(result => result.error) ? "partial" : unreadable ? "invalid" : "valid",
|
|
3608
3605
|
dataStatus: unreadable ? "invalid" : "valid",
|
|
3609
|
-
visualStatus: design.length ? "issues" : "no-issues-found",
|
|
3606
|
+
visualStatus: design.length ? "issues" : outcome.interrupted ? "partial" : "no-issues-found",
|
|
3610
3607
|
issueCount: design.length,
|
|
3611
3608
|
issues: full ? design : page.items,
|
|
3612
3609
|
...(full ? {} : { page: page.page }),
|
|
@@ -3618,7 +3615,8 @@ async function validateWholePackage(packagePath, args, workspace, resolution, on
|
|
|
3618
3615
|
selection: { themes: themeSettings(workspace).selection.themes },
|
|
3619
3616
|
coverage: {
|
|
3620
3617
|
// Every target drawn and every check run on it.
|
|
3621
|
-
complete: unreadable === 0 && notChecked.length === 0,
|
|
3618
|
+
complete: unreadable === 0 && notChecked.length === 0 && !outcome.interrupted,
|
|
3619
|
+
...executionCoverage(outcome),
|
|
3622
3620
|
targetCount: checked.length,
|
|
3623
3621
|
// By name, short: "Home (desktop)", "Button (Style=primary)".
|
|
3624
3622
|
// Pages by version; components as one line each unless --full.
|
|
@@ -3763,48 +3761,63 @@ function projectSummary(snapshot) {
|
|
|
3763
3761
|
};
|
|
3764
3762
|
}
|
|
3765
3763
|
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
const
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3764
|
+
function validationLabel(workspace, selection) {
|
|
3765
|
+
const named = selectionNames(workspace, selection);
|
|
3766
|
+
const parts = [named.page ?? named.component, named.platform ?? named.variant].filter(Boolean);
|
|
3767
|
+
return parts.length > 1 ? `${parts[0]} (${parts[1]})` : parts[0] ?? "design";
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
async function runChecks(workspace, jobs, args) {
|
|
3771
|
+
const controller = new AbortController();
|
|
3772
|
+
const interrupt = () => controller.abort();
|
|
3773
|
+
process.once("SIGINT", interrupt);
|
|
3774
|
+
process.once("SIGTERM", interrupt);
|
|
3775
|
+
try {
|
|
3776
|
+
const outcome = await runValidationJobs(workspace, jobs.map(job => ({
|
|
3777
|
+
...job, label: validationLabel(workspace, job.selection),
|
|
3778
|
+
})), {
|
|
3779
|
+
timeoutMs: Number(option(args, "--target-timeout") ?? 30_000),
|
|
3780
|
+
signal: controller.signal,
|
|
3781
|
+
progress: event => process.stderr.write(JSON.stringify(event) + "\n"),
|
|
3783
3782
|
});
|
|
3784
|
-
if (
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
...workspace,
|
|
3790
|
-
context: design.projection.context,
|
|
3791
|
-
initialProjection: design.projection,
|
|
3792
|
-
},
|
|
3793
|
-
);
|
|
3794
|
-
report.issues.push(
|
|
3795
|
-
...flow.issues.map((issue) => ({
|
|
3796
|
-
...issue,
|
|
3797
|
-
check: "prototype-connections",
|
|
3798
|
-
})),
|
|
3799
|
-
);
|
|
3800
|
-
report.coverage.checks.push("prototype-connections");
|
|
3801
|
-
report.coverage.connectionCount = flow.connections.length;
|
|
3802
|
-
}
|
|
3803
|
-
reports.push(report);
|
|
3783
|
+
if (outcome.interrupted) process.exitCode = 130;
|
|
3784
|
+
return outcome;
|
|
3785
|
+
} finally {
|
|
3786
|
+
process.removeListener("SIGINT", interrupt);
|
|
3787
|
+
process.removeListener("SIGTERM", interrupt);
|
|
3804
3788
|
}
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3791
|
+
function executionCoverage(outcome) {
|
|
3792
|
+
return {
|
|
3793
|
+
totalTargetCount: outcome.total,
|
|
3794
|
+
completedTargetCount: outcome.results.length,
|
|
3795
|
+
failedTargetCount: outcome.results.filter(result => result.error).length,
|
|
3796
|
+
remainingCount: outcome.remaining.length,
|
|
3797
|
+
remaining: outcome.remaining,
|
|
3798
|
+
interrupted: outcome.interrupted,
|
|
3799
|
+
};
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3802
|
+
function validationResult({ job, report, error }) {
|
|
3803
|
+
return report ?? {
|
|
3804
|
+
selection: job.selection,
|
|
3805
|
+
issues: [{ ...error, severity: "error", check: "execution" }],
|
|
3806
|
+
coverage: { complete: false, nodeCount: 0, visibleNodeCount: 0, checks: [],
|
|
3807
|
+
skipped: [{ check: "native-layout", reason: error.message, code: error.code, target: job.selection }] },
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
// Every check of the selected targets, untruncated.
|
|
3812
|
+
async function validateTargets(workspace, args) {
|
|
3813
|
+
const outcome = await runChecks(workspace, await validationJobs(workspace, args), args);
|
|
3814
|
+
const reports = outcome.results.map(validationResult);
|
|
3815
|
+
const empty = { issues: [], coverage: { complete: false, checks: [], skipped: [], nodeCount: 0, visibleNodeCount: 0 } };
|
|
3805
3816
|
const all = flag(args, "--all");
|
|
3806
3817
|
const visual = {
|
|
3807
|
-
...reports[0],
|
|
3818
|
+
...(reports[0] ?? empty),
|
|
3819
|
+
...(outcome.interrupted ? { status: "interrupted", visualStatus: "partial" }
|
|
3820
|
+
: outcome.results.some(result => result.error) ? { status: "partial", visualStatus: "partial" } : {}),
|
|
3808
3821
|
...(reports.some((report) => report.hints?.length) ? { hints: reports.flatMap((report) => report.hints ?? []) } : {}),
|
|
3809
3822
|
issues: reports.flatMap((report) =>
|
|
3810
3823
|
report.issues.map((issue) =>
|
|
@@ -3812,7 +3825,9 @@ async function validateTargets(workspace, args) {
|
|
|
3812
3825
|
),
|
|
3813
3826
|
),
|
|
3814
3827
|
coverage: {
|
|
3815
|
-
...reports[0].coverage,
|
|
3828
|
+
...(reports[0]?.coverage ?? empty.coverage),
|
|
3829
|
+
...executionCoverage(outcome),
|
|
3830
|
+
complete: !outcome.interrupted && reports.every(report => report.coverage.complete),
|
|
3816
3831
|
targets: reports.map((report) => ({ ...selectionNames(workspace, report.selection), ...report.selection })),
|
|
3817
3832
|
targetCount: reports.length,
|
|
3818
3833
|
nodeCount: reports.reduce(
|
|
@@ -3859,7 +3874,7 @@ async function validateTargets(workspace, args) {
|
|
|
3859
3874
|
...(option(args, "--component-id")
|
|
3860
3875
|
? {
|
|
3861
3876
|
componentId: option(args, "--component-id"),
|
|
3862
|
-
packageId: reports[0]
|
|
3877
|
+
packageId: reports[0]?.selection.packageId,
|
|
3863
3878
|
}
|
|
3864
3879
|
: { screenId: option(args, "--screen-id") }),
|
|
3865
3880
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
|
|
3
|
+
// A persistent worker reuses the shared App runtime. Terminating the worker
|
|
4
|
+
// also stops synchronous WASM; a Promise timeout in this process cannot.
|
|
5
|
+
export async function runValidationJobs(workspace, jobs, {
|
|
6
|
+
timeoutMs = 30_000, signal, progress = () => {},
|
|
7
|
+
workerUrl = new URL("./validation-worker.mjs", import.meta.url),
|
|
8
|
+
} = {}) {
|
|
9
|
+
const results = [];
|
|
10
|
+
let worker;
|
|
11
|
+
const emit = (event, extra = {}) => progress({
|
|
12
|
+
type: "validation-progress", event, total: jobs.length, completed: results.length, ...extra,
|
|
13
|
+
});
|
|
14
|
+
emit("start");
|
|
15
|
+
try {
|
|
16
|
+
for (const job of jobs) {
|
|
17
|
+
if (signal?.aborted) break;
|
|
18
|
+
emit("target", { target: job.label });
|
|
19
|
+
worker ??= new Worker(workerUrl, { workerData: workspace });
|
|
20
|
+
const result = await new Promise(resolve => {
|
|
21
|
+
let finished = false;
|
|
22
|
+
const finish = value => {
|
|
23
|
+
if (finished) return;
|
|
24
|
+
finished = true;
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
worker.off("message", onMessage);
|
|
27
|
+
worker.off("error", onError);
|
|
28
|
+
worker.off("exit", onExit);
|
|
29
|
+
signal?.removeEventListener("abort", onAbort);
|
|
30
|
+
resolve(value);
|
|
31
|
+
};
|
|
32
|
+
const onMessage = value => finish(value);
|
|
33
|
+
const onError = error => finish({ error: { code: "validation_worker_failed", message: error.message }, restart: true });
|
|
34
|
+
const onExit = code => onError(new Error(`Validation worker exited (${code})`));
|
|
35
|
+
const onAbort = () => finish({ interrupted: true, restart: true });
|
|
36
|
+
const timer = setTimeout(() => finish({ error: {
|
|
37
|
+
code: "validation_target_timeout", message: `Target exceeded ${timeoutMs}ms`,
|
|
38
|
+
details: { timeoutMs, target: job.label, selection: job.selection },
|
|
39
|
+
}, restart: true }), timeoutMs);
|
|
40
|
+
worker.once("message", onMessage);
|
|
41
|
+
worker.once("error", onError);
|
|
42
|
+
worker.once("exit", onExit);
|
|
43
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
44
|
+
if (signal?.aborted) onAbort();
|
|
45
|
+
else worker.postMessage(job);
|
|
46
|
+
});
|
|
47
|
+
if (result.restart) {
|
|
48
|
+
await worker.terminate();
|
|
49
|
+
worker = undefined;
|
|
50
|
+
}
|
|
51
|
+
if (result.interrupted) break;
|
|
52
|
+
results.push({ job, ...result });
|
|
53
|
+
emit("completed", { target: job.label, status: result.error ? result.error.code : "checked" });
|
|
54
|
+
}
|
|
55
|
+
} finally {
|
|
56
|
+
await worker?.terminate();
|
|
57
|
+
}
|
|
58
|
+
const remaining = jobs.slice(results.length).map(job => ({ target: job.label, selection: job.selection }));
|
|
59
|
+
const interrupted = Boolean(signal?.aborted);
|
|
60
|
+
emit(interrupted ? "interrupted" : "finished", { remaining: remaining.length });
|
|
61
|
+
return { results, interrupted, remaining, total: jobs.length };
|
|
62
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
2
|
+
import { elementPath, prototypeConnections } from "@smallpen/core";
|
|
3
|
+
import { selectedDesign, validateDesign } from "./design-output.mjs";
|
|
4
|
+
|
|
5
|
+
const workspace = workerData;
|
|
6
|
+
parentPort.on("message", async (job) => {
|
|
7
|
+
try {
|
|
8
|
+
const design = job.design ?? selectedDesign(workspace, job.selector, job.target);
|
|
9
|
+
const report = { ...(await validateDesign(workspace, design)), selection: design.selection };
|
|
10
|
+
const nodes = design.projection.nodes;
|
|
11
|
+
report.coverage.skipped = (report.coverage.skipped ?? []).map(skip => {
|
|
12
|
+
const at = [skip.path, skip.nodeId].find(id => typeof id === "string" && Object.hasOwn(nodes, id));
|
|
13
|
+
if (!at) return skip;
|
|
14
|
+
const { path: _path, ...rest } = skip;
|
|
15
|
+
return { ...rest, element: elementPath(nodes, design.projection.rootId, at) || nodes[at].name };
|
|
16
|
+
});
|
|
17
|
+
if (design.selection.screenId) {
|
|
18
|
+
const flow = prototypeConnections(workspace.product, design.selection, {
|
|
19
|
+
...workspace, context: design.projection.context, initialProjection: design.projection,
|
|
20
|
+
});
|
|
21
|
+
report.issues.push(...flow.issues.map(issue => ({ ...issue, check: "prototype-connections" })));
|
|
22
|
+
report.coverage.checks.push("prototype-connections");
|
|
23
|
+
report.coverage.connectionCount = flow.connections.length;
|
|
24
|
+
}
|
|
25
|
+
parentPort.postMessage({ report });
|
|
26
|
+
} catch (error) {
|
|
27
|
+
parentPort.postMessage({ error: { code: error.code ?? "unreadable_target", message: error.message, details: error.details } });
|
|
28
|
+
}
|
|
29
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smallpen/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.14",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"bin"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@smallpen/core": "0.1.0-alpha.
|
|
19
|
-
"@smallpen/local-package": "0.1.0-alpha.
|
|
18
|
+
"@smallpen/core": "0.1.0-alpha.14",
|
|
19
|
+
"@smallpen/local-package": "0.1.0-alpha.14"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|