@terrazzo/parser 0.0.2 → 0.0.3
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/package.json +1 -1
- package/parse/index.js +29 -18
package/package.json
CHANGED
package/parse/index.js
CHANGED
|
@@ -56,38 +56,41 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
56
56
|
// 2. Walk AST once to validate tokens
|
|
57
57
|
const startValidation = performance.now();
|
|
58
58
|
logger.debug({ group: 'parser', task: 'validate', message: 'Start tokens validation' });
|
|
59
|
-
|
|
60
|
-
let last$TypePath = '';
|
|
59
|
+
const $typeInheritance = {};
|
|
61
60
|
traverse(ast, {
|
|
62
61
|
enter(node, parent, path) {
|
|
63
|
-
// reset last$Type if not in a direct ancestor tree
|
|
64
|
-
if (!last$TypePath || !path.join('.').startsWith(last$TypePath)) {
|
|
65
|
-
last$Type = undefined;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
62
|
if (node.type === 'Member' && node.value.type === 'Object' && node.value.members) {
|
|
69
63
|
const members = getObjMembers(node.value);
|
|
70
64
|
|
|
71
|
-
// keep track of
|
|
72
|
-
// note: this is only reliable in a synchronous, single-pass traversal;
|
|
73
|
-
// otherwise we’d have to do something more complicated
|
|
65
|
+
// keep track of $types
|
|
74
66
|
if (members.$type && members.$type.type === 'String' && !members.$value) {
|
|
75
|
-
|
|
76
|
-
last$TypePath = path.join('.');
|
|
67
|
+
$typeInheritance[path.join('.') || '.'] = node.value.members.find((m) => m.name.value === '$type');
|
|
77
68
|
}
|
|
78
69
|
|
|
79
70
|
if (members.$value) {
|
|
80
71
|
const extensions = members.$extensions ? getObjMembers(members.$extensions) : undefined;
|
|
81
72
|
const sourceNode = structuredClone(node);
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
const id = path.join('.');
|
|
74
|
+
|
|
75
|
+
// get parent type by taking the closest-scoped $type (length === closer)
|
|
76
|
+
let parent$type;
|
|
77
|
+
let longestPath = '';
|
|
78
|
+
for (const [k, v] of Object.entries($typeInheritance)) {
|
|
79
|
+
if (k === '.' || id.startsWith(k)) {
|
|
80
|
+
if (k.length > longestPath.length) {
|
|
81
|
+
parent$type = v;
|
|
82
|
+
longestPath = k;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (parent$type && !members.$type) {
|
|
87
|
+
sourceNode.value = injectObjMembers(sourceNode.value, [parent$type]);
|
|
84
88
|
}
|
|
85
89
|
validate(sourceNode, { ast, logger });
|
|
86
90
|
|
|
87
|
-
const id = path.join('.');
|
|
88
91
|
const group = { id: splitID(id).group, tokens: [] };
|
|
89
|
-
if (
|
|
90
|
-
group.$type =
|
|
92
|
+
if (parent$type) {
|
|
93
|
+
group.$type = parent$type.value.value;
|
|
91
94
|
}
|
|
92
95
|
// note: this will also include sibling tokens, so be selective about only accessing group-specific properties
|
|
93
96
|
const groupMembers = getObjMembers(parent);
|
|
@@ -98,7 +101,7 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
98
101
|
group.$extensions = evaluate(groupMembers.$extensions);
|
|
99
102
|
}
|
|
100
103
|
const token = {
|
|
101
|
-
$type: members.$type?.value ??
|
|
104
|
+
$type: members.$type?.value ?? parent$type?.value.value,
|
|
102
105
|
$value: evaluate(members.$value),
|
|
103
106
|
id,
|
|
104
107
|
mode: {},
|
|
@@ -130,6 +133,14 @@ export default async function parse(input, { logger = new Logger(), skipLint = f
|
|
|
130
133
|
logger.warn({ message: `Group ${id} has "value". Did you mean "$value"?`, node, ast });
|
|
131
134
|
}
|
|
132
135
|
}
|
|
136
|
+
|
|
137
|
+
// edge case: if $type appears at root of tokens.json, collect it
|
|
138
|
+
if (node.type === 'Document' && node.body.type === 'Object' && node.body.members) {
|
|
139
|
+
const members = getObjMembers(node.body);
|
|
140
|
+
if (members.$type && members.$type.type === 'String' && !members.$value) {
|
|
141
|
+
$typeInheritance['.'] = node.body.members.find((m) => m.name.value === '$type');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
133
144
|
},
|
|
134
145
|
});
|
|
135
146
|
logger.debug({
|