@terrazzo/parser 0.0.8 → 0.0.10
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/config.js +17 -9
- package/logger.d.ts +16 -8
- package/logger.js +18 -0
- package/package.json +3 -3
- package/parse/index.d.ts +2 -0
- package/parse/index.js +18 -6
package/config.js
CHANGED
|
@@ -11,12 +11,16 @@ const TRAILING_SLASH_RE = /\/*$/;
|
|
|
11
11
|
* @param {Logger} options.logger
|
|
12
12
|
* @param {URL} options.cwd
|
|
13
13
|
*/
|
|
14
|
-
export default function defineConfig(rawConfig, { logger = new Logger(), cwd
|
|
14
|
+
export default function defineConfig(rawConfig, { logger = new Logger(), cwd } = {}) {
|
|
15
15
|
const configStart = performance.now();
|
|
16
16
|
|
|
17
|
+
if (!cwd) {
|
|
18
|
+
logger.error({ label: 'core', message: 'defineConfig() missing `cwd` for JS API' });
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
logger.debug({ group: 'parser', task: 'config', message: 'Start config validation' });
|
|
18
22
|
|
|
19
|
-
const config = {
|
|
23
|
+
const config = merge({}, rawConfig);
|
|
20
24
|
|
|
21
25
|
// config.tokens
|
|
22
26
|
if (rawConfig.tokens === undefined) {
|
|
@@ -26,7 +30,7 @@ export default function defineConfig(rawConfig, { logger = new Logger(), cwd = i
|
|
|
26
30
|
} else if (Array.isArray(rawConfig.tokens)) {
|
|
27
31
|
config.tokens = [];
|
|
28
32
|
for (const file of rawConfig.tokens) {
|
|
29
|
-
if (typeof file === 'string') {
|
|
33
|
+
if (typeof file === 'string' || file instanceof URL) {
|
|
30
34
|
config.tokens.push(file); // will be normalized in next step
|
|
31
35
|
} else {
|
|
32
36
|
logger.error({
|
|
@@ -43,15 +47,20 @@ export default function defineConfig(rawConfig, { logger = new Logger(), cwd = i
|
|
|
43
47
|
}
|
|
44
48
|
for (let i = 0; i < config.tokens.length; i++) {
|
|
45
49
|
const filepath = config.tokens[i];
|
|
50
|
+
if (filepath instanceof URL) {
|
|
51
|
+
continue; // skip if already resolved
|
|
52
|
+
}
|
|
46
53
|
try {
|
|
47
54
|
config.tokens[i] = new URL(filepath, cwd);
|
|
48
|
-
} catch {
|
|
55
|
+
} catch (err) {
|
|
49
56
|
logger.error({ label: 'config.tokens', message: `Invalid URL ${filepath}` });
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
// config.outDir
|
|
54
|
-
if (
|
|
61
|
+
if (config.outDir instanceof URL) {
|
|
62
|
+
// noop
|
|
63
|
+
} else if (typeof config.outDir === 'undefined') {
|
|
55
64
|
config.outDir = new URL('./tokens/', cwd);
|
|
56
65
|
} else if (typeof config.outDir !== 'string') {
|
|
57
66
|
logger.error({ label: 'config.outDir', message: `Expected string, received ${JSON.stringify(config.outDir)}` });
|
|
@@ -95,7 +104,6 @@ export default function defineConfig(rawConfig, { logger = new Logger(), cwd = i
|
|
|
95
104
|
logger.error({ label: 'config.lint', message: 'Must be an object' });
|
|
96
105
|
return config;
|
|
97
106
|
}
|
|
98
|
-
|
|
99
107
|
if (!config.lint.build) {
|
|
100
108
|
config.lint.build = { enabled: true };
|
|
101
109
|
}
|
|
@@ -109,15 +117,15 @@ export default function defineConfig(rawConfig, { logger = new Logger(), cwd = i
|
|
|
109
117
|
} else {
|
|
110
118
|
config.lint.build.enabled = true;
|
|
111
119
|
}
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
if (config.lint.rules === undefined) {
|
|
121
|
+
config.lint.rules = {};
|
|
122
|
+
} else {
|
|
114
123
|
if (config.lint.rules === null || typeof config.lint.rules !== 'object' || Array.isArray(config.lint.rules)) {
|
|
115
124
|
logger.error({
|
|
116
125
|
label: 'config.lint.rules',
|
|
117
126
|
message: `Expected object, received ${JSON.stringify(config.lint.rules)}`,
|
|
118
127
|
});
|
|
119
128
|
}
|
|
120
|
-
|
|
121
129
|
for (const id in config.lint.rules) {
|
|
122
130
|
if (!Object.hasOwn(config.lint.rules, id)) {
|
|
123
131
|
continue;
|
package/logger.d.ts
CHANGED
|
@@ -36,14 +36,6 @@ export interface DebugEntry {
|
|
|
36
36
|
|
|
37
37
|
export default class Logger {
|
|
38
38
|
constructor(options?: { level?: LogLevel; debugScope: string });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class TokensJSONError extends Error {
|
|
42
|
-
level: LogLevel;
|
|
43
|
-
debugScope: string;
|
|
44
|
-
node?: AnyNode;
|
|
45
|
-
|
|
46
|
-
constructor(message: string, node: AnyNode);
|
|
47
39
|
|
|
48
40
|
setLevel(level: LogLevel): void;
|
|
49
41
|
|
|
@@ -58,4 +50,20 @@ export class TokensJSONError extends Error {
|
|
|
58
50
|
|
|
59
51
|
/** Log a diagnostics message (if logging level permits) */
|
|
60
52
|
debug(entry: DebugEntry): void;
|
|
53
|
+
|
|
54
|
+
/** Get current stats for logger instance */
|
|
55
|
+
stats(): {
|
|
56
|
+
errorCount: number;
|
|
57
|
+
infoCount: number;
|
|
58
|
+
warnCount: number;
|
|
59
|
+
debugCount: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class TokensJSONError extends Error {
|
|
64
|
+
level: LogLevel;
|
|
65
|
+
debugScope: string;
|
|
66
|
+
node?: AnyNode;
|
|
67
|
+
|
|
68
|
+
constructor(message: string, node: AnyNode);
|
|
61
69
|
}
|
package/logger.js
CHANGED
|
@@ -32,6 +32,10 @@ export function formatMessage(entry, severity) {
|
|
|
32
32
|
export default class Logger {
|
|
33
33
|
level = 'info';
|
|
34
34
|
debugScope = '*';
|
|
35
|
+
errorCount = 0;
|
|
36
|
+
warnCount = 0;
|
|
37
|
+
infoCount = 0;
|
|
38
|
+
debugCount = 0;
|
|
35
39
|
|
|
36
40
|
constructor(options) {
|
|
37
41
|
if (options?.level) {
|
|
@@ -48,6 +52,7 @@ export default class Logger {
|
|
|
48
52
|
|
|
49
53
|
/** Log an error message (always; can’t be silenced) */
|
|
50
54
|
error(entry) {
|
|
55
|
+
this.errorCount++;
|
|
51
56
|
const message = formatMessage(entry, 'error');
|
|
52
57
|
if (entry.continueOnError) {
|
|
53
58
|
console.error(message);
|
|
@@ -64,6 +69,7 @@ export default class Logger {
|
|
|
64
69
|
|
|
65
70
|
/** Log an info message (if logging level permits) */
|
|
66
71
|
info(entry) {
|
|
72
|
+
this.infoCount++;
|
|
67
73
|
if (this.level === 'silent' || LOG_ORDER.indexOf(this.level) < LOG_ORDER.indexOf('info')) {
|
|
68
74
|
return;
|
|
69
75
|
}
|
|
@@ -73,6 +79,7 @@ export default class Logger {
|
|
|
73
79
|
|
|
74
80
|
/** Log a warning message (if logging level permits) */
|
|
75
81
|
warn(entry) {
|
|
82
|
+
this.warnCount++;
|
|
76
83
|
if (this.level === 'silent' || LOG_ORDER.indexOf(this.level) < LOG_ORDER.indexOf('warn')) {
|
|
77
84
|
return;
|
|
78
85
|
}
|
|
@@ -81,6 +88,7 @@ export default class Logger {
|
|
|
81
88
|
|
|
82
89
|
/** Log a diagnostics message (if logging level permits) */
|
|
83
90
|
debug(entry) {
|
|
91
|
+
this.debugCount++;
|
|
84
92
|
if (this.level === 'silent' || LOG_ORDER.indexOf(this.level) < LOG_ORDER.indexOf('debug')) {
|
|
85
93
|
return;
|
|
86
94
|
}
|
|
@@ -107,6 +115,16 @@ export default class Logger {
|
|
|
107
115
|
// biome-ignore lint/suspicious/noConsoleLog: this is its job
|
|
108
116
|
console.log(message);
|
|
109
117
|
}
|
|
118
|
+
|
|
119
|
+
/** Get stats for current logger instance */
|
|
120
|
+
stats() {
|
|
121
|
+
return {
|
|
122
|
+
errorCount: this.errorCount,
|
|
123
|
+
warnCount: this.warnCount,
|
|
124
|
+
infoCount: this.infoCount,
|
|
125
|
+
debugCount: this.debugCount,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
110
128
|
}
|
|
111
129
|
|
|
112
130
|
export class TokensJSONError extends Error {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terrazzo/parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "Parser/validator for the Design Tokens Community Group (DTCG) standard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/code-frame": "^7.24.7",
|
|
34
|
-
"@humanwhocodes/momoa": "^3.
|
|
34
|
+
"@humanwhocodes/momoa": "^3.1.1",
|
|
35
35
|
"@types/babel__code-frame": "^7.0.6",
|
|
36
|
-
"@types/culori": "^2.1.
|
|
36
|
+
"@types/culori": "^2.1.1",
|
|
37
37
|
"@types/deep-equal": "^1.0.4",
|
|
38
38
|
"culori": "^4.0.1",
|
|
39
39
|
"deep-equal": "^2.2.3",
|
package/parse/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export interface ParseOptions {
|
|
|
10
10
|
/** Skip lint step (default: false) */
|
|
11
11
|
skipLint?: boolean;
|
|
12
12
|
config: ConfigInit;
|
|
13
|
+
/** Continue on error? (Useful for `tz check`) (default: false) */
|
|
14
|
+
continueOnError?: boolean;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export interface ParseResult {
|
package/parse/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { evaluate, parse as parseJSON, print } from '@humanwhocodes/momoa';
|
|
2
|
-
import { isAlias, parseAlias, splitID } from '@terrazzo/token-tools';
|
|
2
|
+
import { isAlias, parseAlias, pluralize, splitID } from '@terrazzo/token-tools';
|
|
3
3
|
import lintRunner from '../lint/index.js';
|
|
4
4
|
import Logger from '../logger.js';
|
|
5
5
|
import normalize from './normalize.js';
|
|
@@ -28,7 +28,10 @@ export * from './validate.js';
|
|
|
28
28
|
* @param {ParseOptions} options
|
|
29
29
|
* @return {Promise<ParseResult>}
|
|
30
30
|
*/
|
|
31
|
-
export default async function parse(
|
|
31
|
+
export default async function parse(
|
|
32
|
+
input,
|
|
33
|
+
{ logger = new Logger(), skipLint = false, config, continueOnError = false } = {},
|
|
34
|
+
) {
|
|
32
35
|
const { plugins } = config;
|
|
33
36
|
|
|
34
37
|
const totalStart = performance.now();
|
|
@@ -193,7 +196,7 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
193
196
|
if (members.$value) {
|
|
194
197
|
node = members.$value;
|
|
195
198
|
}
|
|
196
|
-
logger.error({ message: err.message, source, node, continueOnError
|
|
199
|
+
logger.error({ message: err.message, source, node, continueOnError });
|
|
197
200
|
}
|
|
198
201
|
for (const mode in tokens[id].mode) {
|
|
199
202
|
if (mode === '.') {
|
|
@@ -207,7 +210,7 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
207
210
|
if (members.$value) {
|
|
208
211
|
node = members.$value;
|
|
209
212
|
}
|
|
210
|
-
logger.error({ message: err.message, source, node: tokens[id].mode[mode].sourceNode, continueOnError
|
|
213
|
+
logger.error({ message: err.message, source, node: tokens[id].mode[mode].sourceNode, continueOnError });
|
|
211
214
|
}
|
|
212
215
|
}
|
|
213
216
|
}
|
|
@@ -273,6 +276,15 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
273
276
|
timing: performance.now() - totalStart,
|
|
274
277
|
});
|
|
275
278
|
|
|
279
|
+
if (continueOnError) {
|
|
280
|
+
const { errorCount } = logger.stats();
|
|
281
|
+
if (errorCount > 0) {
|
|
282
|
+
logger.error({
|
|
283
|
+
message: `Parser encountered ${errorCount} ${pluralize(errorCount, 'error', 'errors')}. Exiting.`,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
276
288
|
return {
|
|
277
289
|
tokens,
|
|
278
290
|
ast,
|
|
@@ -302,10 +314,10 @@ export function maybeJSONString(input) {
|
|
|
302
314
|
export function resolveAlias(alias, { tokens, logger, source, node, scanned = [] }) {
|
|
303
315
|
const { id } = parseAlias(alias);
|
|
304
316
|
if (!tokens[id]) {
|
|
305
|
-
logger.error({ message: `Alias "${alias}" not found`, source, node
|
|
317
|
+
logger.error({ message: `Alias "${alias}" not found`, source, node });
|
|
306
318
|
}
|
|
307
319
|
if (scanned.includes(id)) {
|
|
308
|
-
logger.error({ message: `Circular alias detected from "${alias}"`, source, node
|
|
320
|
+
logger.error({ message: `Circular alias detected from "${alias}"`, source, node });
|
|
309
321
|
}
|
|
310
322
|
const token = tokens[id];
|
|
311
323
|
if (!isAlias(token.$value)) {
|