@terrazzo/parser 0.1.2 → 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.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +26 -0
- package/CONTRIBUTING.md +0 -12
- package/dist/build/index.d.ts +19 -0
- package/dist/build/index.js +165 -0
- package/dist/build/index.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +269 -0
- package/dist/config.js.map +1 -0
- package/{index.d.ts → dist/index.d.ts} +1 -5
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/code-frame.d.ts +30 -0
- package/dist/lib/code-frame.js +108 -0
- package/dist/lib/code-frame.js.map +1 -0
- package/dist/lint/index.d.ts +11 -0
- package/dist/lint/index.js +102 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/plugin-core/index.d.ts +12 -0
- package/dist/lint/plugin-core/index.js +40 -0
- package/dist/lint/plugin-core/index.js.map +1 -0
- package/dist/lint/plugin-core/lib/docs.d.ts +1 -0
- package/dist/lint/plugin-core/lib/docs.js +4 -0
- package/dist/lint/plugin-core/lib/docs.js.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.d.ts +39 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.js +58 -0
- package/dist/lint/plugin-core/rules/a11y-min-contrast.js.map +1 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.d.ts +13 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.js +45 -0
- package/dist/lint/plugin-core/rules/a11y-min-font-size.js.map +1 -0
- package/dist/lint/plugin-core/rules/colorspace.d.ts +14 -0
- package/dist/lint/plugin-core/rules/colorspace.js +85 -0
- package/dist/lint/plugin-core/rules/colorspace.js.map +1 -0
- package/dist/lint/plugin-core/rules/consistent-naming.d.ts +11 -0
- package/dist/lint/plugin-core/rules/consistent-naming.js +49 -0
- package/dist/lint/plugin-core/rules/consistent-naming.js.map +1 -0
- package/dist/lint/plugin-core/rules/descriptions.d.ts +9 -0
- package/dist/lint/plugin-core/rules/descriptions.js +32 -0
- package/dist/lint/plugin-core/rules/descriptions.js.map +1 -0
- package/dist/lint/plugin-core/rules/duplicate-values.d.ts +9 -0
- package/dist/lint/plugin-core/rules/duplicate-values.js +65 -0
- package/dist/lint/plugin-core/rules/duplicate-values.js.map +1 -0
- package/dist/lint/plugin-core/rules/max-gamut.d.ts +14 -0
- package/dist/lint/plugin-core/rules/max-gamut.js +101 -0
- package/dist/lint/plugin-core/rules/max-gamut.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-children.d.ts +18 -0
- package/dist/lint/plugin-core/rules/required-children.js +78 -0
- package/dist/lint/plugin-core/rules/required-children.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-modes.d.ts +13 -0
- package/dist/lint/plugin-core/rules/required-modes.js +52 -0
- package/dist/lint/plugin-core/rules/required-modes.js.map +1 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.d.ts +10 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.js +38 -0
- package/dist/lint/plugin-core/rules/required-typography-properties.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.js +123 -0
- package/dist/logger.js.map +1 -0
- package/dist/parse/alias.d.ts +51 -0
- package/dist/parse/alias.js +188 -0
- package/dist/parse/alias.js.map +1 -0
- package/dist/parse/index.d.ts +27 -0
- package/dist/parse/index.js +379 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/json.d.ts +36 -0
- package/dist/parse/json.js +88 -0
- package/dist/parse/json.js.map +1 -0
- package/dist/parse/normalize.d.ts +23 -0
- package/dist/parse/normalize.js +163 -0
- package/dist/parse/normalize.js.map +1 -0
- package/dist/parse/validate.d.ts +45 -0
- package/dist/parse/validate.js +601 -0
- package/dist/parse/validate.js.map +1 -0
- package/dist/types.d.ts +264 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +7 -7
- package/{build/index.js → src/build/index.ts} +47 -63
- package/src/config.ts +280 -0
- package/src/index.ts +18 -0
- package/{lib/code-frame.js → src/lib/code-frame.ts} +41 -8
- package/src/lint/index.ts +135 -0
- package/src/lint/plugin-core/index.ts +47 -0
- package/src/lint/plugin-core/lib/docs.ts +3 -0
- package/src/lint/plugin-core/rules/a11y-min-contrast.ts +91 -0
- package/src/lint/plugin-core/rules/a11y-min-font-size.ts +64 -0
- package/src/lint/plugin-core/rules/colorspace.ts +101 -0
- package/src/lint/plugin-core/rules/consistent-naming.ts +65 -0
- package/src/lint/plugin-core/rules/descriptions.ts +41 -0
- package/src/lint/plugin-core/rules/duplicate-values.ts +80 -0
- package/src/lint/plugin-core/rules/max-gamut.ts +121 -0
- package/src/lint/plugin-core/rules/required-children.ts +104 -0
- package/src/lint/plugin-core/rules/required-modes.ts +71 -0
- package/src/lint/plugin-core/rules/required-typography-properties.ts +53 -0
- package/{logger.js → src/logger.ts} +55 -16
- package/src/parse/alias.ts +224 -0
- package/src/parse/index.ts +457 -0
- package/src/parse/json.ts +106 -0
- package/{parse/normalize.js → src/parse/normalize.ts} +70 -23
- package/{parse/validate.js → src/parse/validate.ts} +159 -227
- package/src/types.ts +310 -0
- package/build/index.d.ts +0 -113
- package/config.d.ts +0 -64
- package/config.js +0 -206
- package/index.js +0 -35
- package/lib/code-frame.d.ts +0 -56
- package/lint/index.d.ts +0 -44
- package/lint/index.js +0 -59
- package/lint/plugin-core/index.d.ts +0 -3
- package/lint/plugin-core/index.js +0 -12
- package/lint/plugin-core/rules/duplicate-values.d.ts +0 -10
- package/lint/plugin-core/rules/duplicate-values.js +0 -68
- package/logger.d.ts +0 -71
- package/parse/index.d.ts +0 -45
- package/parse/index.js +0 -592
- package/parse/json.d.ts +0 -30
- package/parse/json.js +0 -94
- package/parse/normalize.d.ts +0 -3
- package/parse/validate.d.ts +0 -43
package/src/types.ts
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import type { AnyNode, DocumentNode } from '@humanwhocodes/momoa';
|
|
2
|
+
import type { TokenNormalized } from '@terrazzo/token-tools';
|
|
3
|
+
import type Logger from './logger.js';
|
|
4
|
+
|
|
5
|
+
export interface BuildHookOptions {
|
|
6
|
+
/** Map of tokens */
|
|
7
|
+
tokens: Record<string, TokenNormalized>;
|
|
8
|
+
/** Query transformed values */
|
|
9
|
+
getTransforms(params: TransformParams): TokenTransformed[];
|
|
10
|
+
/** Momoa documents */
|
|
11
|
+
sources: InputSource[];
|
|
12
|
+
outputFile: (
|
|
13
|
+
/** Filename to output (relative to outDir) */
|
|
14
|
+
filename: string,
|
|
15
|
+
/** Contents to write to file */
|
|
16
|
+
contents: string | Buffer,
|
|
17
|
+
) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface BuildRunnerResult {
|
|
21
|
+
outputFiles: OutputFile[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface BuildEndHookOptions {
|
|
25
|
+
/** Map of tokens */
|
|
26
|
+
tokens: Record<string, TokenNormalized>;
|
|
27
|
+
/** Query transformed values */
|
|
28
|
+
getTransforms(params: TransformParams): TokenTransformed[];
|
|
29
|
+
/** Momoa documents */
|
|
30
|
+
sources: InputSource[];
|
|
31
|
+
/** Final files to be written */
|
|
32
|
+
outputFiles: OutputFileExpanded[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// loosey-goosey user-defined config
|
|
36
|
+
export interface Config {
|
|
37
|
+
/**
|
|
38
|
+
* Path to tokens.json
|
|
39
|
+
* @default "./tokens.json"
|
|
40
|
+
*/
|
|
41
|
+
tokens?: string | string[];
|
|
42
|
+
/**
|
|
43
|
+
* Output directory
|
|
44
|
+
* @default "./tokens/"
|
|
45
|
+
*/
|
|
46
|
+
outDir?: string;
|
|
47
|
+
/** Specify plugins */
|
|
48
|
+
plugins?: Plugin[];
|
|
49
|
+
/** Specify linting settings */
|
|
50
|
+
lint?: {
|
|
51
|
+
/** Configure build behavior */
|
|
52
|
+
build?: {
|
|
53
|
+
/**
|
|
54
|
+
* Should linters run with `tz build`?
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
enabled?: boolean;
|
|
58
|
+
};
|
|
59
|
+
/** Configure lint rules */
|
|
60
|
+
rules?: Record<string, LintRuleShorthand | LintRuleLonghand>;
|
|
61
|
+
};
|
|
62
|
+
/** Ignore token groups */
|
|
63
|
+
ignore?: {
|
|
64
|
+
/** Token patterns to ignore. Accepts globs. */
|
|
65
|
+
tokens?: string[];
|
|
66
|
+
/** Ignore deprecated tokens */
|
|
67
|
+
deprecated?: boolean;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// normalized, finalized config
|
|
72
|
+
export interface ConfigInit {
|
|
73
|
+
tokens: URL[];
|
|
74
|
+
outDir: URL;
|
|
75
|
+
plugins: Plugin[];
|
|
76
|
+
lint: {
|
|
77
|
+
build: NonNullable<NonNullable<Config['lint']>['build']>;
|
|
78
|
+
rules: Record<string, [LintRuleSeverity, any]>;
|
|
79
|
+
};
|
|
80
|
+
ignore: {
|
|
81
|
+
tokens: string[];
|
|
82
|
+
deprecated: boolean;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ConfigOptions {
|
|
87
|
+
logger?: Logger;
|
|
88
|
+
/** @terrazzo/parser needs cwd so this can be run without Node.js. Importing defineConfig from @terrazzo/cli doesn’t need this. */
|
|
89
|
+
cwd: URL;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface InputSource {
|
|
93
|
+
filename?: URL;
|
|
94
|
+
src: string;
|
|
95
|
+
document: DocumentNode;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface LintNotice {
|
|
99
|
+
/** Lint message shown to the user */
|
|
100
|
+
message: string;
|
|
101
|
+
/** Erring node (used to point to a specific line) */
|
|
102
|
+
node?: AnyNode;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type LintRuleSeverity = 'error' | 'warn' | 'off';
|
|
106
|
+
export type LintRuleShorthand = LintRuleSeverity | 0 | 1 | 2;
|
|
107
|
+
export type LintRuleLonghand = [LintRuleSeverity | 0 | 1 | 2, any];
|
|
108
|
+
|
|
109
|
+
export interface LintRuleNormalized<O = any> {
|
|
110
|
+
id: string;
|
|
111
|
+
severity: LintRuleSeverity;
|
|
112
|
+
options?: O;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type LintReportDescriptor<MessageIds extends string> = {
|
|
116
|
+
/** To error on a specific token source file, provide an erring node */
|
|
117
|
+
node?: AnyNode;
|
|
118
|
+
/** To error on a specific token source file, also provide the source */
|
|
119
|
+
source?: InputSource;
|
|
120
|
+
/** Provide data for messages */
|
|
121
|
+
data?: Record<string, unknown>;
|
|
122
|
+
} & (
|
|
123
|
+
| {
|
|
124
|
+
/** Provide the error message to display */
|
|
125
|
+
message: string;
|
|
126
|
+
messageId?: never;
|
|
127
|
+
}
|
|
128
|
+
| {
|
|
129
|
+
message?: never;
|
|
130
|
+
/** Provide the error message ID */
|
|
131
|
+
messageId: MessageIds;
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Note: lint types intentionally steal the API from ESLint. Options were
|
|
136
|
+
// omitted where they don’t make sense (or were deprecated from ESLint—we don’t
|
|
137
|
+
// need to worry about backwards compat). The types also leave room in the
|
|
138
|
+
// future to be expanded easily if needed.
|
|
139
|
+
|
|
140
|
+
export interface LintRule<
|
|
141
|
+
MessageIds extends string,
|
|
142
|
+
LintRuleOptions extends object | undefined = undefined,
|
|
143
|
+
LintRuleDocs = unknown,
|
|
144
|
+
> {
|
|
145
|
+
meta?: LintRuleMetaData<MessageIds, LintRuleOptions, LintRuleDocs>;
|
|
146
|
+
/**
|
|
147
|
+
* Function which returns an object with methods that ESLint calls to “visit”
|
|
148
|
+
* nodes while traversing the abstract syntax tree.
|
|
149
|
+
*/
|
|
150
|
+
create(context: Readonly<LintRuleContext<MessageIds, LintRuleOptions>>): void | Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Default options the rule will be run with
|
|
153
|
+
*/
|
|
154
|
+
defaultOptions: LintRuleOptions;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface LintRuleContext<MessageIds extends string, LintRuleOptions extends object | undefined = undefined> {
|
|
158
|
+
/** The rule ID. */
|
|
159
|
+
id: string;
|
|
160
|
+
/**
|
|
161
|
+
* An array of the configured options for this rule. This array does not
|
|
162
|
+
* include the rule severity.
|
|
163
|
+
*/
|
|
164
|
+
options: LintRuleOptions;
|
|
165
|
+
/** The current working directory. */
|
|
166
|
+
cwd?: URL;
|
|
167
|
+
/** Source file the token came from. */
|
|
168
|
+
src: string;
|
|
169
|
+
/** Source file location. */
|
|
170
|
+
filename?: URL;
|
|
171
|
+
/** ID:Token map of all tokens. */
|
|
172
|
+
tokens: Record<string, TokenNormalized>;
|
|
173
|
+
/** Reports a problem in the code. */
|
|
174
|
+
report(descriptor: LintReportDescriptor<MessageIds>): void;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface LintRuleMetaData<
|
|
178
|
+
MessageIds extends string,
|
|
179
|
+
LintRuleOptions extends object | undefined = undefined,
|
|
180
|
+
LintRuleDocs = unknown,
|
|
181
|
+
> {
|
|
182
|
+
/**
|
|
183
|
+
* Documentation for the rule
|
|
184
|
+
*/
|
|
185
|
+
docs?: LintRuleDocs & LintRuleMetaDataDocs;
|
|
186
|
+
/**
|
|
187
|
+
* A map of messages which the rule can report. The key is the messageId, and
|
|
188
|
+
* the string is the parameterised error string.
|
|
189
|
+
*/
|
|
190
|
+
messages?: Record<MessageIds, string>;
|
|
191
|
+
/**
|
|
192
|
+
* Specifies default options for the rule. If present, any user-provided
|
|
193
|
+
* options in their config will be merged on top of them recursively. This
|
|
194
|
+
* merging will be applied directly to `context.options`.
|
|
195
|
+
*/
|
|
196
|
+
defaultOptions?: LintRuleOptions;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface LintRuleMetaDataDocs {
|
|
200
|
+
/** Concise description of the rule. */
|
|
201
|
+
description: string;
|
|
202
|
+
/** The URL of the rule's docs. */
|
|
203
|
+
url?: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface OutputFile {
|
|
207
|
+
/** Filename, relative to outDir */
|
|
208
|
+
filename: string;
|
|
209
|
+
/** File contents */
|
|
210
|
+
contents: string | Buffer;
|
|
211
|
+
/** Plugin name that generated the file */
|
|
212
|
+
plugin?: string;
|
|
213
|
+
/** Time taken to generate file */
|
|
214
|
+
time?: number;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface OutputFileExpanded extends OutputFile {
|
|
218
|
+
/** The `name` of the plugin that produced this file. */
|
|
219
|
+
plugin: string;
|
|
220
|
+
/** How long this output took to make. */
|
|
221
|
+
time: number;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface Plugin {
|
|
225
|
+
name: string;
|
|
226
|
+
/** Read config, and optionally modify */
|
|
227
|
+
// biome-ignore lint/suspicious/noConfusingVoidType format: this helps plugins be a little looser on their typing
|
|
228
|
+
config?(config: ConfigInit): void | ConfigInit | undefined;
|
|
229
|
+
/**
|
|
230
|
+
* Declare:
|
|
231
|
+
* - `"pre"`: run this plugin BEFORE all others
|
|
232
|
+
* - `"post"`: run this plugin AFTER all others
|
|
233
|
+
* - (default) run this plugin in default order (array order)
|
|
234
|
+
*/
|
|
235
|
+
enforce?: 'pre' | 'post';
|
|
236
|
+
/** Throw lint errors/warnings */
|
|
237
|
+
lint?(): Record<string, LintRule<any, any, any>>;
|
|
238
|
+
transform?(options: TransformHookOptions): Promise<void>;
|
|
239
|
+
build?(options: BuildHookOptions): Promise<void>;
|
|
240
|
+
buildEnd?(result: BuildRunnerResult): Promise<void>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Transformed token with a single value. Note that this may be any type! */
|
|
244
|
+
export interface TokenTransformedSingleValue {
|
|
245
|
+
/** Original Token ID */
|
|
246
|
+
id: string;
|
|
247
|
+
/** ID unique to this format. */
|
|
248
|
+
localID?: string;
|
|
249
|
+
type: 'SINGLE_VALUE';
|
|
250
|
+
value: string;
|
|
251
|
+
/**
|
|
252
|
+
* The mode of this value
|
|
253
|
+
* @default "."
|
|
254
|
+
*/
|
|
255
|
+
mode: string;
|
|
256
|
+
/** The original token. */
|
|
257
|
+
token: TokenNormalized;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Transformed token with multiple values. Note that this may be any type! */
|
|
261
|
+
export interface TokenTransformedMultiValue {
|
|
262
|
+
/** Original Token ID */
|
|
263
|
+
id: string;
|
|
264
|
+
/** ID unique to this format.*/
|
|
265
|
+
localID?: string;
|
|
266
|
+
type: 'MULTI_VALUE';
|
|
267
|
+
value: Record<string, string>;
|
|
268
|
+
/**
|
|
269
|
+
* The mode of this value
|
|
270
|
+
* @default "."
|
|
271
|
+
*/
|
|
272
|
+
mode: string;
|
|
273
|
+
/** The original token */
|
|
274
|
+
token: TokenNormalized;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type TokenTransformed = TokenTransformedSingleValue | TokenTransformedMultiValue;
|
|
278
|
+
|
|
279
|
+
export interface TransformParams {
|
|
280
|
+
/** ID of an existing format */
|
|
281
|
+
format: string;
|
|
282
|
+
/** Glob of tokens to select (e.g. `"color.*"` to select all tokens starting with `"color."`) */
|
|
283
|
+
id?: string | string[];
|
|
284
|
+
/** $type(s) to filter for */
|
|
285
|
+
$type?: string | string[];
|
|
286
|
+
/**
|
|
287
|
+
* Mode name, if selecting a mode
|
|
288
|
+
* @default "."
|
|
289
|
+
*/
|
|
290
|
+
mode?: string | string[];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface TransformHookOptions {
|
|
294
|
+
/** Map of tokens */
|
|
295
|
+
tokens: Record<string, TokenNormalized>;
|
|
296
|
+
/** Query transformed values */
|
|
297
|
+
getTransforms(params: TransformParams): TokenTransformed[];
|
|
298
|
+
/** Update transformed values */
|
|
299
|
+
setTransform(
|
|
300
|
+
id: string,
|
|
301
|
+
params: {
|
|
302
|
+
format: string;
|
|
303
|
+
localID?: string;
|
|
304
|
+
value: string | Record<string, string>; // allow looser type for input (`undefined` will just get stripped)
|
|
305
|
+
mode?: string;
|
|
306
|
+
},
|
|
307
|
+
): void;
|
|
308
|
+
/** Momoa documents */
|
|
309
|
+
sources: InputSource[];
|
|
310
|
+
}
|
package/build/index.d.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { DocumentNode } from '@humanwhocodes/momoa';
|
|
2
|
-
import type { TokenNormalized } from '@terrazzo/token-tools';
|
|
3
|
-
import type { ConfigInit } from '../config.js';
|
|
4
|
-
import type Logger from '../logger.js';
|
|
5
|
-
|
|
6
|
-
export interface BuildRunnerOptions {
|
|
7
|
-
sources: { filename?: URL; src: string; document: DocumentNode }[];
|
|
8
|
-
config: ConfigInit;
|
|
9
|
-
logger?: Logger;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface OutputFile {
|
|
13
|
-
filename: string;
|
|
14
|
-
contents: string | Buffer;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface OutputFileExpanded extends OutputFile {
|
|
18
|
-
/** The `name` of the plugin that produced this file. */
|
|
19
|
-
plugin: string;
|
|
20
|
-
/** How long this output took to make. */
|
|
21
|
-
time: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Transformed token with a single value. Note that this may be any type! */
|
|
25
|
-
export interface TokenTransformedSingleValue {
|
|
26
|
-
/** ID unique to this format. If missing, use `token.id`. */
|
|
27
|
-
localID?: string;
|
|
28
|
-
type: 'SINGLE_VALUE';
|
|
29
|
-
value: string;
|
|
30
|
-
/** The mode of this value (default: `"."`) */
|
|
31
|
-
mode: string;
|
|
32
|
-
/** The original token */
|
|
33
|
-
token: TokenNormalized;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Transformed token with multiple values. Note that this may be any type! */
|
|
37
|
-
export interface TokenTransformedMultiValue {
|
|
38
|
-
/** ID unique to this format. If missing, use `token.id` */
|
|
39
|
-
localID?: string;
|
|
40
|
-
type: 'MULTI_VALUE';
|
|
41
|
-
value: Record<string, string>;
|
|
42
|
-
/** The mode of this value (default: `"."`) */
|
|
43
|
-
mode: string;
|
|
44
|
-
/** The original token */
|
|
45
|
-
token: TokenNormalized;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type TokenTransformed = TokenTransformedSingleValue | TokenTransformedMultiValue;
|
|
49
|
-
|
|
50
|
-
export interface TransformParams {
|
|
51
|
-
/** ID of an existing format */
|
|
52
|
-
format: string;
|
|
53
|
-
/** Glob of tokens to select (e.g. `"color.*"` to select all tokens starting with `"color."`) */
|
|
54
|
-
id?: string | string[];
|
|
55
|
-
/** $type(s) to filter for */
|
|
56
|
-
$type?: string | string[];
|
|
57
|
-
/** Mode name, if selecting a mode (default: `"."`) */
|
|
58
|
-
mode?: string | string[];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface TransformHookOptions {
|
|
62
|
-
/** Map of tokens */
|
|
63
|
-
tokens: Record<string, TokenNormalized>;
|
|
64
|
-
/** Query transformed values */
|
|
65
|
-
getTransforms(params: TransformParams): TokenTransformed[];
|
|
66
|
-
/** Update transformed values */
|
|
67
|
-
setTransform(
|
|
68
|
-
id: string,
|
|
69
|
-
params: {
|
|
70
|
-
format: string;
|
|
71
|
-
localID?: string;
|
|
72
|
-
value: string | Record<string, string | undefined>; // allow looser type for input (`undefined` will just get stripped)
|
|
73
|
-
mode?: string;
|
|
74
|
-
},
|
|
75
|
-
): void;
|
|
76
|
-
/** Momoa documents */
|
|
77
|
-
sources: { filename?: URL; src: string; document: DocumentNode }[];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface BuildHookOptions {
|
|
81
|
-
/** Map of tokens */
|
|
82
|
-
tokens: Record<string, TokenNormalized>;
|
|
83
|
-
/** Query transformed values */
|
|
84
|
-
getTransforms(params: TransformParams): TokenTransformed[];
|
|
85
|
-
/** Momoa documents */
|
|
86
|
-
sources: { filename?: URL; src: string; document: DocumentNode }[];
|
|
87
|
-
outputFile: (
|
|
88
|
-
/** Filename to output (relative to outDir) */
|
|
89
|
-
filename: string,
|
|
90
|
-
/** Contents to write to file */
|
|
91
|
-
contents: string | Buffer,
|
|
92
|
-
) => void;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export interface BuildRunnerResult {
|
|
96
|
-
outputFiles: OutputFile[];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface BuildEndHookOptions {
|
|
100
|
-
/** Map of tokens */
|
|
101
|
-
tokens: Record<string, TokenNormalized>;
|
|
102
|
-
/** Query transformed values */
|
|
103
|
-
getTransforms(params: TransformParams): TokenTransformed[];
|
|
104
|
-
/** Momoa documents */
|
|
105
|
-
sources: { filename?: URL; src: string; document: DocumentNode }[];
|
|
106
|
-
/** Final files to be written */
|
|
107
|
-
outputFiles: OutputFileExpanded[];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export default function build(
|
|
111
|
-
tokens: Record<string, TokenNormalized>,
|
|
112
|
-
options: BuildRunnerOptions,
|
|
113
|
-
): Promise<BuildRunnerResult>;
|
package/config.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { BuildHookOptions, BuildRunnerResult, TransformHookOptions } from './build/index.js';
|
|
2
|
-
import type { LintRuleShorthand, LintRuleLonghand, Linter } from './lint/index.js';
|
|
3
|
-
import type Logger from './logger.js';
|
|
4
|
-
|
|
5
|
-
export interface Config {
|
|
6
|
-
/** Path to tokens.json (default: "./tokens.json") */
|
|
7
|
-
tokens?: string | string[];
|
|
8
|
-
/** Output directory (default: "./tokens/") */
|
|
9
|
-
outDir?: string;
|
|
10
|
-
/** Specify plugins */
|
|
11
|
-
plugins?: Plugin[];
|
|
12
|
-
/** Specify linting settings */
|
|
13
|
-
lint?: {
|
|
14
|
-
/** Configure build behavior */
|
|
15
|
-
build?: {
|
|
16
|
-
/** Should linters run with `tz build`? (default: true) */
|
|
17
|
-
enabled?: boolean;
|
|
18
|
-
};
|
|
19
|
-
/** Configure lint rules */
|
|
20
|
-
rules?: Record<string, LintRuleShorthand | LintRuleLonghand>;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ConfigInit {
|
|
25
|
-
tokens: URL[];
|
|
26
|
-
outDir: URL;
|
|
27
|
-
plugins: Plugin[];
|
|
28
|
-
lint: {
|
|
29
|
-
build: NonNullable<NonNullable<Config['lint']>['build']>;
|
|
30
|
-
rules: Record<string, LintRuleLonghand>;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface Plugin {
|
|
35
|
-
name: string;
|
|
36
|
-
/** Read config, and optionally modify */
|
|
37
|
-
// biome-ignore lint/suspicious/noConfusingVoidType format: this helps plugins be a little looser on their typing
|
|
38
|
-
config?(config: ConfigInit): void | ConfigInit | undefined;
|
|
39
|
-
/**
|
|
40
|
-
* Declare:
|
|
41
|
-
* - `"pre"`: run this plugin BEFORE all others
|
|
42
|
-
* - `"post"`: run this plugin AFTER all others
|
|
43
|
-
* - (default) run this plugin in default order (array order)
|
|
44
|
-
*/
|
|
45
|
-
enforce?: 'pre' | 'post';
|
|
46
|
-
/** Throw lint errors/warnings */
|
|
47
|
-
lint?(): Record<string, Linter>;
|
|
48
|
-
transform?(options: TransformHookOptions): Promise<void>;
|
|
49
|
-
build?(options: BuildHookOptions): Promise<void>;
|
|
50
|
-
buildEnd?(result: BuildRunnerResult): Promise<void>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface ConfigOptions {
|
|
54
|
-
logger?: Logger;
|
|
55
|
-
/** @terrazzo/parser needs cwd so this can be run without Node.js. Importing defineConfig from @terrazzo/cli doesn’t need this. */
|
|
56
|
-
cwd: URL;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Validate and normalize a config
|
|
61
|
-
*/
|
|
62
|
-
export default function defineConfig(rawConfig: Config, options: ConfigOptions): ConfigInit;
|
|
63
|
-
|
|
64
|
-
export function mergeConfigs(a: Config, b: Config): Config;
|
package/config.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { merge } from 'merge-anything';
|
|
2
|
-
import coreLintPlugin from './lint/plugin-core/index.js';
|
|
3
|
-
import Logger from './logger.js';
|
|
4
|
-
|
|
5
|
-
const TRAILING_SLASH_RE = /\/*$/;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Validate and normalize a config
|
|
9
|
-
* @param {Config} rawConfig
|
|
10
|
-
* @param {object} options
|
|
11
|
-
* @param {Logger} options.logger
|
|
12
|
-
* @param {URL} options.cwd
|
|
13
|
-
*/
|
|
14
|
-
export default function defineConfig(rawConfig, { logger = new Logger(), cwd } = {}) {
|
|
15
|
-
const configStart = performance.now();
|
|
16
|
-
|
|
17
|
-
if (!cwd) {
|
|
18
|
-
logger.error({ label: 'core', message: 'defineConfig() missing `cwd` for JS API' });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
logger.debug({ group: 'parser', task: 'config', message: 'Start config validation' });
|
|
22
|
-
|
|
23
|
-
const config = merge({}, rawConfig);
|
|
24
|
-
|
|
25
|
-
// config.tokens
|
|
26
|
-
if (rawConfig.tokens === undefined) {
|
|
27
|
-
config.tokens = ['./tokens.json']; // will be normalized in next step
|
|
28
|
-
} else if (typeof rawConfig.tokens === 'string') {
|
|
29
|
-
config.tokens = [rawConfig.tokens]; // will be normalized in next step
|
|
30
|
-
} else if (Array.isArray(rawConfig.tokens)) {
|
|
31
|
-
config.tokens = [];
|
|
32
|
-
for (const file of rawConfig.tokens) {
|
|
33
|
-
if (typeof file === 'string' || file instanceof URL) {
|
|
34
|
-
config.tokens.push(file); // will be normalized in next step
|
|
35
|
-
} else {
|
|
36
|
-
logger.error({
|
|
37
|
-
label: 'config.tokens',
|
|
38
|
-
message: `Expected array of strings, encountered ${JSON.stringify(file)}`,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
logger.error({
|
|
44
|
-
label: 'config.tokens',
|
|
45
|
-
message: `Expected string or array of strings, received ${typeof rawConfig.tokens}`,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
for (let i = 0; i < config.tokens.length; i++) {
|
|
49
|
-
const filepath = config.tokens[i];
|
|
50
|
-
if (filepath instanceof URL) {
|
|
51
|
-
continue; // skip if already resolved
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
config.tokens[i] = new URL(filepath, cwd);
|
|
55
|
-
} catch (err) {
|
|
56
|
-
logger.error({ label: 'config.tokens', message: `Invalid URL ${filepath}` });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// config.outDir
|
|
61
|
-
if (config.outDir instanceof URL) {
|
|
62
|
-
// noop
|
|
63
|
-
} else if (typeof config.outDir === 'undefined') {
|
|
64
|
-
config.outDir = new URL('./tokens/', cwd);
|
|
65
|
-
} else if (typeof config.outDir !== 'string') {
|
|
66
|
-
logger.error({ label: 'config.outDir', message: `Expected string, received ${JSON.stringify(config.outDir)}` });
|
|
67
|
-
} else {
|
|
68
|
-
config.outDir = new URL(config.outDir, cwd);
|
|
69
|
-
// always add trailing slash so URL treats it as a directory.
|
|
70
|
-
// do AFTER it has been normalized to POSIX paths with `href` (don’t use Node internals here! This may run in the browser)
|
|
71
|
-
config.outDir = new URL(config.outDir.href.replace(TRAILING_SLASH_RE, '/'));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// config.plugins
|
|
75
|
-
if (typeof config.plugins === 'undefined') {
|
|
76
|
-
config.plugins = [];
|
|
77
|
-
}
|
|
78
|
-
if (!Array.isArray(config.plugins)) {
|
|
79
|
-
logger.error({
|
|
80
|
-
label: 'config.plugins',
|
|
81
|
-
message: `Expected array of plugins, received ${JSON.stringify(config.plugins)}`,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
config.plugins.push(coreLintPlugin());
|
|
85
|
-
for (let n = 0; n < config.plugins.length; n++) {
|
|
86
|
-
const plugin = config.plugins[n];
|
|
87
|
-
if (typeof plugin !== 'object') {
|
|
88
|
-
logger.error({ label: `plugin[${n}]`, message: `Expected output plugin, received ${JSON.stringify(plugin)}` });
|
|
89
|
-
} else if (!plugin.name) {
|
|
90
|
-
logger.error({ label: `plugin[${n}]`, message: `Missing "name"` });
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// order plugins with "enforce"
|
|
94
|
-
config.plugins.sort((a, b) => {
|
|
95
|
-
if (a.enforce === 'pre' && b.enforce !== 'pre') {
|
|
96
|
-
return -1;
|
|
97
|
-
} else if (a.enforce === 'post' && b.enforce !== 'post') {
|
|
98
|
-
return 1;
|
|
99
|
-
}
|
|
100
|
-
return 0;
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// config.lint
|
|
104
|
-
if (config.lint !== undefined) {
|
|
105
|
-
if (config.lint === null || typeof config.lint !== 'object' || Array.isArray(config.lint)) {
|
|
106
|
-
logger.error({ label: 'config.lint', message: 'Must be an object' });
|
|
107
|
-
return config;
|
|
108
|
-
}
|
|
109
|
-
if (!config.lint.build) {
|
|
110
|
-
config.lint.build = { enabled: true };
|
|
111
|
-
}
|
|
112
|
-
if (config.lint.build.enabled !== undefined) {
|
|
113
|
-
if (typeof config.lint.build.enabled !== 'boolean') {
|
|
114
|
-
logger.error({
|
|
115
|
-
label: 'config.lint.build.enabled',
|
|
116
|
-
message: `Expected boolean, received ${JSON.stringify(config.lint.build)}`,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
config.lint.build.enabled = true;
|
|
121
|
-
}
|
|
122
|
-
if (config.lint.rules === undefined) {
|
|
123
|
-
config.lint.rules = {};
|
|
124
|
-
} else {
|
|
125
|
-
if (config.lint.rules === null || typeof config.lint.rules !== 'object' || Array.isArray(config.lint.rules)) {
|
|
126
|
-
logger.error({
|
|
127
|
-
label: 'config.lint.rules',
|
|
128
|
-
message: `Expected object, received ${JSON.stringify(config.lint.rules)}`,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
for (const id in config.lint.rules) {
|
|
132
|
-
if (!Object.hasOwn(config.lint.rules, id)) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
if (typeof id !== 'string') {
|
|
136
|
-
logger.error({ label: 'config.lint.rules', message: `Expects string keys, received ${JSON.stringify(id)}` });
|
|
137
|
-
}
|
|
138
|
-
const value = config.lint.rules[id];
|
|
139
|
-
let severity = 'off';
|
|
140
|
-
let options;
|
|
141
|
-
if (typeof value === 'number' || typeof value === 'string') {
|
|
142
|
-
severity = value;
|
|
143
|
-
} else if (Array.isArray(value)) {
|
|
144
|
-
severity = value[0];
|
|
145
|
-
options = value[1];
|
|
146
|
-
} else if (value !== undefined) {
|
|
147
|
-
logger.error({
|
|
148
|
-
label: `config.lint.rule:${id}`,
|
|
149
|
-
message: `Invalid eyntax. Expected \`string | number | Array\`, received ${JSON.stringify(value)}}`,
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
config.lint.rules[id] = { id, severity, options };
|
|
153
|
-
if (typeof severity === 'number') {
|
|
154
|
-
if (severity !== 0 && severity !== 1 && severity !== 2) {
|
|
155
|
-
logger.error({
|
|
156
|
-
label: `config.lint.rule:${id}`,
|
|
157
|
-
message: `Invalid number ${severity}. Specify 0 (off), 1 (warn), or 2 (error).`,
|
|
158
|
-
});
|
|
159
|
-
return config;
|
|
160
|
-
}
|
|
161
|
-
config.lint.rules[id].severity = ['off', 'warn', 'error'][severity];
|
|
162
|
-
} else if (typeof severity === 'string') {
|
|
163
|
-
if (severity !== 'off' && severity !== 'warn' && severity !== 'error') {
|
|
164
|
-
logger.error({
|
|
165
|
-
label: `config.lint.rule:${id}`,
|
|
166
|
-
message: `Invalid string ${JSON.stringify(severity)}. Specify "off", "warn", or "error".`,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
} else if (value !== null) {
|
|
170
|
-
logger.error({
|
|
171
|
-
label: `config.lint.rule:${id}`,
|
|
172
|
-
message: `Expected string or number, received ${JSON.stringify(value)}`,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
} else {
|
|
178
|
-
config.lint = {
|
|
179
|
-
build: { enabled: true },
|
|
180
|
-
rules: {},
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// call plugin.config()
|
|
185
|
-
for (const plugin of config.plugins) {
|
|
186
|
-
plugin.config?.({ ...config });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
logger.debug({
|
|
190
|
-
group: 'parser',
|
|
191
|
-
task: 'config',
|
|
192
|
-
message: 'Finish config validation',
|
|
193
|
-
timing: performance.now() - configStart,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
return config;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @param {object} a
|
|
201
|
-
* @param {object} b
|
|
202
|
-
* @return {object}
|
|
203
|
-
*/
|
|
204
|
-
export function mergeConfigs(a, b) {
|
|
205
|
-
return merge(a, b);
|
|
206
|
-
}
|