@terrazzo/parser 0.1.3 → 0.2.1

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.
Files changed (118) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +23 -0
  3. package/CONTRIBUTING.md +0 -12
  4. package/dist/build/index.d.ts +19 -0
  5. package/dist/build/index.js +165 -0
  6. package/dist/build/index.js.map +1 -0
  7. package/dist/config.d.ts +7 -0
  8. package/dist/config.js +269 -0
  9. package/dist/config.js.map +1 -0
  10. package/{index.d.ts → dist/index.d.ts} +1 -5
  11. package/dist/index.js +13 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/code-frame.d.ts +30 -0
  14. package/dist/lib/code-frame.js +108 -0
  15. package/dist/lib/code-frame.js.map +1 -0
  16. package/dist/lint/index.d.ts +11 -0
  17. package/dist/lint/index.js +102 -0
  18. package/dist/lint/index.js.map +1 -0
  19. package/dist/lint/plugin-core/index.d.ts +12 -0
  20. package/dist/lint/plugin-core/index.js +40 -0
  21. package/dist/lint/plugin-core/index.js.map +1 -0
  22. package/dist/lint/plugin-core/lib/docs.d.ts +1 -0
  23. package/dist/lint/plugin-core/lib/docs.js +4 -0
  24. package/dist/lint/plugin-core/lib/docs.js.map +1 -0
  25. package/dist/lint/plugin-core/rules/a11y-min-contrast.d.ts +39 -0
  26. package/dist/lint/plugin-core/rules/a11y-min-contrast.js +58 -0
  27. package/dist/lint/plugin-core/rules/a11y-min-contrast.js.map +1 -0
  28. package/dist/lint/plugin-core/rules/a11y-min-font-size.d.ts +13 -0
  29. package/dist/lint/plugin-core/rules/a11y-min-font-size.js +45 -0
  30. package/dist/lint/plugin-core/rules/a11y-min-font-size.js.map +1 -0
  31. package/dist/lint/plugin-core/rules/colorspace.d.ts +14 -0
  32. package/dist/lint/plugin-core/rules/colorspace.js +85 -0
  33. package/dist/lint/plugin-core/rules/colorspace.js.map +1 -0
  34. package/dist/lint/plugin-core/rules/consistent-naming.d.ts +11 -0
  35. package/dist/lint/plugin-core/rules/consistent-naming.js +49 -0
  36. package/dist/lint/plugin-core/rules/consistent-naming.js.map +1 -0
  37. package/dist/lint/plugin-core/rules/descriptions.d.ts +9 -0
  38. package/dist/lint/plugin-core/rules/descriptions.js +32 -0
  39. package/dist/lint/plugin-core/rules/descriptions.js.map +1 -0
  40. package/dist/lint/plugin-core/rules/duplicate-values.d.ts +9 -0
  41. package/dist/lint/plugin-core/rules/duplicate-values.js +65 -0
  42. package/dist/lint/plugin-core/rules/duplicate-values.js.map +1 -0
  43. package/dist/lint/plugin-core/rules/max-gamut.d.ts +14 -0
  44. package/dist/lint/plugin-core/rules/max-gamut.js +101 -0
  45. package/dist/lint/plugin-core/rules/max-gamut.js.map +1 -0
  46. package/dist/lint/plugin-core/rules/required-children.d.ts +18 -0
  47. package/dist/lint/plugin-core/rules/required-children.js +78 -0
  48. package/dist/lint/plugin-core/rules/required-children.js.map +1 -0
  49. package/dist/lint/plugin-core/rules/required-modes.d.ts +13 -0
  50. package/dist/lint/plugin-core/rules/required-modes.js +52 -0
  51. package/dist/lint/plugin-core/rules/required-modes.js.map +1 -0
  52. package/dist/lint/plugin-core/rules/required-typography-properties.d.ts +10 -0
  53. package/dist/lint/plugin-core/rules/required-typography-properties.js +38 -0
  54. package/dist/lint/plugin-core/rules/required-typography-properties.js.map +1 -0
  55. package/dist/logger.d.ts +76 -0
  56. package/dist/logger.js +123 -0
  57. package/dist/logger.js.map +1 -0
  58. package/dist/parse/alias.d.ts +51 -0
  59. package/dist/parse/alias.js +188 -0
  60. package/dist/parse/alias.js.map +1 -0
  61. package/dist/parse/index.d.ts +27 -0
  62. package/dist/parse/index.js +379 -0
  63. package/dist/parse/index.js.map +1 -0
  64. package/dist/parse/json.d.ts +36 -0
  65. package/dist/parse/json.js +88 -0
  66. package/dist/parse/json.js.map +1 -0
  67. package/dist/parse/normalize.d.ts +23 -0
  68. package/dist/parse/normalize.js +163 -0
  69. package/dist/parse/normalize.js.map +1 -0
  70. package/dist/parse/validate.d.ts +45 -0
  71. package/dist/parse/validate.js +601 -0
  72. package/dist/parse/validate.js.map +1 -0
  73. package/dist/types.d.ts +264 -0
  74. package/dist/types.js +2 -0
  75. package/dist/types.js.map +1 -0
  76. package/package.json +7 -7
  77. package/{build/index.js → src/build/index.ts} +47 -63
  78. package/src/config.ts +280 -0
  79. package/src/index.ts +18 -0
  80. package/{lib/code-frame.js → src/lib/code-frame.ts} +41 -8
  81. package/src/lint/index.ts +135 -0
  82. package/src/lint/plugin-core/index.ts +47 -0
  83. package/src/lint/plugin-core/lib/docs.ts +3 -0
  84. package/src/lint/plugin-core/rules/a11y-min-contrast.ts +91 -0
  85. package/src/lint/plugin-core/rules/a11y-min-font-size.ts +64 -0
  86. package/src/lint/plugin-core/rules/colorspace.ts +101 -0
  87. package/src/lint/plugin-core/rules/consistent-naming.ts +65 -0
  88. package/src/lint/plugin-core/rules/descriptions.ts +41 -0
  89. package/src/lint/plugin-core/rules/duplicate-values.ts +80 -0
  90. package/src/lint/plugin-core/rules/max-gamut.ts +121 -0
  91. package/src/lint/plugin-core/rules/required-children.ts +104 -0
  92. package/src/lint/plugin-core/rules/required-modes.ts +71 -0
  93. package/src/lint/plugin-core/rules/required-typography-properties.ts +53 -0
  94. package/{logger.js → src/logger.ts} +55 -16
  95. package/src/parse/alias.ts +224 -0
  96. package/src/parse/index.ts +457 -0
  97. package/src/parse/json.ts +106 -0
  98. package/{parse/normalize.js → src/parse/normalize.ts} +70 -24
  99. package/{parse/validate.js → src/parse/validate.ts} +154 -236
  100. package/src/types.ts +310 -0
  101. package/build/index.d.ts +0 -113
  102. package/config.d.ts +0 -64
  103. package/config.js +0 -206
  104. package/index.js +0 -35
  105. package/lib/code-frame.d.ts +0 -56
  106. package/lint/index.d.ts +0 -44
  107. package/lint/index.js +0 -59
  108. package/lint/plugin-core/index.d.ts +0 -3
  109. package/lint/plugin-core/index.js +0 -12
  110. package/lint/plugin-core/rules/duplicate-values.d.ts +0 -10
  111. package/lint/plugin-core/rules/duplicate-values.js +0 -68
  112. package/logger.d.ts +0 -71
  113. package/parse/index.d.ts +0 -45
  114. package/parse/index.js +0 -592
  115. package/parse/json.d.ts +0 -30
  116. package/parse/json.js +0 -94
  117. package/parse/normalize.d.ts +0 -3
  118. 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
- }