@cssints/css-grammar 0.0.0-stage → 0.2.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.
@@ -0,0 +1,146 @@
1
+ import { Consume, Matches, Parse, Stuck, Unexpected } from "./css.mjs";
2
+ import { CSSStyleValue } from "./values.mjs";
3
+ //#region src/token.d.ts
4
+ /**
5
+ * Per token type, by the name of `token.<name>`:
6
+ * - `syntax`: the `@property` syntax, `<syntax>`, checked by the twin and by `ValidSyntax`;
7
+ * - `sentinels`: the typed-value types the token stands for in a property value (`⟨length⟩`, api-typed.ts);
8
+ * - `probes`: literals of the type that a build-time check puts in place of the token (one per sentinel), since the
9
+ * recognizer reads text and a token is `var(--name)`;
10
+ * - `grammar`: the grammar of a value when it is not `<syntax>` (a list of shadows);
11
+ * - `property`: the `@property` syntax when `<syntax>` is not one `@property` takes: `*`, any value, which a browser
12
+ * does not check or animate (an easing function, a shadow).
13
+ */
14
+ export declare const TOKEN_TYPES: {
15
+ readonly color: {
16
+ readonly syntax: "color";
17
+ readonly sentinels: readonly ["color"];
18
+ readonly probes: readonly ["red"];
19
+ };
20
+ readonly length: {
21
+ readonly syntax: "length";
22
+ readonly sentinels: readonly ["length"];
23
+ readonly probes: readonly ["1px"];
24
+ };
25
+ readonly percentage: {
26
+ readonly syntax: "percentage";
27
+ readonly sentinels: readonly ["percentage"];
28
+ readonly probes: readonly ["1%"];
29
+ };
30
+ readonly lengthPercentage: {
31
+ readonly syntax: "length-percentage";
32
+ readonly sentinels: readonly ["length", "percentage"];
33
+ readonly probes: readonly ["1px", "1%"];
34
+ };
35
+ readonly number: {
36
+ readonly syntax: "number";
37
+ readonly sentinels: readonly ["number"];
38
+ readonly probes: readonly ["1"];
39
+ };
40
+ readonly integer: {
41
+ readonly syntax: "integer";
42
+ readonly sentinels: readonly ["integer"];
43
+ readonly probes: readonly ["1"];
44
+ };
45
+ readonly angle: {
46
+ readonly syntax: "angle";
47
+ readonly sentinels: readonly ["angle"];
48
+ readonly probes: readonly ["1deg"];
49
+ };
50
+ readonly time: {
51
+ readonly syntax: "time";
52
+ readonly sentinels: readonly ["time"];
53
+ readonly probes: readonly ["1s"];
54
+ };
55
+ readonly customIdent: {
56
+ readonly syntax: "custom-ident";
57
+ readonly sentinels: readonly ["custom-ident"];
58
+ readonly probes: readonly ["x"];
59
+ };
60
+ readonly resolution: {
61
+ readonly syntax: "resolution";
62
+ readonly sentinels: readonly ["resolution"];
63
+ readonly probes: readonly ["1dppx"];
64
+ };
65
+ readonly url: {
66
+ readonly syntax: "url";
67
+ readonly sentinels: readonly ["url"];
68
+ readonly probes: readonly ["url(x)"];
69
+ };
70
+ readonly image: {
71
+ readonly syntax: "image";
72
+ readonly sentinels: readonly ["image"];
73
+ readonly probes: readonly ["linear-gradient(red, blue)"];
74
+ };
75
+ readonly transformList: {
76
+ readonly syntax: "transform-list";
77
+ readonly sentinels: readonly ["transform-list"];
78
+ readonly probes: readonly ["translateX(1px)"];
79
+ };
80
+ readonly easingFunction: {
81
+ readonly syntax: "easing-function";
82
+ readonly sentinels: readonly ["easing-function"];
83
+ readonly probes: readonly ["ease"];
84
+ readonly property: "*";
85
+ };
86
+ readonly shadow: {
87
+ readonly syntax: "shadow";
88
+ readonly sentinels: readonly ["shadow"];
89
+ readonly probes: readonly ["0 0 red"];
90
+ readonly grammar: "<shadow>#";
91
+ readonly property: "*";
92
+ };
93
+ };
94
+ export type TokenType = keyof typeof TOKEN_TYPES;
95
+ /**
96
+ * The grammar of a value of a token type.
97
+ * @param {string} syntax the `syntax` of the token type
98
+ * @returns {string} `<syntax>`, or the type's `grammar`
99
+ */
100
+ export declare const grammarOf: (syntax: string) => string;
101
+ /**
102
+ * DTCG `$type` to token type (createTokens, docs/API.md "Themes"). `fontWeight` is a number: its keywords become numbers.
103
+ * The other DTCG types (`fontFamily`, `strokeStyle`, `border`, `transition`, `gradient`, `typography`) are an error.
104
+ */
105
+ export declare const DTCG_TYPES: {
106
+ readonly color: "color";
107
+ readonly dimension: "length";
108
+ readonly number: "number";
109
+ readonly duration: "time";
110
+ readonly fontWeight: "number";
111
+ readonly cubicBezier: "easingFunction";
112
+ readonly shadow: "shadow";
113
+ };
114
+ export type DtcgType = keyof typeof DTCG_TYPES;
115
+ export type Syntax<K extends TokenType> = (typeof TOKEN_TYPES)[K]["syntax"];
116
+ /** The grammar of a value of the token type `K` (`grammarOf`). */
117
+ export type Grammar<K extends TokenType> = (typeof TOKEN_TYPES)[K] extends {
118
+ readonly grammar: infer G extends string;
119
+ } ? G : `<${Syntax<K>}>`;
120
+ type Trim<S extends string> = S extends ` ${infer R}` ? Trim<R> : S;
121
+ /** The value, or a message naming the bad token, like `Valid` for a property. */
122
+ export type ValidSyntax<K extends string, S extends string, G extends string = `<${K}>`> = Matches<G, S> extends true ? S : S extends string ? `${K}: ${Unexpected<Stuck<Trim<S> | Consume<Parse<G>, Trim<S>>>>} in "${S}", grammar ${G}` : never;
123
+ /** `ValidSyntax` for a value of the token type `K`. */
124
+ export type ValidToken<K extends TokenType, S extends string> = ValidSyntax<Syntax<K>, S, Grammar<K>>;
125
+ /**
126
+ * A token: a Typed OM value of its type whose text is `var(--name)`. `Settable` is whether it has a name. `V` is the value of
127
+ * the definition as text, inferred by `createTokens` (`"#545434"`, `"{color.base}"` for an alias), `string` where nothing
128
+ * says; a covariant phantom, so a token of any `V` is a `Token<K, S>`.
129
+ */
130
+ export interface Token<K extends TokenType = TokenType, Settable extends boolean = boolean, V extends string = string> extends CSSStyleValue<(typeof TOKEN_TYPES)[K]["sentinels"][number]> {
131
+ readonly "~token": K;
132
+ readonly "~settable": Settable;
133
+ readonly "~value": V;
134
+ }
135
+ /** `--name`, and whether the variable inherits (default true). */
136
+ export interface TokenName {
137
+ var: string;
138
+ inherit?: boolean;
139
+ }
140
+ /** An inline style: what `style()` and `token.set()` give, for a `style` prop. */
141
+ export type StyleObject = Record<string, string>;
142
+ /** `token.<type>(initial, name?)`: with a name the token can be set, without one it is private. */
143
+ export type TokenFn<K extends TokenType> = <const I extends string, const N extends string | TokenName | undefined = undefined>(initial: ValidToken<K, I>, name?: N) => Token<K, [N] extends [undefined] ? false : true>;
144
+ /** `token.set(token, value)`: a style object with one custom property. A private token cannot be set. */
145
+ export type TokenSetFn = <const K extends TokenType, const V extends string>(token: Token<K, true>, value: ValidToken<K, V>) => StyleObject;
146
+ //#endregion
package/dist/token.mjs ADDED
@@ -0,0 +1,112 @@
1
+ //#region src/token.ts
2
+ /**
3
+ * Per token type, by the name of `token.<name>`:
4
+ * - `syntax`: the `@property` syntax, `<syntax>`, checked by the twin and by `ValidSyntax`;
5
+ * - `sentinels`: the typed-value types the token stands for in a property value (`⟨length⟩`, api-typed.ts);
6
+ * - `probes`: literals of the type that a build-time check puts in place of the token (one per sentinel), since the
7
+ * recognizer reads text and a token is `var(--name)`;
8
+ * - `grammar`: the grammar of a value when it is not `<syntax>` (a list of shadows);
9
+ * - `property`: the `@property` syntax when `<syntax>` is not one `@property` takes: `*`, any value, which a browser
10
+ * does not check or animate (an easing function, a shadow).
11
+ */
12
+ const TOKEN_TYPES = {
13
+ color: {
14
+ syntax: "color",
15
+ sentinels: ["color"],
16
+ probes: ["red"]
17
+ },
18
+ length: {
19
+ syntax: "length",
20
+ sentinels: ["length"],
21
+ probes: ["1px"]
22
+ },
23
+ percentage: {
24
+ syntax: "percentage",
25
+ sentinels: ["percentage"],
26
+ probes: ["1%"]
27
+ },
28
+ lengthPercentage: {
29
+ syntax: "length-percentage",
30
+ sentinels: ["length", "percentage"],
31
+ probes: ["1px", "1%"]
32
+ },
33
+ number: {
34
+ syntax: "number",
35
+ sentinels: ["number"],
36
+ probes: ["1"]
37
+ },
38
+ integer: {
39
+ syntax: "integer",
40
+ sentinels: ["integer"],
41
+ probes: ["1"]
42
+ },
43
+ angle: {
44
+ syntax: "angle",
45
+ sentinels: ["angle"],
46
+ probes: ["1deg"]
47
+ },
48
+ time: {
49
+ syntax: "time",
50
+ sentinels: ["time"],
51
+ probes: ["1s"]
52
+ },
53
+ customIdent: {
54
+ syntax: "custom-ident",
55
+ sentinels: ["custom-ident"],
56
+ probes: ["x"]
57
+ },
58
+ resolution: {
59
+ syntax: "resolution",
60
+ sentinels: ["resolution"],
61
+ probes: ["1dppx"]
62
+ },
63
+ url: {
64
+ syntax: "url",
65
+ sentinels: ["url"],
66
+ probes: ["url(x)"]
67
+ },
68
+ image: {
69
+ syntax: "image",
70
+ sentinels: ["image"],
71
+ probes: ["linear-gradient(red, blue)"]
72
+ },
73
+ transformList: {
74
+ syntax: "transform-list",
75
+ sentinels: ["transform-list"],
76
+ probes: ["translateX(1px)"]
77
+ },
78
+ easingFunction: {
79
+ syntax: "easing-function",
80
+ sentinels: ["easing-function"],
81
+ probes: ["ease"],
82
+ property: "*"
83
+ },
84
+ shadow: {
85
+ syntax: "shadow",
86
+ sentinels: ["shadow"],
87
+ probes: ["0 0 red"],
88
+ grammar: "<shadow>#",
89
+ property: "*"
90
+ }
91
+ };
92
+ /**
93
+ * The grammar of a value of a token type.
94
+ * @param {string} syntax the `syntax` of the token type
95
+ * @returns {string} `<syntax>`, or the type's `grammar`
96
+ */
97
+ const grammarOf = (syntax) => Object.values(TOKEN_TYPES).find((t) => t.syntax === syntax)?.grammar ?? `<${syntax}>`;
98
+ /**
99
+ * DTCG `$type` to token type (createTokens, docs/API.md "Themes"). `fontWeight` is a number: its keywords become numbers.
100
+ * The other DTCG types (`fontFamily`, `strokeStyle`, `border`, `transition`, `gradient`, `typography`) are an error.
101
+ */
102
+ const DTCG_TYPES = {
103
+ color: "color",
104
+ dimension: "length",
105
+ number: "number",
106
+ duration: "time",
107
+ fontWeight: "number",
108
+ cubicBezier: "easingFunction",
109
+ shadow: "shadow"
110
+ };
111
+ //#endregion
112
+ export { DTCG_TYPES, TOKEN_TYPES, grammarOf };
@@ -0,0 +1,48 @@
1
+ //#region src/twin-core.d.ts
2
+ type Tok = {
3
+ t: "type";
4
+ v: string;
5
+ lo?: string;
6
+ hi?: string;
7
+ } | {
8
+ t: "prop";
9
+ v: string;
10
+ } | {
11
+ t: "kw";
12
+ v: string;
13
+ } | {
14
+ t: "fn";
15
+ v: string;
16
+ } | {
17
+ t: "range";
18
+ lo: string;
19
+ hi: string;
20
+ } | {
21
+ t: "p";
22
+ v: string;
23
+ } | {
24
+ t: "lit";
25
+ v: string;
26
+ } | {
27
+ t: "eof";
28
+ };
29
+ export declare function next(s: string): [Tok, string];
30
+ export type Node = ["kw", string] | ["type", string, string?, string?] | ["prop", string] | ["fn", string, Node] | ["lit", string] | ["alt", Node[]] | ["or", Node[]] | ["and", Node[]] | ["seq", Node[]] | ["opt", Node] | ["star", Node] | ["plus", Node] | ["list", Node] | ["rep", Node, string, string] | ["bang", Node];
31
+ export declare function parseGrammar(s: string): Node;
32
+ export declare const spaced: (q: string) => string;
33
+ export declare const isNative: (name: string) => boolean;
34
+ interface Ctx {
35
+ len: number;
36
+ far: number;
37
+ expected: Set<string>;
38
+ pend?: boolean;
39
+ ch?: readonly string[];
40
+ why?: [at: number, text: string];
41
+ fix?: [at: number, written: string, canonical: string];
42
+ }
43
+ export declare function consume(n: Node, s: string, ctx: Ctx, label?: string): Set<string>;
44
+ export declare const magnitude: (t: string) => number;
45
+ export declare const nullable: (n: Node) => boolean;
46
+ export declare function matches(syntax: string, s: string, pending?: boolean): boolean;
47
+ export declare function valid(p: string, s: string, syntax?: string | undefined): string;
48
+ //#endregion