swatch-token 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 +21 -0
- package/README.md +169 -2
- package/dist/cli.js +660 -0
- package/dist/client.js +81 -0
- package/dist/server/files.d.ts +16 -0
- package/dist/server/guard.d.ts +13 -0
- package/dist/server/project.d.ts +71 -0
- package/dist/server/requests.d.ts +42 -0
- package/dist/server/stylesheet.d.ts +51 -0
- package/dist/vite.d.ts +4 -0
- package/dist/vite.js +629 -0
- package/package.json +63 -4
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Change, type Edit } from "./stylesheet.js";
|
|
2
|
+
export declare function readSheet(file: string): {
|
|
3
|
+
tokens: Map<string, {
|
|
4
|
+
light?: string;
|
|
5
|
+
dark?: string;
|
|
6
|
+
}>;
|
|
7
|
+
dark: import("./stylesheet.ts").DarkSelector | null;
|
|
8
|
+
};
|
|
9
|
+
/** The whole batch on one read and one write, so a save of forty values is
|
|
10
|
+
* one change to the file and one hot reload. A failed check writes
|
|
11
|
+
* nothing. */
|
|
12
|
+
export declare function write(file: string, edits: Edit[]): Change[];
|
|
13
|
+
/** Several files' batches as one save: every file's new text is worked out
|
|
14
|
+
* before any is written, and if a write fails part-way the files already
|
|
15
|
+
* written are put back as they were. Either all of them change or none. */
|
|
16
|
+
export declare function writeAll(batches: Map<string, Edit[]>): Change[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
export type Trust = {
|
|
3
|
+
/** Vite's `server.allowedHosts`: true for any host, or a list (a leading "." allows subdomains) */
|
|
4
|
+
allowedHosts?: true | string[];
|
|
5
|
+
/** origins named in Swatch's options, e.g. "https://my-tunnel.example" */
|
|
6
|
+
allowedOrigins?: string[];
|
|
7
|
+
};
|
|
8
|
+
/** Why a write is refused, or null when it may go ahead. */
|
|
9
|
+
export declare function refuseWrite(req: Pick<IncomingMessage, "headers"> & {
|
|
10
|
+
socket: {
|
|
11
|
+
remoteAddress?: string;
|
|
12
|
+
};
|
|
13
|
+
}, trust?: Trust): string | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { THEMES, type Change, type DarkSelector, type Edit, type Theme } from "./stylesheet.js";
|
|
2
|
+
export type Options = {
|
|
3
|
+
/** The stylesheet(s) the tokens live in, from the project root. Left
|
|
4
|
+
* out, every stylesheet in the project that declares custom properties
|
|
5
|
+
* on a theme is used. */
|
|
6
|
+
css?: string | string[];
|
|
7
|
+
/** Where uses are counted, from the project root. Default: the whole
|
|
8
|
+
* project, without the folders below. */
|
|
9
|
+
src?: string;
|
|
10
|
+
/** Section titles for the panel, each with a pattern its token names
|
|
11
|
+
* match, tried in order. Left out, tokens are grouped by the first
|
|
12
|
+
* word of their name. */
|
|
13
|
+
groups?: Record<string, RegExp | string>;
|
|
14
|
+
/** Show "Save & send to agent" and "Figma sync", which leave requests in
|
|
15
|
+
* `.swatch/requests.jsonl` for a coding agent to pick up. */
|
|
16
|
+
agent?: boolean;
|
|
17
|
+
/** Folders, from the project root, that are neither searched for
|
|
18
|
+
* stylesheets nor counted for uses (node_modules, hidden folders and the
|
|
19
|
+
* build output are left out already). */
|
|
20
|
+
ignore?: string[];
|
|
21
|
+
/** Origins besides the dev server's own that may save, e.g. a tunnel's
|
|
22
|
+
* "https://my-tunnel.example" (hosts in Vite's `server.allowedHosts`
|
|
23
|
+
* are trusted already). */
|
|
24
|
+
allowedOrigins?: string[];
|
|
25
|
+
};
|
|
26
|
+
export type Token = {
|
|
27
|
+
name: string;
|
|
28
|
+
light?: string;
|
|
29
|
+
dark?: string;
|
|
30
|
+
/** the stylesheet each value is in, from the project root */
|
|
31
|
+
file: string;
|
|
32
|
+
/** how its stylesheet selects the dark theme, where that differs from the project's */
|
|
33
|
+
darkAt?: DarkSelector;
|
|
34
|
+
uses: {
|
|
35
|
+
file: string;
|
|
36
|
+
n: number;
|
|
37
|
+
}[];
|
|
38
|
+
};
|
|
39
|
+
export type Sheet = {
|
|
40
|
+
files: string[];
|
|
41
|
+
tokens: Token[];
|
|
42
|
+
dark: DarkSelector | null;
|
|
43
|
+
groups: [string, string][] | null;
|
|
44
|
+
agent: boolean;
|
|
45
|
+
changes?: Change[];
|
|
46
|
+
};
|
|
47
|
+
export declare class Project {
|
|
48
|
+
readonly root: string;
|
|
49
|
+
readonly options: Options;
|
|
50
|
+
/** folders left out of every search, absolute */
|
|
51
|
+
private readonly skip;
|
|
52
|
+
private watching;
|
|
53
|
+
private sheets;
|
|
54
|
+
private sources;
|
|
55
|
+
constructor(root: string, options?: Options, skip?: string[]);
|
|
56
|
+
private get src();
|
|
57
|
+
watch(): void;
|
|
58
|
+
/** A file changed (or was added or removed: `listChanged`). */
|
|
59
|
+
forget(path: string, listChanged: boolean): void;
|
|
60
|
+
/** The stylesheets that hold tokens: the ones named, or every one in the
|
|
61
|
+
* project that declares a custom property on a theme. */
|
|
62
|
+
stylesheets(): string[];
|
|
63
|
+
read(): Sheet;
|
|
64
|
+
/** Sends each edit to the stylesheet that holds the token in that theme;
|
|
65
|
+
* failing that, the one that holds it in the other theme; failing that
|
|
66
|
+
* (a new token), the one with the most tokens. Every edit is checked,
|
|
67
|
+
* and every file's new text worked out, before any file is touched. */
|
|
68
|
+
write(edits: Edit[]): Change[];
|
|
69
|
+
}
|
|
70
|
+
export { THEMES };
|
|
71
|
+
export type { Change, Edit, Theme };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Change, type Theme } from "./stylesheet.js";
|
|
2
|
+
export type Request = {
|
|
3
|
+
kind: "commit";
|
|
4
|
+
changes: Change[];
|
|
5
|
+
} | {
|
|
6
|
+
kind: "figma-sync";
|
|
7
|
+
figma: string;
|
|
8
|
+
};
|
|
9
|
+
export type Queued = Request & {
|
|
10
|
+
id: string;
|
|
11
|
+
at: string;
|
|
12
|
+
files: string[];
|
|
13
|
+
};
|
|
14
|
+
export type Proposal = Record<string, Partial<Record<Theme, string>>>;
|
|
15
|
+
export declare class Queue {
|
|
16
|
+
readonly dir: string;
|
|
17
|
+
readonly incoming: string;
|
|
18
|
+
constructor(root: string);
|
|
19
|
+
/** The queue holds only what was checked field by field: nothing a
|
|
20
|
+
* caller adds to the body, and no field of ours a caller can replace. */
|
|
21
|
+
add(r: Request, files: string[]): {
|
|
22
|
+
id: string;
|
|
23
|
+
};
|
|
24
|
+
/** What the agent left, or null (also while it is half written). */
|
|
25
|
+
take(): unknown;
|
|
26
|
+
clear(): void;
|
|
27
|
+
private get file();
|
|
28
|
+
private seen;
|
|
29
|
+
/** The requests no agent has dealt with yet, oldest first. A request that
|
|
30
|
+
* has been dealt with is taken out of the file (below), so the file only
|
|
31
|
+
* ever holds what is pending, and stays small. */
|
|
32
|
+
pending(): Queued[];
|
|
33
|
+
/** Takes a request out of the queue, as dealt with, and notes it (with
|
|
34
|
+
* its note) in done.jsonl, which keeps the last hundred. The panel may
|
|
35
|
+
* append a request while this rewrites the file: the file is read again
|
|
36
|
+
* and the rewrite retried if it grew in between, so no request is lost. */
|
|
37
|
+
resolve(id: string, note?: string): void;
|
|
38
|
+
/** Leaves values for the panel to load as unsaved edits: every one
|
|
39
|
+
* checked as a write would be, and the file put in place whole, so the
|
|
40
|
+
* panel never reads half of it. Returns how many values. */
|
|
41
|
+
propose(edits: Proposal, note?: string): number;
|
|
42
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type AtRule, type Declaration, type Root, type Rule } from "postcss";
|
|
2
|
+
export type Theme = "light" | "dark";
|
|
3
|
+
export declare const THEMES: Theme[];
|
|
4
|
+
export type Edit = {
|
|
5
|
+
theme: Theme;
|
|
6
|
+
name: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
export type Change = {
|
|
10
|
+
name: string;
|
|
11
|
+
theme: Theme;
|
|
12
|
+
from: string | null;
|
|
13
|
+
to: string | null;
|
|
14
|
+
};
|
|
15
|
+
/** A block that holds a theme's declarations: a rule, or an `@theme` block. */
|
|
16
|
+
type Block = Rule | AtRule;
|
|
17
|
+
type Found = {
|
|
18
|
+
decl: Declaration;
|
|
19
|
+
theme: Theme;
|
|
20
|
+
};
|
|
21
|
+
export type DarkSelector = {
|
|
22
|
+
selector: string;
|
|
23
|
+
media: string | null;
|
|
24
|
+
};
|
|
25
|
+
export type Parsed = {
|
|
26
|
+
root: Root;
|
|
27
|
+
decls: Found[];
|
|
28
|
+
blocks: Record<Theme, Block[]>;
|
|
29
|
+
dark: DarkSelector | null;
|
|
30
|
+
};
|
|
31
|
+
export declare function parse(css: string, from: string): Parsed;
|
|
32
|
+
/** A declaration's value as the panel shows it. */
|
|
33
|
+
export declare const shown: (d: Declaration | undefined) => string | null;
|
|
34
|
+
/** Every custom property of the two themes in one stylesheet. The last
|
|
35
|
+
* declaration in a theme is the one the cascade uses. */
|
|
36
|
+
export declare function readText(css: string, from?: string): {
|
|
37
|
+
tokens: Map<string, {
|
|
38
|
+
light?: string;
|
|
39
|
+
dark?: string;
|
|
40
|
+
}>;
|
|
41
|
+
dark: DarkSelector | null;
|
|
42
|
+
};
|
|
43
|
+
export declare function check(e: Edit): void;
|
|
44
|
+
/** The stylesheet with a batch of edits applied, and what each changed. A
|
|
45
|
+
* failed check, or a result that would not read back as a stylesheet,
|
|
46
|
+
* throws and gives nothing. */
|
|
47
|
+
export declare function writeText(css: string, edits: Edit[], from?: string): {
|
|
48
|
+
css: string;
|
|
49
|
+
changes: Change[];
|
|
50
|
+
};
|
|
51
|
+
export {};
|
package/dist/vite.d.ts
ADDED