-
Notifications
You must be signed in to change notification settings - Fork 28.1k
/
yaml_to_js.js
134 lines (122 loc) Β· 3.99 KB
/
yaml_to_js.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
'use strict';
const {
codes: {
ERR_TEST_FAILURE,
},
} = require('internal/errors');
const AssertionError = require('internal/assert/assertion_error');
const {
ArrayPrototypeJoin,
ArrayPrototypePush,
Error,
Number,
NumberIsNaN,
RegExpPrototypeExec,
StringPrototypeEndsWith,
StringPrototypeRepeat,
StringPrototypeSlice,
StringPrototypeStartsWith,
StringPrototypeSubstring,
} = primordials;
const kYamlKeyRegex = /^(\s+)?(\w+):(\s)*([>|][-+])?(.*)$/;
const kStackDelimiter = ' at ';
function reConstructError(parsedYaml) {
if (!('error' in parsedYaml)) {
return parsedYaml;
}
const isAssertionError = parsedYaml.code === 'ERR_ASSERTION' ||
'actual' in parsedYaml || 'expected' in parsedYaml || 'operator' in parsedYaml;
const isTestFailure = parsedYaml.code === 'ERR_TEST_FAILURE' || 'failureType' in parsedYaml;
const stack = parsedYaml.stack ? kStackDelimiter + ArrayPrototypeJoin(parsedYaml.stack, `\n${kStackDelimiter}`) : '';
let error, cause;
if (isAssertionError) {
cause = new AssertionError({
message: parsedYaml.error,
actual: parsedYaml.actual,
expected: parsedYaml.expected,
operator: parsedYaml.operator,
});
} else {
// eslint-disable-next-line no-restricted-syntax
cause = new Error(parsedYaml.error);
}
const name = parsedYaml.name ?? 'Error';
cause.stack = `${name}: ${parsedYaml.error}\n${stack}`;
if (!isAssertionError && !isTestFailure) {
cause.code = parsedYaml.code;
}
if (isTestFailure) {
error = new ERR_TEST_FAILURE(cause, parsedYaml.failureType);
error.stack = stack;
}
parsedYaml.error = error ?? cause;
delete parsedYaml.stack;
delete parsedYaml.code;
delete parsedYaml.failureType;
delete parsedYaml.actual;
delete parsedYaml.expected;
delete parsedYaml.operator;
return parsedYaml;
}
function getYamlValue(value) {
if (StringPrototypeStartsWith(value, "'") && StringPrototypeEndsWith(value, "'")) {
return StringPrototypeSlice(value, 1, -1);
}
if (value === 'true') {
return true;
}
if (value === 'false') {
return false;
}
if (value !== '') {
const valueAsNumber = Number(value);
return NumberIsNaN(valueAsNumber) ? value : valueAsNumber;
}
return value;
}
// This parses the YAML generated by the built-in TAP reporter,
// which is a subset of the full YAML spec. There are some
// YAML features that won't be parsed here. This function should not be exposed publicly.
function YAMLToJs(lines) {
if (lines == null) {
return undefined;
}
const result = { __proto__: null };
let context = { __proto__: null, object: result, indent: 0, currentKey: null };
let isInYamlBlock = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (isInYamlBlock && !StringPrototypeStartsWith(line, StringPrototypeRepeat(' ', isInYamlBlock.indent))) {
context.object[isInYamlBlock.key] = isInYamlBlock.key === 'stack' ?
context.object[isInYamlBlock.key] : ArrayPrototypeJoin(context.object[isInYamlBlock.key], '\n');
isInYamlBlock = false;
}
if (isInYamlBlock) {
const blockLine = StringPrototypeSubstring(line, isInYamlBlock.indent);
ArrayPrototypePush(context.object[isInYamlBlock.key], blockLine);
continue;
}
const match = RegExpPrototypeExec(kYamlKeyRegex, line);
if (match !== null) {
const { 1: leadingSpaces, 2: key, 4: block, 5: value } = match;
const indent = leadingSpaces?.length ?? 0;
if (block) {
isInYamlBlock = { key, indent: indent + 2 };
context.object[key] = [];
continue;
}
if (indent > context.indent) {
context.object[context.currentKey] ||= {};
context = { __proto__: null, parent: context, object: context.object[context.currentKey], indent };
} else if (indent < context.indent) {
context = context.parent;
}
context.currentKey = key;
context.object[key] = getYamlValue(value);
}
}
return reConstructError(result);
}
module.exports = {
YAMLToJs,
};