@terrazzo/parser 0.0.12 → 0.0.13
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/CHANGELOG.md +8 -0
- package/lib/code-frame.d.ts +56 -0
- package/lib/code-frame.js +141 -0
- package/lint/plugin-core/rules/duplicate-values.js +1 -2
- package/logger.js +3 -3
- package/package.json +7 -6
- package/parse/index.d.ts +3 -0
- package/parse/index.js +26 -8
- package/parse/validate.js +2 -2
- package/parse/yaml.d.ts +0 -11
- package/parse/yaml.js +0 -45
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @terrazzo/parser
|
|
2
2
|
|
|
3
|
+
## 0.0.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#289](https://github.com/terrazzoapp/terrazzo/pull/289) [`0fc9738`](https://github.com/terrazzoapp/terrazzo/commit/0fc9738bb3dfecb680d225e4bd3970f21cfe8079) Thanks [@drwpow](https://github.com/drwpow)! - Add YAML support
|
|
8
|
+
|
|
9
|
+
- [#291](https://github.com/terrazzoapp/terrazzo/pull/291) [`6a875b1`](https://github.com/terrazzoapp/terrazzo/commit/6a875b163539dba8111911851a7819732056b3aa) Thanks [@drwpow](https://github.com/drwpow)! - Allow negative dimension values
|
|
10
|
+
|
|
3
11
|
## 0.0.12
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
//
|
|
3
|
+
// Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
|
4
|
+
//
|
|
5
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
// a copy of this software and associated documentation files (the
|
|
7
|
+
// "Software"), to deal in the Software without restriction, including
|
|
8
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
// the following conditions:
|
|
12
|
+
//
|
|
13
|
+
// The above copyright notice and this permission notice shall be
|
|
14
|
+
// included in all copies or substantial portions of the Software.
|
|
15
|
+
//
|
|
16
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
export interface Location {
|
|
25
|
+
line: number;
|
|
26
|
+
column: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface NodeLocation {
|
|
30
|
+
end?: Location;
|
|
31
|
+
start: Location;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Options {
|
|
35
|
+
/** Syntax highlight the code as JavaScript for terminals. default: false */
|
|
36
|
+
highlightCode?: boolean;
|
|
37
|
+
/** The number of lines to show above the error. default: 2 */
|
|
38
|
+
linesAbove?: number;
|
|
39
|
+
/** The number of lines to show below the error. default: 3 */
|
|
40
|
+
linesBelow?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Forcibly syntax highlight the code as JavaScript (for non-terminals);
|
|
43
|
+
* overrides highlightCode.
|
|
44
|
+
* default: false
|
|
45
|
+
*/
|
|
46
|
+
forceColor?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Pass in a string to be displayed inline (if possible) next to the
|
|
49
|
+
* highlighted location in the code. If it can't be positioned inline,
|
|
50
|
+
* it will be placed above the code frame.
|
|
51
|
+
* default: nothing
|
|
52
|
+
*/
|
|
53
|
+
message?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function codeFrameColumns(input: string, location: NodeLocation, options?: Options): string;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// This is copied from @babel/code-frame package but without the heavyweight color highlighting
|
|
2
|
+
// (note: Babel loads both chalk AND picocolors, and doesn’t treeshake well)
|
|
3
|
+
// Babel is MIT-licensed and unaffiliated with this project.
|
|
4
|
+
|
|
5
|
+
// MIT License
|
|
6
|
+
//
|
|
7
|
+
// Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
|
8
|
+
//
|
|
9
|
+
// Permission is hereby granted, free of charge, to any person obtaining
|
|
10
|
+
// a copy of this software and associated documentation files (the
|
|
11
|
+
// "Software"), to deal in the Software without restriction, including
|
|
12
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
|
13
|
+
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
14
|
+
// permit persons to whom the Software is furnished to do so, subject to
|
|
15
|
+
// the following conditions:
|
|
16
|
+
//
|
|
17
|
+
// The above copyright notice and this permission notice shall be
|
|
18
|
+
// included in all copies or substantial portions of the Software.
|
|
19
|
+
//
|
|
20
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
21
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
22
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
23
|
+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
24
|
+
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
25
|
+
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
26
|
+
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Extract what lines should be marked and highlighted.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
function getMarkerLines(loc, source, opts = {}) {
|
|
33
|
+
const startLoc = {
|
|
34
|
+
column: 0,
|
|
35
|
+
line: -1,
|
|
36
|
+
...loc.start,
|
|
37
|
+
};
|
|
38
|
+
const endLoc = {
|
|
39
|
+
...startLoc,
|
|
40
|
+
...loc.end,
|
|
41
|
+
};
|
|
42
|
+
const { linesAbove = 2, linesBelow = 3 } = opts || {};
|
|
43
|
+
const startLine = startLoc.line;
|
|
44
|
+
const startColumn = startLoc.column;
|
|
45
|
+
const endLine = endLoc.line;
|
|
46
|
+
const endColumn = endLoc.column;
|
|
47
|
+
|
|
48
|
+
let start = Math.max(startLine - (linesAbove + 1), 0);
|
|
49
|
+
let end = Math.min(source.length, endLine + linesBelow);
|
|
50
|
+
|
|
51
|
+
if (startLine === -1) {
|
|
52
|
+
start = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (endLine === -1) {
|
|
56
|
+
end = source.length;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const lineDiff = endLine - startLine;
|
|
60
|
+
const markerLines = {};
|
|
61
|
+
|
|
62
|
+
if (lineDiff) {
|
|
63
|
+
for (let i = 0; i <= lineDiff; i++) {
|
|
64
|
+
const lineNumber = i + startLine;
|
|
65
|
+
|
|
66
|
+
if (!startColumn) {
|
|
67
|
+
markerLines[lineNumber] = true;
|
|
68
|
+
} else if (i === 0) {
|
|
69
|
+
const sourceLength = source[lineNumber - 1].length;
|
|
70
|
+
|
|
71
|
+
markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
|
|
72
|
+
} else if (i === lineDiff) {
|
|
73
|
+
markerLines[lineNumber] = [0, endColumn];
|
|
74
|
+
} else {
|
|
75
|
+
const sourceLength = source[lineNumber - i].length;
|
|
76
|
+
|
|
77
|
+
markerLines[lineNumber] = [0, sourceLength];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
if (startColumn === endColumn) {
|
|
82
|
+
if (startColumn) {
|
|
83
|
+
markerLines[startLine] = [startColumn, 0];
|
|
84
|
+
} else {
|
|
85
|
+
markerLines[startLine] = true;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
markerLines[startLine] = [startColumn, endColumn - startColumn];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { start, end, markerLines };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* RegExp to test for newlines in terminal.
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
|
|
100
|
+
|
|
101
|
+
export function codeFrameColumns(rawLines, loc, opts = {}) {
|
|
102
|
+
const lines = rawLines.split(NEWLINE);
|
|
103
|
+
const { start, end, markerLines } = getMarkerLines(loc, lines, opts);
|
|
104
|
+
const hasColumns = loc.start && typeof loc.start.column === 'number';
|
|
105
|
+
|
|
106
|
+
const numberMaxWidth = String(end).length;
|
|
107
|
+
|
|
108
|
+
let frame = rawLines
|
|
109
|
+
.split(NEWLINE, end)
|
|
110
|
+
.slice(start, end)
|
|
111
|
+
.map((line, index) => {
|
|
112
|
+
const number = start + 1 + index;
|
|
113
|
+
const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
|
|
114
|
+
const gutter = ` ${paddedNumber} |`;
|
|
115
|
+
const hasMarker = markerLines[number];
|
|
116
|
+
const lastMarkerLine = !markerLines[number + 1];
|
|
117
|
+
if (hasMarker) {
|
|
118
|
+
let markerLine = '';
|
|
119
|
+
if (Array.isArray(hasMarker)) {
|
|
120
|
+
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, ' ');
|
|
121
|
+
const numberOfMarkers = hasMarker[1] || 1;
|
|
122
|
+
|
|
123
|
+
markerLine = ['\n ', gutter.replace(/\d/g, ' '), ' ', markerSpacing, '^'.repeat(numberOfMarkers)].join('');
|
|
124
|
+
|
|
125
|
+
if (lastMarkerLine && opts.message) {
|
|
126
|
+
markerLine += ` ${opts.message}`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return ['>', gutter, line.length > 0 ? ` ${line}` : '', markerLine].join('');
|
|
130
|
+
} else {
|
|
131
|
+
return ` ${gutter}${line.length > 0 ? ` ${line}` : ''}`;
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.join('\n');
|
|
135
|
+
|
|
136
|
+
if (opts.message && !hasColumns) {
|
|
137
|
+
frame = `${' '.repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return frame;
|
|
141
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isAlias, isTokenMatch } from '@terrazzo/token-tools';
|
|
2
|
-
import deepEqual from 'deep-equal';
|
|
3
2
|
|
|
4
3
|
export default function ruleDuplicateValues({ tokens, rule: { severity }, options }) {
|
|
5
4
|
if (severity === 'off') {
|
|
@@ -51,7 +50,7 @@ export default function ruleDuplicateValues({ tokens, rule: { severity }, option
|
|
|
51
50
|
// everything else: use deepEqual
|
|
52
51
|
let isDuplicate = false;
|
|
53
52
|
for (const v of values[t.$type]?.values() ?? []) {
|
|
54
|
-
if (
|
|
53
|
+
if (JSON.stringify(t.$value) === JSON.stringify(v)) {
|
|
55
54
|
notices.push({ message: `Duplicated value (${t.id})`, node: t.sourceNode });
|
|
56
55
|
isDuplicate = true;
|
|
57
56
|
break;
|
package/logger.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { codeFrameColumns } from '@babel/code-frame';
|
|
2
1
|
import color from 'picocolors';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
2
|
import wcmatch from 'wildcard-match';
|
|
3
|
+
import { codeFrameColumns } from './lib/code-frame.js';
|
|
5
4
|
|
|
6
5
|
export const LOG_ORDER = ['error', 'warn', 'info', 'debug'];
|
|
7
6
|
|
|
@@ -26,7 +25,8 @@ export function formatMessage(entry, severity) {
|
|
|
26
25
|
}
|
|
27
26
|
if (entry.src) {
|
|
28
27
|
const start = entry.node?.loc?.start;
|
|
29
|
-
|
|
28
|
+
// note: strip "file://" protocol, but not href
|
|
29
|
+
message = `${message}\n\n${entry.filename ? `${entry.filename.href.replace(/^file:\/\//, '')}:${start?.line ?? 0}:${start?.column ?? 0}\n\n` : ''}${codeFrameColumns(entry.src, { start }, { highlightCode: false })}`;
|
|
30
30
|
}
|
|
31
31
|
return message;
|
|
32
32
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terrazzo/parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Parser/validator for the Design Tokens Community Group (DTCG) standard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -30,20 +30,21 @@
|
|
|
30
30
|
},
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"@humanwhocodes/momoa": "^3.1.1",
|
|
33
|
+
"@humanwhocodes/momoa": "^3.2.0",
|
|
35
34
|
"@types/babel__code-frame": "^7.0.6",
|
|
36
35
|
"@types/culori": "^2.1.1",
|
|
37
|
-
"@types/deep-equal": "^1.0.4",
|
|
38
36
|
"culori": "^4.0.1",
|
|
39
|
-
"deep-equal": "^2.2.3",
|
|
40
37
|
"is-what": "^4.1.16",
|
|
41
38
|
"merge-anything": "^5.1.7",
|
|
42
39
|
"picocolors": "^1.0.1",
|
|
43
40
|
"wildcard-match": "^5.1.3",
|
|
44
|
-
"yaml": "^2.
|
|
41
|
+
"yaml": "^2.5.0",
|
|
45
42
|
"@terrazzo/token-tools": "^0.0.6"
|
|
46
43
|
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"esbuild": "^0.23.0",
|
|
46
|
+
"yaml-to-momoa": "^0.0.1"
|
|
47
|
+
},
|
|
47
48
|
"scripts": {
|
|
48
49
|
"lint": "biome check .",
|
|
49
50
|
"test": "pnpm --filter @terrazzo/parser run \"/^test:.*/\"",
|
package/parse/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DocumentNode } from '@humanwhocodes/momoa';
|
|
2
2
|
import type { TokenNormalized } from '@terrazzo/token-tools';
|
|
3
|
+
import type yamlToMomoa from 'yaml-to-momoa';
|
|
3
4
|
import type { ConfigInit } from '../config.js';
|
|
4
5
|
import type Logger from '../logger.js';
|
|
5
6
|
|
|
@@ -19,6 +20,8 @@ export interface ParseOptions {
|
|
|
19
20
|
skipLint?: boolean;
|
|
20
21
|
/** Continue on error? (Useful for `tz check`) (default: false) */
|
|
21
22
|
continueOnError?: boolean;
|
|
23
|
+
/** Provide yamlToMomoa module to parse YAML (by default, this isn’t shipped to cut down on package weight) */
|
|
24
|
+
yamlToMomoa?: typeof yamlToMomoa;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export interface ParseResult {
|
package/parse/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { evaluate, parse as parseJSON, print } from '@humanwhocodes/momoa';
|
|
2
2
|
import { isAlias, parseAlias, pluralize, splitID } from '@terrazzo/token-tools';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
3
|
import lintRunner from '../lint/index.js';
|
|
5
4
|
import Logger from '../logger.js';
|
|
6
5
|
import normalize from './normalize.js';
|
|
7
|
-
import parseYAML from './yaml.js';
|
|
8
6
|
import validate from './validate.js';
|
|
9
7
|
import { getObjMembers, injectObjMembers, traverse } from './json.js';
|
|
10
8
|
|
|
@@ -27,6 +25,7 @@ export * from './validate.js';
|
|
|
27
25
|
* @typedef {object} ParseOptions
|
|
28
26
|
* @property {Logger} logger
|
|
29
27
|
* @property {import("../config.js").Config} config
|
|
28
|
+
* @property {import("yamlToMomoa")} yamlToMomoa
|
|
30
29
|
* @property {boolean} [skipLint=false]
|
|
31
30
|
* @property {boolean} [continueOnError=false]
|
|
32
31
|
*/
|
|
@@ -38,7 +37,7 @@ export * from './validate.js';
|
|
|
38
37
|
*/
|
|
39
38
|
export default async function parse(
|
|
40
39
|
input,
|
|
41
|
-
{ logger = new Logger(), skipLint = false, config = {}, continueOnError = false } = {},
|
|
40
|
+
{ logger = new Logger(), skipLint = false, config = {}, continueOnError = false, yamlToMomoa } = {},
|
|
42
41
|
) {
|
|
43
42
|
let tokens = {};
|
|
44
43
|
// note: only keeps track of sources with locations on disk; in-memory sources are discarded
|
|
@@ -73,11 +72,12 @@ export default async function parse(
|
|
|
73
72
|
config,
|
|
74
73
|
skipLint,
|
|
75
74
|
continueOnError,
|
|
75
|
+
yamlToMomoa,
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
tokens = Object.assign(tokens, result.tokens);
|
|
79
79
|
if (input[i].filename) {
|
|
80
|
-
sources[input[i].filename.protocol === 'file:' ?
|
|
80
|
+
sources[input[i].filename.protocol === 'file:' ? input[i].filename.href : input[i].filename.href] = {
|
|
81
81
|
filename: input[i].filename,
|
|
82
82
|
src: result.src,
|
|
83
83
|
document: result.document,
|
|
@@ -172,7 +172,7 @@ export default async function parse(
|
|
|
172
172
|
* @param {import("../config.js").Config} [options.config]
|
|
173
173
|
* @param {boolean} [options.skipLint]
|
|
174
174
|
*/
|
|
175
|
-
async function parseSingle(input, { filename, logger, config, skipLint, continueOnError = false }) {
|
|
175
|
+
async function parseSingle(input, { filename, logger, config, skipLint, continueOnError = false, yamlToMomoa }) {
|
|
176
176
|
// 1. Build AST
|
|
177
177
|
let src;
|
|
178
178
|
if (typeof input === 'string') {
|
|
@@ -182,7 +182,25 @@ async function parseSingle(input, { filename, logger, config, skipLint, continue
|
|
|
182
182
|
logger.debug({ group: 'parser', task: 'parse', message: 'Start tokens parsing' });
|
|
183
183
|
let document;
|
|
184
184
|
if (typeof input === 'string' && !maybeJSONString(input)) {
|
|
185
|
-
|
|
185
|
+
if (yamlToMomoa) {
|
|
186
|
+
try {
|
|
187
|
+
document = yamlToMomoa(input); // if string, but not JSON, attempt YAML
|
|
188
|
+
} catch (err) {
|
|
189
|
+
logger.error({ message: String(err), filename, src: input, continueOnError });
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
logger.error({
|
|
193
|
+
group: 'parser',
|
|
194
|
+
task: 'parse',
|
|
195
|
+
message: `Install \`yaml-to-momoa\` package to parse YAML, and pass in as option, e.g.:
|
|
196
|
+
|
|
197
|
+
import { parse } from '@terrazzo/parser';
|
|
198
|
+
import yamlToMomoa from 'yaml-to-momoa';
|
|
199
|
+
|
|
200
|
+
parse(yamlString, { yamlToMomoa });`,
|
|
201
|
+
continueOnError: false, // fail here; no point in continuing
|
|
202
|
+
});
|
|
203
|
+
}
|
|
186
204
|
} else {
|
|
187
205
|
document = parseJSON(
|
|
188
206
|
typeof input === 'string' ? input : JSON.stringify(input, undefined, 2), // everything else: assert it’s JSON-serializable
|
|
@@ -259,7 +277,7 @@ async function parseSingle(input, { filename, logger, config, skipLint, continue
|
|
|
259
277
|
originalValue: evaluate(node.value),
|
|
260
278
|
group,
|
|
261
279
|
source: {
|
|
262
|
-
loc: filename ?
|
|
280
|
+
loc: filename ? filename.href : undefined,
|
|
263
281
|
node: sourceNode.value,
|
|
264
282
|
},
|
|
265
283
|
};
|
|
@@ -276,7 +294,7 @@ async function parseSingle(input, { filename, logger, config, skipLint, continue
|
|
|
276
294
|
$type: token.$type,
|
|
277
295
|
$value: mode === '.' ? token.$value : evaluate(modeValues[mode]),
|
|
278
296
|
source: {
|
|
279
|
-
loc: filename ?
|
|
297
|
+
loc: filename ? filename.href : undefined,
|
|
280
298
|
node: mode === '.' ? structuredClone(token.source.node) : modeValues[mode],
|
|
281
299
|
},
|
|
282
300
|
};
|
package/parse/validate.js
CHANGED
|
@@ -266,9 +266,9 @@ export function validateDimension($value, node, { filename, src, logger }) {
|
|
|
266
266
|
logger.error({ message: `Expected string, received ${$value.type}`, filename, node: $value, src });
|
|
267
267
|
} else if ($value.value === '') {
|
|
268
268
|
logger.error({ message: 'Expected dimension, received empty string', filename, node: $value, src });
|
|
269
|
-
} else if (String(Number($value.value)) === $value.value) {
|
|
269
|
+
} else if (String(Number.parseFloat($value.value)) === $value.value) {
|
|
270
270
|
logger.error({ message: 'Missing units', filename, node: $value, src });
|
|
271
|
-
} else if (
|
|
271
|
+
} else if (!/^-?[0-9]+(\.[0-9]+)?/.test($value.value)) {
|
|
272
272
|
logger.error({ message: `Expected dimension with units, received ${print($value)}`, filename, node: $value, src });
|
|
273
273
|
}
|
|
274
274
|
}
|
package/parse/yaml.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { DocumentNode } from '@humanwhocodes/momoa';
|
|
2
|
-
import type Logger from '../logger.js';
|
|
3
|
-
|
|
4
|
-
export interface ParseYAMLOptions {
|
|
5
|
-
logger: Logger;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Take a YAML document and create a Momoa JSON AST from it
|
|
10
|
-
*/
|
|
11
|
-
export default function yamlToAST(input: string, options: ParseYAMLOptions): DocumentNode;
|
package/parse/yaml.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Composer, Parser } from 'yaml';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {import("yaml").YAMLError} YAMLError
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Convert YAML position to line, column
|
|
9
|
-
* @param {string} input
|
|
10
|
-
* @param {YAMLError{"pos"]} pos
|
|
11
|
-
* @return {import("@babel/code-frame").SourceLocation["start"]}
|
|
12
|
-
*/
|
|
13
|
-
function posToLoc(input, pos) {
|
|
14
|
-
let line = 1;
|
|
15
|
-
let column = 0;
|
|
16
|
-
for (let i = 0; i <= (pos[0] || 0); i++) {
|
|
17
|
-
const c = input[i];
|
|
18
|
-
if (c === '\n') {
|
|
19
|
-
line++;
|
|
20
|
-
column = 0;
|
|
21
|
-
}
|
|
22
|
-
column++;
|
|
23
|
-
}
|
|
24
|
-
return { line, column };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Take a YAML document and create a Momoa JSON AST from it
|
|
29
|
-
*/
|
|
30
|
-
export default function yamlToAST(input, { logger }) {
|
|
31
|
-
const parser = new Parser();
|
|
32
|
-
const composer = new Composer();
|
|
33
|
-
for (const node of composer.compose(parser.parse(input))) {
|
|
34
|
-
if (node.errors) {
|
|
35
|
-
for (const error of node.errors) {
|
|
36
|
-
logger.error({
|
|
37
|
-
label: 'parse:yaml',
|
|
38
|
-
message: `${error.code} ${error.message}`,
|
|
39
|
-
node: { loc: { start: posToLoc(input, error.pos) } },
|
|
40
|
-
source: input,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|