@cogitato/kit-cli 0.0.0-stage → 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/LICENSE +202 -0
- package/README.md +34 -2
- package/bin/kit.js +4 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +204 -0
- package/dist/cli.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.js +72 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/export-flows.d.ts +8 -0
- package/dist/export-flows.js +15 -0
- package/dist/export-flows.js.map +1 -0
- package/dist/flows.d.ts +38 -0
- package/dist/flows.js +141 -0
- package/dist/flows.js.map +1 -0
- package/dist/format.d.ts +3 -0
- package/dist/format.js +27 -0
- package/dist/format.js.map +1 -0
- package/dist/gaps.d.ts +21 -0
- package/dist/gaps.js +52 -0
- package/dist/gaps.js.map +1 -0
- package/dist/hook.d.ts +33 -0
- package/dist/hook.js +78 -0
- package/dist/hook.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/issue.d.ts +17 -0
- package/dist/issue.js +65 -0
- package/dist/issue.js.map +1 -0
- package/dist/links.d.ts +16 -0
- package/dist/links.js +61 -0
- package/dist/links.js.map +1 -0
- package/dist/preview.d.ts +16 -0
- package/dist/preview.js +38 -0
- package/dist/preview.js.map +1 -0
- package/dist/project.d.ts +35 -0
- package/dist/project.js +88 -0
- package/dist/project.js.map +1 -0
- package/dist/registry.d.ts +67 -0
- package/dist/registry.js +224 -0
- package/dist/registry.js.map +1 -0
- package/dist/rules/css-values.d.ts +31 -0
- package/dist/rules/css-values.js +185 -0
- package/dist/rules/css-values.js.map +1 -0
- package/dist/rules/css.d.ts +4 -0
- package/dist/rules/css.js +39 -0
- package/dist/rules/css.js.map +1 -0
- package/dist/rules/tsx.d.ts +24 -0
- package/dist/rules/tsx.js +190 -0
- package/dist/rules/tsx.js.map +1 -0
- package/dist/save.d.ts +27 -0
- package/dist/save.js +125 -0
- package/dist/save.js.map +1 -0
- package/dist/scaffold.d.ts +42 -0
- package/dist/scaffold.js +230 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/snapshots.d.ts +23 -0
- package/dist/snapshots.js +126 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/status.d.ts +14 -0
- package/dist/status.js +38 -0
- package/dist/status.js.map +1 -0
- package/dist/validate.d.ts +14 -0
- package/dist/validate.js +64 -0
- package/dist/validate.js.map +1 -0
- package/package.json +48 -3
package/dist/links.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { DEFAULT_PORT } from "./doctor.js";
|
|
3
|
+
import { KitError } from "./errors.js";
|
|
4
|
+
import { sourceFiles } from "./project.js";
|
|
5
|
+
import { readRegistry } from "./registry.js";
|
|
6
|
+
export const CANVAS_PATH = "/__canvas";
|
|
7
|
+
/** Finds the screen and state for "{screen id}.{state}" or a bare screen id (its default state). */
|
|
8
|
+
function resolveNode(project, node) {
|
|
9
|
+
const { screens } = readRegistry(project, sourceFiles(project));
|
|
10
|
+
let screen = screens.find((s) => s.id === node);
|
|
11
|
+
let state = "default";
|
|
12
|
+
if (!screen) {
|
|
13
|
+
const dot = node.lastIndexOf(".");
|
|
14
|
+
screen = screens.find((s) => s.id === node.slice(0, dot));
|
|
15
|
+
state = node.slice(dot + 1);
|
|
16
|
+
}
|
|
17
|
+
if (!screen)
|
|
18
|
+
throw new KitError(`There's no screen or state called "${node}".`);
|
|
19
|
+
if (!screen.fixtures.some((f) => f.key === state)) {
|
|
20
|
+
throw new KitError(`The ${screen.title} screen has no state called "${state}".`);
|
|
21
|
+
}
|
|
22
|
+
return { screen, state };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Local address of a screen state, like http://localhost:5173/checkout/payment?fixture=card-declined.
|
|
26
|
+
* `node` is "{screen id}.{state}" or just a screen id (its default state).
|
|
27
|
+
*/
|
|
28
|
+
export function stateLink(project, node, port = DEFAULT_PORT) {
|
|
29
|
+
const { screen, state } = resolveNode(project, node);
|
|
30
|
+
return `http://localhost:${port}${screen.route}?fixture=${encodeURIComponent(state)}`;
|
|
31
|
+
}
|
|
32
|
+
/** Local canvas, opened on one state's frame. */
|
|
33
|
+
export function canvasLink(project, node, port = DEFAULT_PORT) {
|
|
34
|
+
const { screen, state } = resolveNode(project, node);
|
|
35
|
+
return `http://localhost:${port}${CANVAS_PATH}?focus=${encodeURIComponent(`${screen.id}.${state}`)}`;
|
|
36
|
+
}
|
|
37
|
+
/** Netlify's form of a branch name in branch-deploy addresses: "design/sam-0102" -> "design-sam-0102". */
|
|
38
|
+
export function branchSlug(branch) {
|
|
39
|
+
return branch.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Hosted canvas for a branch, from `"kit": { "previewUrl": "https://{branch}--site.netlify.app" }`
|
|
43
|
+
* in the prototype's package.json. Undefined when the prototype has no hosting set up.
|
|
44
|
+
*/
|
|
45
|
+
export function previewLink(project, branch, node) {
|
|
46
|
+
const pkgPath = project.abs("package.json");
|
|
47
|
+
if (!existsSync(pkgPath))
|
|
48
|
+
return undefined;
|
|
49
|
+
let template;
|
|
50
|
+
try {
|
|
51
|
+
template = JSON.parse(readFileSync(pkgPath, "utf8")).kit?.previewUrl;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (typeof template !== "string" || !template.includes("{branch}"))
|
|
57
|
+
return undefined;
|
|
58
|
+
const base = template.replace("{branch}", branchSlug(branch)).replace(/\/+$/, "");
|
|
59
|
+
return `${base}${CANVAS_PATH}${node ? `?focus=${encodeURIComponent(node)}` : ""}`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,YAAY,EAAoB,MAAM,eAAe,CAAC;AAE/D,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AAEvC,oGAAoG;AACpG,SAAS,WAAW,CAAC,OAAgB,EAAE,IAAY;IACjD,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAChD,IAAI,KAAK,GAAG,SAAS,CAAC;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1D,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,QAAQ,CAAC,sCAAsC,IAAI,IAAI,CAAC,CAAC;IAChF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,QAAQ,CAAC,OAAO,MAAM,CAAC,KAAK,gCAAgC,KAAK,IAAI,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB,EAAE,IAAY,EAAE,IAAI,GAAG,YAAY;IAC3E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACrD,OAAO,oBAAoB,IAAI,GAAG,MAAM,CAAC,KAAK,YAAY,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;AACxF,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,IAAY,EAAE,IAAI,GAAG,YAAY;IAC5E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACrD,OAAO,oBAAoB,IAAI,GAAG,WAAW,UAAU,kBAAkB,CAAC,GAAG,MAAM,CAAC,EAAE,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC;AACvG,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,MAAc,EAAE,IAAa;IACzE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAwC,CAAC,GAAG,EAAE,UAAU,CAAC;IAC/G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IACrF,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClF,OAAO,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
import type { Project } from "./project.js";
|
|
3
|
+
export declare const KIT_PATH = "/__kit";
|
|
4
|
+
export interface PreviewOptions {
|
|
5
|
+
port?: number;
|
|
6
|
+
open?: boolean;
|
|
7
|
+
/** Called with progress messages for the person running the command. */
|
|
8
|
+
log?: (message: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface PreviewResult {
|
|
11
|
+
url: string;
|
|
12
|
+
/** The dev server Cogitato started, if it wasn't already running. Resolves when it exits. */
|
|
13
|
+
server?: ChildProcess;
|
|
14
|
+
}
|
|
15
|
+
/** Makes sure the prototype is running, then opens its /__kit page with every token and component. */
|
|
16
|
+
export declare function preview(project: Project, opts?: PreviewOptions): Promise<PreviewResult>;
|
package/dist/preview.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { DEFAULT_PORT, isServerUp } from "./doctor.js";
|
|
3
|
+
export const KIT_PATH = "/__kit";
|
|
4
|
+
function openInBrowser(url) {
|
|
5
|
+
const [cmd, args] = process.platform === "win32"
|
|
6
|
+
? ["cmd", ["/c", "start", "", url]]
|
|
7
|
+
: process.platform === "darwin"
|
|
8
|
+
? ["open", [url]]
|
|
9
|
+
: ["xdg-open", [url]];
|
|
10
|
+
spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
|
|
11
|
+
}
|
|
12
|
+
/** Makes sure the prototype is running, then opens its /__kit page with every token and component. */
|
|
13
|
+
export async function preview(project, opts = {}) {
|
|
14
|
+
const port = opts.port ?? DEFAULT_PORT;
|
|
15
|
+
const url = `http://localhost:${port}${KIT_PATH}`;
|
|
16
|
+
const log = opts.log ?? (() => { });
|
|
17
|
+
let server;
|
|
18
|
+
if (!(await isServerUp(port))) {
|
|
19
|
+
log("Starting the prototype...");
|
|
20
|
+
server = spawn("pnpm", ["exec", "vite", "--port", String(port), "--strictPort"], {
|
|
21
|
+
cwd: project.root,
|
|
22
|
+
stdio: "inherit",
|
|
23
|
+
shell: true,
|
|
24
|
+
});
|
|
25
|
+
const deadline = Date.now() + 30_000;
|
|
26
|
+
while (!(await isServerUp(port))) {
|
|
27
|
+
if (server.exitCode !== null || Date.now() > deadline) {
|
|
28
|
+
throw new Error("The prototype didn't start. Run kit doctor to see what's missing.");
|
|
29
|
+
}
|
|
30
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
log(`The design kit is at ${url}`);
|
|
34
|
+
if (opts.open !== false)
|
|
35
|
+
openInBrowser(url);
|
|
36
|
+
return { url, ...(server ? { server } : {}) };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAejC,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GACf,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC1B,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAC7B,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAChE,CAAC;AAED,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAgB,EAAE,OAAuB,EAAE;IACvE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC;IACvC,MAAM,GAAG,GAAG,oBAAoB,IAAI,GAAG,QAAQ,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEnC,IAAI,MAAgC,CAAC;IACrC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC9B,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACjC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,EAAE;YAC/E,GAAG,EAAE,OAAO,CAAC,IAAI;YACjB,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;QACrC,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACjC,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;YACvF,CAAC;YACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IACD,GAAG,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5C,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ComponentManifest, type ResolvedToken } from "@cogitato/contract";
|
|
2
|
+
/** Folder and file conventions every Cogitato prototype follows (no config file in v1). */
|
|
3
|
+
export declare const LAYOUT: {
|
|
4
|
+
readonly design: "design";
|
|
5
|
+
readonly contract: "design/contract";
|
|
6
|
+
readonly flowsJson: "design/flows.json";
|
|
7
|
+
readonly src: "src";
|
|
8
|
+
readonly screens: "src/screens";
|
|
9
|
+
readonly kit: "src/kit";
|
|
10
|
+
readonly flowsTs: "src/flows.ts";
|
|
11
|
+
readonly screenFile: "screen.tsx";
|
|
12
|
+
};
|
|
13
|
+
export interface Project {
|
|
14
|
+
/** Absolute path of the prototype root (the folder holding design/ and src/). */
|
|
15
|
+
root: string;
|
|
16
|
+
/** Absolute path for a project-relative path. */
|
|
17
|
+
abs(rel: string): string;
|
|
18
|
+
/** Project-relative path with "/" separators. */
|
|
19
|
+
rel(abs: string): string;
|
|
20
|
+
}
|
|
21
|
+
/** Finds the prototype root by walking up from `from` to the first folder containing design/contract. */
|
|
22
|
+
export declare function findProject(from?: string): Project | undefined;
|
|
23
|
+
export declare function projectAt(root: string): Project;
|
|
24
|
+
/** Every .ts, .tsx and .css file under src/, project-relative, sorted. */
|
|
25
|
+
export declare function sourceFiles(project: Project): string[];
|
|
26
|
+
export declare const isScreenFile: (rel: string) => boolean;
|
|
27
|
+
export declare const isKitFile: (rel: string) => boolean;
|
|
28
|
+
/** What the code rules need from the contract. Read leniently: contract problems are reported by contract validation. */
|
|
29
|
+
export interface ContractView {
|
|
30
|
+
tokens: ResolvedToken[];
|
|
31
|
+
/** Every CSS custom property the runtime defines, taken from the generated token CSS itself. */
|
|
32
|
+
cssVars: Set<string>;
|
|
33
|
+
manifests: Map<string, ComponentManifest>;
|
|
34
|
+
}
|
|
35
|
+
export declare function readContract(project: Project): ContractView;
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { resolveTokens, tokensToCss, } from "@cogitato/contract";
|
|
4
|
+
/** Folder and file conventions every Cogitato prototype follows (no config file in v1). */
|
|
5
|
+
export const LAYOUT = {
|
|
6
|
+
design: "design",
|
|
7
|
+
contract: "design/contract",
|
|
8
|
+
flowsJson: "design/flows.json",
|
|
9
|
+
src: "src",
|
|
10
|
+
screens: "src/screens",
|
|
11
|
+
kit: "src/kit",
|
|
12
|
+
flowsTs: "src/flows.ts",
|
|
13
|
+
screenFile: "screen.tsx",
|
|
14
|
+
};
|
|
15
|
+
/** Finds the prototype root by walking up from `from` to the first folder containing design/contract. */
|
|
16
|
+
export function findProject(from = process.cwd()) {
|
|
17
|
+
let dir = resolve(from);
|
|
18
|
+
for (;;) {
|
|
19
|
+
if (existsSync(join(dir, LAYOUT.contract)))
|
|
20
|
+
return projectAt(dir);
|
|
21
|
+
const parent = dirname(dir);
|
|
22
|
+
if (parent === dir)
|
|
23
|
+
return undefined;
|
|
24
|
+
dir = parent;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function projectAt(root) {
|
|
28
|
+
return {
|
|
29
|
+
root,
|
|
30
|
+
abs: (rel) => (isAbsolute(rel) ? rel : join(root, rel)),
|
|
31
|
+
rel: (abs) => relative(root, isAbsolute(abs) ? abs : join(root, abs)).split(sep).join("/"),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const SOURCE = /\.(tsx?|css)$/;
|
|
35
|
+
/** Every .ts, .tsx and .css file under src/, project-relative, sorted. */
|
|
36
|
+
export function sourceFiles(project) {
|
|
37
|
+
const out = [];
|
|
38
|
+
const walk = (dir) => {
|
|
39
|
+
if (!existsSync(dir))
|
|
40
|
+
return;
|
|
41
|
+
for (const name of readdirSync(dir)) {
|
|
42
|
+
if (name === "node_modules" || name.startsWith("."))
|
|
43
|
+
continue;
|
|
44
|
+
const path = join(dir, name);
|
|
45
|
+
if (statSync(path).isDirectory())
|
|
46
|
+
walk(path);
|
|
47
|
+
else if (SOURCE.test(name) && !name.endsWith(".d.ts"))
|
|
48
|
+
out.push(project.rel(path));
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
walk(project.abs(LAYOUT.src));
|
|
52
|
+
return out.sort();
|
|
53
|
+
}
|
|
54
|
+
export const isScreenFile = (rel) => rel.startsWith(`${LAYOUT.screens}/`) && rel.endsWith(`/${LAYOUT.screenFile}`);
|
|
55
|
+
export const isKitFile = (rel) => rel.startsWith(`${LAYOUT.kit}/`);
|
|
56
|
+
function readJson(path) {
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function readContract(project) {
|
|
65
|
+
const tokensJson = readJson(project.abs(`${LAYOUT.contract}/tokens.json`));
|
|
66
|
+
let tokens = [];
|
|
67
|
+
let cssVars = new Set();
|
|
68
|
+
try {
|
|
69
|
+
if (tokensJson) {
|
|
70
|
+
tokens = resolveTokens(tokensJson);
|
|
71
|
+
cssVars = new Set(tokensToCss(tokensJson).match(/--kit-[A-Za-z0-9_-]+(?=:)/g) ?? []);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
tokens = [];
|
|
76
|
+
}
|
|
77
|
+
const manifests = new Map();
|
|
78
|
+
const dir = project.abs(`${LAYOUT.contract}/components`);
|
|
79
|
+
if (existsSync(dir)) {
|
|
80
|
+
for (const f of readdirSync(dir).filter((f) => f.endsWith(".json"))) {
|
|
81
|
+
const m = readJson(join(dir, f));
|
|
82
|
+
if (m && typeof m.name === "string")
|
|
83
|
+
manifests.set(m.name, m);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { tokens, cssVars, manifests };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { type Issue } from "./issue.js";
|
|
3
|
+
import { type Project } from "./project.js";
|
|
4
|
+
export declare const ID_PATTERNS: {
|
|
5
|
+
screenId: RegExp;
|
|
6
|
+
slug: RegExp;
|
|
7
|
+
kitId: RegExp;
|
|
8
|
+
nodeRef: RegExp;
|
|
9
|
+
};
|
|
10
|
+
interface Located {
|
|
11
|
+
file: string;
|
|
12
|
+
line: number;
|
|
13
|
+
column: number;
|
|
14
|
+
}
|
|
15
|
+
export interface FixtureEntry extends Located {
|
|
16
|
+
key: string;
|
|
17
|
+
title: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ScreenEntry extends Located {
|
|
20
|
+
id: string;
|
|
21
|
+
route: string;
|
|
22
|
+
title: string;
|
|
23
|
+
fixtures: FixtureEntry[];
|
|
24
|
+
/** Folder of the screen (project-relative). Files inside it belong to this screen. */
|
|
25
|
+
dir: string;
|
|
26
|
+
}
|
|
27
|
+
export interface EdgeEntry extends Located {
|
|
28
|
+
from: string;
|
|
29
|
+
to: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface FlowEntry extends Located {
|
|
33
|
+
id: string;
|
|
34
|
+
title: string;
|
|
35
|
+
nodes?: {
|
|
36
|
+
ref: string;
|
|
37
|
+
at: Located;
|
|
38
|
+
}[];
|
|
39
|
+
edges: EdgeEntry[];
|
|
40
|
+
}
|
|
41
|
+
export interface Registry {
|
|
42
|
+
screens: ScreenEntry[];
|
|
43
|
+
flows: FlowEntry[];
|
|
44
|
+
issues: Issue[];
|
|
45
|
+
/**
|
|
46
|
+
* False when a screen file couldn't be read as a screen. Flow checks are skipped then:
|
|
47
|
+
* they'd report that screen's states as missing, which only repeats the real problem.
|
|
48
|
+
*/
|
|
49
|
+
complete: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** "card-declined" -> "Card declined". Same rule as the runtime's fixture titles. */
|
|
52
|
+
export declare function humanize(key: string): string;
|
|
53
|
+
/** Reads the defineScreen({...}) registration in one screen.tsx. */
|
|
54
|
+
export declare function readScreen(sf: ts.SourceFile): {
|
|
55
|
+
screen?: ScreenEntry;
|
|
56
|
+
issues: Issue[];
|
|
57
|
+
};
|
|
58
|
+
/** Reads defineFlows([...]) from src/flows.ts. */
|
|
59
|
+
export declare function readFlows(sf: ts.SourceFile): {
|
|
60
|
+
flows: FlowEntry[];
|
|
61
|
+
issues: Issue[];
|
|
62
|
+
};
|
|
63
|
+
/** Parses a project file, reusing the parse while its text is unchanged (keeps repeat runs fast). */
|
|
64
|
+
export declare function parseProjectFile(project: Project, rel: string): ts.SourceFile;
|
|
65
|
+
/** Reads every screen registration and src/flows.ts. Never runs prototype code. */
|
|
66
|
+
export declare function readRegistry(project: Project, files: string[]): Registry;
|
|
67
|
+
export {};
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { readSchema } from "@cogitato/contract";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { findCalls, getProperty, issueAt, literalText, parseSource, propertyName } from "./issue.js";
|
|
5
|
+
import { LAYOUT, isScreenFile } from "./project.js";
|
|
6
|
+
// Id formats come from the shared schema so the reader and the validators can't disagree.
|
|
7
|
+
const common = readSchema("common.schema.json");
|
|
8
|
+
const pattern = (name) => new RegExp(common.$defs[name].pattern);
|
|
9
|
+
export const ID_PATTERNS = {
|
|
10
|
+
screenId: pattern("screenId"),
|
|
11
|
+
slug: pattern("slug"),
|
|
12
|
+
kitId: pattern("kitId"),
|
|
13
|
+
nodeRef: pattern("nodeRef"),
|
|
14
|
+
};
|
|
15
|
+
/** "card-declined" -> "Card declined". Same rule as the runtime's fixture titles. */
|
|
16
|
+
export function humanize(key) {
|
|
17
|
+
const words = key.replace(/[-_.]+/g, " ").trim();
|
|
18
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
19
|
+
}
|
|
20
|
+
function locate(sf, node) {
|
|
21
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
22
|
+
return { file: sf.fileName, line: line + 1, column: character + 1 };
|
|
23
|
+
}
|
|
24
|
+
const notStatic = (sf, node, what, example) => issueAt("code-screen-not-static", sf, node, `Write ${what} as plain text, like ${example}, so Cogitato can find it without running the code.`);
|
|
25
|
+
/** Reads the defineScreen({...}) registration in one screen.tsx. */
|
|
26
|
+
export function readScreen(sf) {
|
|
27
|
+
const issues = [];
|
|
28
|
+
const calls = findCalls(sf, "defineScreen");
|
|
29
|
+
if (calls.length === 0) {
|
|
30
|
+
const first = sf.statements[0] ?? sf;
|
|
31
|
+
issues.push(issueAt("code-screen-missing", sf, first, `${sf.fileName} doesn't register a screen. Export one with \`export default defineScreen({ ... })\`.`));
|
|
32
|
+
return { issues };
|
|
33
|
+
}
|
|
34
|
+
const call = calls[0];
|
|
35
|
+
const arg = call.arguments[0];
|
|
36
|
+
if (!arg || !ts.isObjectLiteralExpression(arg)) {
|
|
37
|
+
issues.push(notStatic(sf, arg ?? call, "the screen's settings", "`defineScreen({ id: \"cart\", ... })`"));
|
|
38
|
+
return { issues };
|
|
39
|
+
}
|
|
40
|
+
const text = (key, example) => {
|
|
41
|
+
const prop = getProperty(arg, key);
|
|
42
|
+
const shorthand = arg.properties.find((p) => ts.isShorthandPropertyAssignment(p) && p.name.text === key);
|
|
43
|
+
if (!prop && shorthand) {
|
|
44
|
+
issues.push(notStatic(sf, shorthand, `the screen's ${key}`, `\`${key}: ${example}\``));
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (!prop) {
|
|
48
|
+
issues.push(issueAt("code-screen-incomplete", sf, arg, `This screen is missing its \`${key}\`. Add it, like \`${key}: ${example}\`.`));
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const value = literalText(prop.initializer);
|
|
52
|
+
if (value === undefined)
|
|
53
|
+
issues.push(notStatic(sf, prop.initializer, `the screen's ${key}`, `\`${example}\``));
|
|
54
|
+
return value;
|
|
55
|
+
};
|
|
56
|
+
const id = text("id", '"checkout.payment"');
|
|
57
|
+
const route = text("route", '"/checkout/payment"');
|
|
58
|
+
const title = text("title", '"Payment"');
|
|
59
|
+
if (id !== undefined && !ID_PATTERNS.screenId.test(id)) {
|
|
60
|
+
issues.push(issueAt("code-invalid-screen-id", sf, getProperty(arg, "id").initializer, `"${id}" isn't a valid screen id. Screen ids are lowercase words separated by dots, like "checkout.payment".`));
|
|
61
|
+
}
|
|
62
|
+
if (route !== undefined && !route.startsWith("/")) {
|
|
63
|
+
issues.push(issueAt("code-invalid-route", sf, getProperty(arg, "route").initializer, `The address "${route}" needs to start with "/", like "/checkout/payment".`));
|
|
64
|
+
}
|
|
65
|
+
const fixtures = [];
|
|
66
|
+
const fixturesProp = getProperty(arg, "fixtures");
|
|
67
|
+
if (!fixturesProp) {
|
|
68
|
+
issues.push(issueAt("code-missing-default-fixture", sf, arg, `This screen has no states. Add \`fixtures: { default: { data: {} } }\`; every screen needs a "default" state.`));
|
|
69
|
+
}
|
|
70
|
+
else if (!ts.isObjectLiteralExpression(fixturesProp.initializer)) {
|
|
71
|
+
issues.push(notStatic(sf, fixturesProp.initializer, "the screen's states (fixtures)", "`fixtures: { default: { data: {...} } }`"));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
for (const p of fixturesProp.initializer.properties) {
|
|
75
|
+
const key = ts.isPropertyAssignment(p) ? propertyName(p.name) : undefined;
|
|
76
|
+
if (!ts.isPropertyAssignment(p) || key === undefined) {
|
|
77
|
+
issues.push(notStatic(sf, p, "each state's name", '`"card-declined": { data: {...} }`'));
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!ID_PATTERNS.slug.test(key)) {
|
|
81
|
+
issues.push(issueAt("code-invalid-fixture-name", sf, p.name, `The state name "${key}" isn't valid. Use lowercase words joined by dashes, like "card-declined".`));
|
|
82
|
+
}
|
|
83
|
+
let fixtureTitle = humanize(key);
|
|
84
|
+
if (ts.isObjectLiteralExpression(p.initializer)) {
|
|
85
|
+
const titleProp = getProperty(p.initializer, "title");
|
|
86
|
+
if (titleProp) {
|
|
87
|
+
const t = literalText(titleProp.initializer);
|
|
88
|
+
if (t === undefined)
|
|
89
|
+
issues.push(notStatic(sf, titleProp.initializer, "the state's title", '`title: "Card declined"`'));
|
|
90
|
+
else
|
|
91
|
+
fixtureTitle = t;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
issues.push(notStatic(sf, p.initializer, `the "${key}" state`, '`{ title: "Card declined", data: {...} }`'));
|
|
96
|
+
}
|
|
97
|
+
fixtures.push({ key, title: fixtureTitle, ...locate(sf, p.name) });
|
|
98
|
+
}
|
|
99
|
+
if (!fixtures.some((f) => f.key === "default")) {
|
|
100
|
+
issues.push(issueAt("code-missing-default-fixture", sf, fixturesProp.name, `${title ?? "This screen"} has no "default" state. Every screen needs one; it's what the screen shows when it first opens.`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (id === undefined || route === undefined || title === undefined)
|
|
104
|
+
return { issues };
|
|
105
|
+
const dir = sf.fileName.slice(0, sf.fileName.lastIndexOf("/"));
|
|
106
|
+
return { screen: { id, route, title, fixtures, dir, ...locate(sf, call) }, issues };
|
|
107
|
+
}
|
|
108
|
+
/** Reads defineFlows([...]) from src/flows.ts. */
|
|
109
|
+
export function readFlows(sf) {
|
|
110
|
+
const issues = [];
|
|
111
|
+
const flows = [];
|
|
112
|
+
const flowsNotStatic = (node, what, example) => issueAt("code-flows-not-static", sf, node, `Write ${what} as plain text, like ${example}, so Cogitato can read it without running the code.`);
|
|
113
|
+
const call = findCalls(sf, "defineFlows")[0];
|
|
114
|
+
if (!call)
|
|
115
|
+
return { flows, issues };
|
|
116
|
+
const list = call.arguments[0];
|
|
117
|
+
if (!list || !ts.isArrayLiteralExpression(list)) {
|
|
118
|
+
issues.push(flowsNotStatic(list ?? call, "the list of flows", "`defineFlows([{ id: \"checkout\", ... }])`"));
|
|
119
|
+
return { flows, issues };
|
|
120
|
+
}
|
|
121
|
+
for (const el of list.elements) {
|
|
122
|
+
if (!ts.isObjectLiteralExpression(el)) {
|
|
123
|
+
issues.push(flowsNotStatic(el, "each flow", '`{ id: "checkout", title: "Checkout", edges: [...] }`'));
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const idProp = getProperty(el, "id");
|
|
127
|
+
const titleProp = getProperty(el, "title");
|
|
128
|
+
const id = literalText(idProp?.initializer);
|
|
129
|
+
const title = literalText(titleProp?.initializer);
|
|
130
|
+
if (id === undefined)
|
|
131
|
+
issues.push(flowsNotStatic(idProp?.initializer ?? el, "the flow's id", '`id: "checkout"`'));
|
|
132
|
+
if (title === undefined)
|
|
133
|
+
issues.push(flowsNotStatic(titleProp?.initializer ?? el, "the flow's title", '`title: "Checkout"`'));
|
|
134
|
+
const edges = [];
|
|
135
|
+
const edgesProp = getProperty(el, "edges");
|
|
136
|
+
if (!edgesProp || !ts.isArrayLiteralExpression(edgesProp.initializer)) {
|
|
137
|
+
issues.push(flowsNotStatic(edgesProp?.initializer ?? el, "the flow's arrows (edges)", '`edges: [{ from: "cart.default", to: "checkout.shipping.default" }]`'));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
for (const e of edgesProp.initializer.elements) {
|
|
141
|
+
const from = ts.isObjectLiteralExpression(e) ? literalText(getProperty(e, "from")?.initializer) : undefined;
|
|
142
|
+
const to = ts.isObjectLiteralExpression(e) ? literalText(getProperty(e, "to")?.initializer) : undefined;
|
|
143
|
+
if (!ts.isObjectLiteralExpression(e) || from === undefined || to === undefined) {
|
|
144
|
+
issues.push(flowsNotStatic(e, "each arrow", '`{ from: "cart.default", to: "checkout.shipping.default" }`'));
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const labelProp = getProperty(e, "label");
|
|
148
|
+
const label = literalText(labelProp?.initializer);
|
|
149
|
+
if (labelProp && label === undefined)
|
|
150
|
+
issues.push(flowsNotStatic(labelProp.initializer, "the arrow's label", '`label: "Pay now"`'));
|
|
151
|
+
edges.push({ from, to, ...(label !== undefined ? { label } : {}), ...locate(sf, e) });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let nodes;
|
|
155
|
+
const nodesProp = getProperty(el, "nodes");
|
|
156
|
+
if (nodesProp) {
|
|
157
|
+
if (!ts.isArrayLiteralExpression(nodesProp.initializer)) {
|
|
158
|
+
issues.push(flowsNotStatic(nodesProp.initializer, "the flow's steps (nodes)", '`nodes: ["cart.default"]`'));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
nodes = [];
|
|
162
|
+
for (const n of nodesProp.initializer.elements) {
|
|
163
|
+
const ref = literalText(n);
|
|
164
|
+
if (ref === undefined)
|
|
165
|
+
issues.push(flowsNotStatic(n, "each step", '`"cart.default"`'));
|
|
166
|
+
else
|
|
167
|
+
nodes.push({ ref, at: locate(sf, n) });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (id !== undefined && title !== undefined)
|
|
172
|
+
flows.push({ id, title, edges, nodes, ...locate(sf, el) });
|
|
173
|
+
}
|
|
174
|
+
return { flows, issues };
|
|
175
|
+
}
|
|
176
|
+
const cache = new Map();
|
|
177
|
+
/** Parses a project file, reusing the parse while its text is unchanged (keeps repeat runs fast). */
|
|
178
|
+
export function parseProjectFile(project, rel) {
|
|
179
|
+
const text = readFileSync(project.abs(rel), "utf8");
|
|
180
|
+
const hit = cache.get(project.abs(rel));
|
|
181
|
+
if (hit && hit.text === text)
|
|
182
|
+
return hit.sf;
|
|
183
|
+
const sf = parseSource(rel, text);
|
|
184
|
+
cache.set(project.abs(rel), { text, sf });
|
|
185
|
+
return sf;
|
|
186
|
+
}
|
|
187
|
+
/** Reads every screen registration and src/flows.ts. Never runs prototype code. */
|
|
188
|
+
export function readRegistry(project, files) {
|
|
189
|
+
const issues = [];
|
|
190
|
+
const screens = [];
|
|
191
|
+
const seen = new Map();
|
|
192
|
+
let complete = true;
|
|
193
|
+
for (const rel of files.filter(isScreenFile)) {
|
|
194
|
+
const r = readScreen(parseProjectFile(project, rel));
|
|
195
|
+
issues.push(...r.issues);
|
|
196
|
+
if (!r.screen) {
|
|
197
|
+
complete = false;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const other = seen.get(r.screen.id);
|
|
201
|
+
if (other) {
|
|
202
|
+
issues.push({
|
|
203
|
+
code: "code-duplicate-screen",
|
|
204
|
+
severity: "error",
|
|
205
|
+
file: r.screen.file,
|
|
206
|
+
path: "",
|
|
207
|
+
line: r.screen.line,
|
|
208
|
+
column: r.screen.column,
|
|
209
|
+
message: `The screen id "${r.screen.id}" is already used by ${other.file}. Each screen needs its own id.`,
|
|
210
|
+
});
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
seen.set(r.screen.id, r.screen);
|
|
214
|
+
screens.push(r.screen);
|
|
215
|
+
}
|
|
216
|
+
let flows = [];
|
|
217
|
+
if (existsSync(project.abs(LAYOUT.flowsTs))) {
|
|
218
|
+
const r = readFlows(parseProjectFile(project, LAYOUT.flowsTs));
|
|
219
|
+
issues.push(...r.issues);
|
|
220
|
+
flows = r.flows;
|
|
221
|
+
}
|
|
222
|
+
return { screens, flows, issues, complete };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ContractView } from "../project.js";
|
|
2
|
+
/** Stands in for a `${...}` substitution when a template literal's text is checked. */
|
|
3
|
+
export declare const SUBSTITUTION = "\u0001";
|
|
4
|
+
export type Finding = {
|
|
5
|
+
kind: "color";
|
|
6
|
+
literal: string;
|
|
7
|
+
message: string;
|
|
8
|
+
suggestion?: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "size";
|
|
11
|
+
literal: string;
|
|
12
|
+
message: string;
|
|
13
|
+
suggestion?: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "unknown-token";
|
|
16
|
+
literal: string;
|
|
17
|
+
message: string;
|
|
18
|
+
suggestion?: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Checks one CSS declaration (or inline style property). `prop` may be camelCase.
|
|
22
|
+
* Token variables, 0, auto, inherit, transparent, currentColor and percentages are fine.
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkCssValue(contract: ContractView, rawProp: string, value: string): Finding[];
|
|
25
|
+
/** A bare number in a React inline style means pixels. */
|
|
26
|
+
export declare function checkCssNumber(contract: ContractView, rawProp: string, n: number): Finding[];
|
|
27
|
+
export declare const FINDING_CODES: {
|
|
28
|
+
readonly color: "code-hardcoded-color";
|
|
29
|
+
readonly size: "code-hardcoded-size";
|
|
30
|
+
readonly "unknown-token": "code-unknown-token";
|
|
31
|
+
};
|