perttool 0.1.0-alpha.2
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 +53 -0
- package/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/analysis/graph.d.ts +41 -0
- package/dist/analysis/graph.d.ts.map +1 -0
- package/dist/analysis/graph.js +199 -0
- package/dist/analysis/graph.js.map +1 -0
- package/dist/analysis/precedence.d.ts +52 -0
- package/dist/analysis/precedence.d.ts.map +1 -0
- package/dist/analysis/precedence.js +187 -0
- package/dist/analysis/precedence.js.map +1 -0
- package/dist/analysis/resource.d.ts +96 -0
- package/dist/analysis/resource.d.ts.map +1 -0
- package/dist/analysis/resource.js +522 -0
- package/dist/analysis/resource.js.map +1 -0
- package/dist/application/analyze.d.ts +32 -0
- package/dist/application/analyze.d.ts.map +1 -0
- package/dist/application/analyze.js +144 -0
- package/dist/application/analyze.js.map +1 -0
- package/dist/application/check.d.ts +24 -0
- package/dist/application/check.d.ts.map +1 -0
- package/dist/application/check.js +43 -0
- package/dist/application/check.js.map +1 -0
- package/dist/application/format.d.ts +21 -0
- package/dist/application/format.d.ts.map +1 -0
- package/dist/application/format.js +52 -0
- package/dist/application/format.js.map +1 -0
- package/dist/application/mutate.d.ts +4 -0
- package/dist/application/mutate.d.ts.map +1 -0
- package/dist/application/mutate.js +175 -0
- package/dist/application/mutate.js.map +1 -0
- package/dist/application/next.d.ts +86 -0
- package/dist/application/next.d.ts.map +1 -0
- package/dist/application/next.js +310 -0
- package/dist/application/next.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2103 -0
- package/dist/cli.js.map +1 -0
- package/dist/conversion/mermaid-import.d.ts +26 -0
- package/dist/conversion/mermaid-import.d.ts.map +1 -0
- package/dist/conversion/mermaid-import.js +655 -0
- package/dist/conversion/mermaid-import.js.map +1 -0
- package/dist/conversion/mermaid.d.ts +38 -0
- package/dist/conversion/mermaid.d.ts.map +1 -0
- package/dist/conversion/mermaid.js +362 -0
- package/dist/conversion/mermaid.js.map +1 -0
- package/dist/editing/unified-diff.d.ts +7 -0
- package/dist/editing/unified-diff.d.ts.map +1 -0
- package/dist/editing/unified-diff.js +81 -0
- package/dist/editing/unified-diff.js.map +1 -0
- package/dist/formatter/source-formatter.d.ts +17 -0
- package/dist/formatter/source-formatter.d.ts.map +1 -0
- package/dist/formatter/source-formatter.js +210 -0
- package/dist/formatter/source-formatter.js.map +1 -0
- package/dist/help/registry.d.ts +37 -0
- package/dist/help/registry.d.ts.map +1 -0
- package/dist/help/registry.js +657 -0
- package/dist/help/registry.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/io/document-file.d.ts +9 -0
- package/dist/io/document-file.d.ts.map +1 -0
- package/dist/io/document-file.js +19 -0
- package/dist/io/document-file.js.map +1 -0
- package/dist/io/safe-write.d.ts +33 -0
- package/dist/io/safe-write.d.ts.map +1 -0
- package/dist/io/safe-write.js +280 -0
- package/dist/io/safe-write.js.map +1 -0
- package/dist/model/diagnostics.d.ts +43 -0
- package/dist/model/diagnostics.d.ts.map +1 -0
- package/dist/model/diagnostics.js +47 -0
- package/dist/model/diagnostics.js.map +1 -0
- package/dist/model/rational.d.ts +21 -0
- package/dist/model/rational.d.ts.map +1 -0
- package/dist/model/rational.js +84 -0
- package/dist/model/rational.js.map +1 -0
- package/dist/model/syntax.d.ts +67 -0
- package/dist/model/syntax.d.ts.map +1 -0
- package/dist/model/syntax.js +15 -0
- package/dist/model/syntax.js.map +1 -0
- package/dist/model/units.d.ts +18 -0
- package/dist/model/units.d.ts.map +1 -0
- package/dist/model/units.js +29 -0
- package/dist/model/units.js.map +1 -0
- package/dist/mutation/advance.d.ts +26 -0
- package/dist/mutation/advance.d.ts.map +1 -0
- package/dist/mutation/advance.js +261 -0
- package/dist/mutation/advance.js.map +1 -0
- package/dist/mutation/diagnostics.d.ts +10 -0
- package/dist/mutation/diagnostics.d.ts.map +1 -0
- package/dist/mutation/diagnostics.js +10 -0
- package/dist/mutation/diagnostics.js.map +1 -0
- package/dist/mutation/entity-editor.d.ts +16 -0
- package/dist/mutation/entity-editor.d.ts.map +1 -0
- package/dist/mutation/entity-editor.js +103 -0
- package/dist/mutation/entity-editor.js.map +1 -0
- package/dist/mutation/milestone.d.ts +5 -0
- package/dist/mutation/milestone.d.ts.map +1 -0
- package/dist/mutation/milestone.js +194 -0
- package/dist/mutation/milestone.js.map +1 -0
- package/dist/mutation/resource.d.ts +5 -0
- package/dist/mutation/resource.d.ts.map +1 -0
- package/dist/mutation/resource.js +145 -0
- package/dist/mutation/resource.js.map +1 -0
- package/dist/mutation/source.d.ts +22 -0
- package/dist/mutation/source.d.ts.map +1 -0
- package/dist/mutation/source.js +155 -0
- package/dist/mutation/source.js.map +1 -0
- package/dist/mutation/task.d.ts +10 -0
- package/dist/mutation/task.d.ts.map +1 -0
- package/dist/mutation/task.js +644 -0
- package/dist/mutation/task.js.map +1 -0
- package/dist/mutation/text-edits.d.ts +8 -0
- package/dist/mutation/text-edits.d.ts.map +1 -0
- package/dist/mutation/text-edits.js +33 -0
- package/dist/mutation/text-edits.js.map +1 -0
- package/dist/mutation/types.d.ts +153 -0
- package/dist/mutation/types.d.ts.map +1 -0
- package/dist/mutation/types.js +2 -0
- package/dist/mutation/types.js.map +1 -0
- package/dist/parser/document-parser.d.ts +6 -0
- package/dist/parser/document-parser.d.ts.map +1 -0
- package/dist/parser/document-parser.js +735 -0
- package/dist/parser/document-parser.js.map +1 -0
- package/dist/recommendation/explanation-types.d.ts +226 -0
- package/dist/recommendation/explanation-types.d.ts.map +1 -0
- package/dist/recommendation/explanation-types.js +2 -0
- package/dist/recommendation/explanation-types.js.map +1 -0
- package/dist/recommendation/explanation-validation.d.ts +4 -0
- package/dist/recommendation/explanation-validation.d.ts.map +1 -0
- package/dist/recommendation/explanation-validation.js +745 -0
- package/dist/recommendation/explanation-validation.js.map +1 -0
- package/dist/recommendation/explanation-values.d.ts +7 -0
- package/dist/recommendation/explanation-values.d.ts.map +1 -0
- package/dist/recommendation/explanation-values.js +283 -0
- package/dist/recommendation/explanation-values.js.map +1 -0
- package/dist/recommendation/explanation.d.ts +8 -0
- package/dist/recommendation/explanation.d.ts.map +1 -0
- package/dist/recommendation/explanation.js +1022 -0
- package/dist/recommendation/explanation.js.map +1 -0
- package/dist/recommendation/failure.d.ts +3 -0
- package/dist/recommendation/failure.d.ts.map +1 -0
- package/dist/recommendation/failure.js +4 -0
- package/dist/recommendation/failure.js.map +1 -0
- package/dist/recommendation/json.d.ts +3 -0
- package/dist/recommendation/json.d.ts.map +1 -0
- package/dist/recommendation/json.js +252 -0
- package/dist/recommendation/json.js.map +1 -0
- package/dist/recommendation/override-types.d.ts +117 -0
- package/dist/recommendation/override-types.d.ts.map +1 -0
- package/dist/recommendation/override-types.js +2 -0
- package/dist/recommendation/override-types.js.map +1 -0
- package/dist/recommendation/override.d.ts +7 -0
- package/dist/recommendation/override.d.ts.map +1 -0
- package/dist/recommendation/override.js +717 -0
- package/dist/recommendation/override.js.map +1 -0
- package/dist/recommendation/ranking.d.ts +7 -0
- package/dist/recommendation/ranking.d.ts.map +1 -0
- package/dist/recommendation/ranking.js +391 -0
- package/dist/recommendation/ranking.js.map +1 -0
- package/dist/recommendation/types.d.ts +83 -0
- package/dist/recommendation/types.d.ts.map +1 -0
- package/dist/recommendation/types.js +2 -0
- package/dist/recommendation/types.js.map +1 -0
- package/dist/semantic/validator.d.ts +4 -0
- package/dist/semantic/validator.d.ts.map +1 -0
- package/dist/semantic/validator.js +490 -0
- package/dist/semantic/validator.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
import { countDiagnostics, limitDiagnostics, normalizeMaxDiagnostics, sortDiagnostics, } from "../model/diagnostics.js";
|
|
2
|
+
const identifierPattern = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
3
|
+
const declarationKinds = new Set([
|
|
4
|
+
"project",
|
|
5
|
+
"resource",
|
|
6
|
+
"milestone",
|
|
7
|
+
"task",
|
|
8
|
+
"gate",
|
|
9
|
+
]);
|
|
10
|
+
const allowedFields = {
|
|
11
|
+
project: new Set([
|
|
12
|
+
"version",
|
|
13
|
+
"title",
|
|
14
|
+
"description",
|
|
15
|
+
"as_of",
|
|
16
|
+
"duration_unit",
|
|
17
|
+
"velocity",
|
|
18
|
+
"finish",
|
|
19
|
+
"critical_epsilon",
|
|
20
|
+
"target_duration",
|
|
21
|
+
]),
|
|
22
|
+
resource: new Set(["title", "description", "capacity", "tags"]),
|
|
23
|
+
milestone: new Set(["title", "description", "state", "tags"]),
|
|
24
|
+
task: new Set([
|
|
25
|
+
"title",
|
|
26
|
+
"description",
|
|
27
|
+
"duration",
|
|
28
|
+
"estimate",
|
|
29
|
+
"status",
|
|
30
|
+
"priority",
|
|
31
|
+
"requires",
|
|
32
|
+
"owner",
|
|
33
|
+
"tags",
|
|
34
|
+
"blocked_reason",
|
|
35
|
+
"source",
|
|
36
|
+
]),
|
|
37
|
+
gate: new Set(["reason"]),
|
|
38
|
+
};
|
|
39
|
+
function splitLines(text) {
|
|
40
|
+
if (text.length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const lines = [];
|
|
43
|
+
let offset = 0;
|
|
44
|
+
let lineNumber = 0;
|
|
45
|
+
while (offset < text.length) {
|
|
46
|
+
const newline = text.indexOf("\n", offset);
|
|
47
|
+
const rawEnd = newline === -1 ? text.length : newline;
|
|
48
|
+
const contentEnd = rawEnd > offset && text[rawEnd - 1] === "\r" ? rawEnd - 1 : rawEnd;
|
|
49
|
+
const prefixLength = lineNumber === 0 && text[offset] === "\uFEFF" ? 1 : 0;
|
|
50
|
+
lines.push({
|
|
51
|
+
text: text.slice(offset + prefixLength, contentEnd),
|
|
52
|
+
start: offset,
|
|
53
|
+
end: contentEnd,
|
|
54
|
+
line: lineNumber,
|
|
55
|
+
prefixLength,
|
|
56
|
+
});
|
|
57
|
+
if (newline === -1)
|
|
58
|
+
break;
|
|
59
|
+
offset = newline + 1;
|
|
60
|
+
lineNumber += 1;
|
|
61
|
+
}
|
|
62
|
+
return lines;
|
|
63
|
+
}
|
|
64
|
+
function position(line, column) {
|
|
65
|
+
const adjusted = line.prefixLength + column;
|
|
66
|
+
return {
|
|
67
|
+
offset: line.start + adjusted,
|
|
68
|
+
line: line.line,
|
|
69
|
+
column: adjusted,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function span(line, start, end) {
|
|
73
|
+
return { start: position(line, start), end: position(line, end) };
|
|
74
|
+
}
|
|
75
|
+
function lineSpan(line) {
|
|
76
|
+
return span(line, 0, line.text.length);
|
|
77
|
+
}
|
|
78
|
+
function joinSpan(start, end) {
|
|
79
|
+
return { start: start.start, end: end.end };
|
|
80
|
+
}
|
|
81
|
+
function leadingIndent(line) {
|
|
82
|
+
let indent = 0;
|
|
83
|
+
let hasTab = false;
|
|
84
|
+
for (const character of line.text) {
|
|
85
|
+
if (character === " ") {
|
|
86
|
+
indent += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (character === "\t") {
|
|
90
|
+
hasTab = true;
|
|
91
|
+
indent += 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
return { indent, hasTab };
|
|
97
|
+
}
|
|
98
|
+
function leadingSpaces(line) {
|
|
99
|
+
let spaces = 0;
|
|
100
|
+
while (line.text[spaces] === " ")
|
|
101
|
+
spaces += 1;
|
|
102
|
+
return spaces;
|
|
103
|
+
}
|
|
104
|
+
function diagnostic(code, message, diagnosticSpan, helpTopic, entityId) {
|
|
105
|
+
return {
|
|
106
|
+
code,
|
|
107
|
+
severity: "error",
|
|
108
|
+
message,
|
|
109
|
+
span: diagnosticSpan,
|
|
110
|
+
helpTopic,
|
|
111
|
+
...(entityId === undefined ? {} : { entityId }),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function parseDuration(raw) {
|
|
115
|
+
const match = /^([0-9]+)(?:\.([0-9]+))?([dhp])$/.exec(raw);
|
|
116
|
+
if (match === null)
|
|
117
|
+
return undefined;
|
|
118
|
+
const whole = match[1];
|
|
119
|
+
if (whole === undefined)
|
|
120
|
+
return undefined;
|
|
121
|
+
const fraction = match[2] ?? "";
|
|
122
|
+
const suffix = match[3];
|
|
123
|
+
if (suffix !== "d" && suffix !== "h" && suffix !== "p")
|
|
124
|
+
return undefined;
|
|
125
|
+
return {
|
|
126
|
+
text: raw,
|
|
127
|
+
digits: BigInt(`${whole}${fraction}`),
|
|
128
|
+
scale: fraction.length,
|
|
129
|
+
suffix,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function parseVelocity(raw) {
|
|
133
|
+
const match = /^([0-9]+(?:\.[0-9]+)?p)\/([0-9]+(?:\.[0-9]+)?[dh])$/.exec(raw);
|
|
134
|
+
if (match === null)
|
|
135
|
+
return undefined;
|
|
136
|
+
const points = parseDuration(match[1]);
|
|
137
|
+
const period = parseDuration(match[2]);
|
|
138
|
+
if (points?.suffix !== "p" || (period?.suffix !== "d" && period?.suffix !== "h")) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
text: raw,
|
|
143
|
+
points: points,
|
|
144
|
+
period: period,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function parseInteger(raw) {
|
|
148
|
+
if (!/^[0-9]+$/.test(raw))
|
|
149
|
+
return undefined;
|
|
150
|
+
const value = Number(raw);
|
|
151
|
+
return Number.isSafeInteger(value) && value <= 2_147_483_647 ? value : undefined;
|
|
152
|
+
}
|
|
153
|
+
function parseString(raw) {
|
|
154
|
+
if (!raw.startsWith('"') || !raw.endsWith('"'))
|
|
155
|
+
return undefined;
|
|
156
|
+
try {
|
|
157
|
+
const value = JSON.parse(raw);
|
|
158
|
+
return typeof value === "string" ? value : undefined;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function findInlineCommentStart(text) {
|
|
165
|
+
let quoted = false;
|
|
166
|
+
let escaped = false;
|
|
167
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
168
|
+
const character = text[index];
|
|
169
|
+
if (quoted) {
|
|
170
|
+
if (escaped) {
|
|
171
|
+
escaped = false;
|
|
172
|
+
}
|
|
173
|
+
else if (character === "\\") {
|
|
174
|
+
escaped = true;
|
|
175
|
+
}
|
|
176
|
+
else if (character === '"') {
|
|
177
|
+
quoted = false;
|
|
178
|
+
}
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (character === '"') {
|
|
182
|
+
quoted = true;
|
|
183
|
+
}
|
|
184
|
+
else if (character === "#") {
|
|
185
|
+
return index;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
function inlineCommentDiagnostic(line, start, entityId) {
|
|
191
|
+
return diagnostic("PTDSL-011", "inline commentは使用できません", span(line, start, line.text.length), "syntax.comments", entityId);
|
|
192
|
+
}
|
|
193
|
+
function splitTagItems(raw) {
|
|
194
|
+
if (!raw.startsWith("[") || !raw.endsWith("]"))
|
|
195
|
+
return undefined;
|
|
196
|
+
const body = raw.slice(1, -1).trim();
|
|
197
|
+
if (body === "")
|
|
198
|
+
return [];
|
|
199
|
+
const items = [];
|
|
200
|
+
let start = 0;
|
|
201
|
+
let quoted = false;
|
|
202
|
+
let escaped = false;
|
|
203
|
+
for (let index = 0; index <= body.length; index += 1) {
|
|
204
|
+
const character = body[index];
|
|
205
|
+
if (index === body.length || (character === "," && !quoted)) {
|
|
206
|
+
const item = body.slice(start, index).trim();
|
|
207
|
+
if (item === "")
|
|
208
|
+
return undefined;
|
|
209
|
+
const stringValue = item.startsWith('"') ? parseString(item) : undefined;
|
|
210
|
+
if (stringValue !== undefined)
|
|
211
|
+
items.push(stringValue);
|
|
212
|
+
else if (identifierPattern.test(item))
|
|
213
|
+
items.push(item);
|
|
214
|
+
else
|
|
215
|
+
return undefined;
|
|
216
|
+
start = index + 1;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (character === "\\" && quoted && !escaped) {
|
|
220
|
+
escaped = true;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (character === '"' && !escaped)
|
|
224
|
+
quoted = !quoted;
|
|
225
|
+
escaped = false;
|
|
226
|
+
}
|
|
227
|
+
return quoted ? undefined : items;
|
|
228
|
+
}
|
|
229
|
+
function scalarFieldValue(name, rawValue) {
|
|
230
|
+
if (["title", "owner", "source"].includes(name)) {
|
|
231
|
+
const value = parseString(rawValue);
|
|
232
|
+
return value === undefined
|
|
233
|
+
? { value: rawValue, code: "PTDSL-006", topic: "syntax.string" }
|
|
234
|
+
: { value };
|
|
235
|
+
}
|
|
236
|
+
if (["description", "blocked_reason", "reason"].includes(name)) {
|
|
237
|
+
const value = parseString(rawValue);
|
|
238
|
+
return value === undefined
|
|
239
|
+
? { value: rawValue, code: "PTDSL-006", topic: "syntax.text" }
|
|
240
|
+
: { value };
|
|
241
|
+
}
|
|
242
|
+
if (["version", "capacity", "priority"].includes(name)) {
|
|
243
|
+
const value = parseInteger(rawValue);
|
|
244
|
+
return value === undefined
|
|
245
|
+
? { value: rawValue, code: "PTDSL-012", topic: "syntax" }
|
|
246
|
+
: { value };
|
|
247
|
+
}
|
|
248
|
+
if (["duration", "critical_epsilon", "target_duration"].includes(name)) {
|
|
249
|
+
const value = parseDuration(rawValue);
|
|
250
|
+
return value === undefined
|
|
251
|
+
? { value: rawValue, code: "PTDSL-007", topic: "syntax.duration" }
|
|
252
|
+
: { value };
|
|
253
|
+
}
|
|
254
|
+
if (name === "velocity") {
|
|
255
|
+
const value = parseVelocity(rawValue);
|
|
256
|
+
return value === undefined
|
|
257
|
+
? { value: rawValue, code: "PTDSL-007", topic: "syntax.velocity" }
|
|
258
|
+
: { value };
|
|
259
|
+
}
|
|
260
|
+
if (name === "finish") {
|
|
261
|
+
return identifierPattern.test(rawValue)
|
|
262
|
+
? { value: rawValue }
|
|
263
|
+
: { value: rawValue, code: "PTDSL-004", topic: "syntax.project" };
|
|
264
|
+
}
|
|
265
|
+
if (name === "duration_unit") {
|
|
266
|
+
return rawValue === "day" || rawValue === "hour" || rawValue === "point"
|
|
267
|
+
? { value: rawValue }
|
|
268
|
+
: { value: rawValue, code: "PTDSL-012", topic: "syntax.duration" };
|
|
269
|
+
}
|
|
270
|
+
if (name === "state") {
|
|
271
|
+
return rawValue === "planned" || rawValue === "reached"
|
|
272
|
+
? { value: rawValue }
|
|
273
|
+
: { value: rawValue, code: "PTDSL-012", topic: "syntax.milestone" };
|
|
274
|
+
}
|
|
275
|
+
if (name === "status") {
|
|
276
|
+
return ["planned", "active", "blocked", "done"].includes(rawValue)
|
|
277
|
+
? { value: rawValue }
|
|
278
|
+
: { value: rawValue, code: "PTDSL-012", topic: "syntax.task" };
|
|
279
|
+
}
|
|
280
|
+
if (name === "tags") {
|
|
281
|
+
const value = splitTagItems(rawValue);
|
|
282
|
+
return value === undefined
|
|
283
|
+
? { value: rawValue, code: "PTDSL-009", topic: "syntax.tags" }
|
|
284
|
+
: { value };
|
|
285
|
+
}
|
|
286
|
+
if (name === "as_of")
|
|
287
|
+
return { value: rawValue };
|
|
288
|
+
return { value: rawValue };
|
|
289
|
+
}
|
|
290
|
+
function parseNestedEstimate(lines, startIndex, diagnostics, trivia) {
|
|
291
|
+
const children = [];
|
|
292
|
+
let index = startIndex;
|
|
293
|
+
let endSpan = lineSpan(lines[startIndex - 1]);
|
|
294
|
+
while (index < lines.length) {
|
|
295
|
+
const line = lines[index];
|
|
296
|
+
const trimmed = line.text.trim();
|
|
297
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
298
|
+
trivia.push({
|
|
299
|
+
kind: trimmed === "" ? "blank" : "comment",
|
|
300
|
+
text: line.text,
|
|
301
|
+
span: lineSpan(line),
|
|
302
|
+
});
|
|
303
|
+
endSpan = lineSpan(line);
|
|
304
|
+
index += 1;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const { indent, hasTab } = leadingIndent(line);
|
|
308
|
+
if (indent <= 2)
|
|
309
|
+
break;
|
|
310
|
+
if (hasTab || indent !== 4) {
|
|
311
|
+
diagnostics.push(diagnostic(hasTab ? "PTDSL-001" : "PTDSL-002", "estimate blockは4 spacesでindentしてください", span(line, 0, indent), "syntax.indentation"));
|
|
312
|
+
index += 1;
|
|
313
|
+
if (indent > 4)
|
|
314
|
+
index = skipIndentedRegion(lines, index, 4);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const content = line.text.slice(4).trimEnd();
|
|
318
|
+
const inlineCommentStart = findInlineCommentStart(content);
|
|
319
|
+
if (inlineCommentStart !== undefined) {
|
|
320
|
+
diagnostics.push(inlineCommentDiagnostic(line, 4 + inlineCommentStart));
|
|
321
|
+
index += 1;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const match = /^(optimistic|most_likely|pessimistic) +(.+)$/.exec(content);
|
|
325
|
+
if (match === null) {
|
|
326
|
+
diagnostics.push(diagnostic("PTDSL-005", "estimate blockのfieldが不正です", lineSpan(line), "syntax.estimate"));
|
|
327
|
+
index += 1;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const name = match[1];
|
|
331
|
+
const rawValue = match[2];
|
|
332
|
+
const valueOffset = line.text.indexOf(rawValue, 4 + name.length);
|
|
333
|
+
const valueSpan = span(line, valueOffset, valueOffset + rawValue.length);
|
|
334
|
+
const value = parseDuration(rawValue);
|
|
335
|
+
if (value === undefined) {
|
|
336
|
+
diagnostics.push(diagnostic("PTDSL-007", `${name}のdurationが不正です`, valueSpan, "syntax.duration"));
|
|
337
|
+
}
|
|
338
|
+
children.push({
|
|
339
|
+
name,
|
|
340
|
+
rawValue,
|
|
341
|
+
value: value ?? rawValue,
|
|
342
|
+
span: lineSpan(line),
|
|
343
|
+
valueSpan,
|
|
344
|
+
});
|
|
345
|
+
endSpan = lineSpan(line);
|
|
346
|
+
index += 1;
|
|
347
|
+
}
|
|
348
|
+
return { children, nextIndex: index, endSpan };
|
|
349
|
+
}
|
|
350
|
+
function parseNestedRequirements(lines, startIndex, diagnostics, trivia) {
|
|
351
|
+
const requirements = [];
|
|
352
|
+
let index = startIndex;
|
|
353
|
+
let endSpan = lineSpan(lines[startIndex - 1]);
|
|
354
|
+
while (index < lines.length) {
|
|
355
|
+
const line = lines[index];
|
|
356
|
+
const trimmed = line.text.trim();
|
|
357
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
358
|
+
trivia.push({
|
|
359
|
+
kind: trimmed === "" ? "blank" : "comment",
|
|
360
|
+
text: line.text,
|
|
361
|
+
span: lineSpan(line),
|
|
362
|
+
});
|
|
363
|
+
endSpan = lineSpan(line);
|
|
364
|
+
index += 1;
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
const { indent, hasTab } = leadingIndent(line);
|
|
368
|
+
if (indent <= 2)
|
|
369
|
+
break;
|
|
370
|
+
if (hasTab || indent !== 4) {
|
|
371
|
+
diagnostics.push(diagnostic(hasTab ? "PTDSL-001" : "PTDSL-002", "requires blockは4 spacesでindentしてください", span(line, 0, indent), "syntax.indentation"));
|
|
372
|
+
index += 1;
|
|
373
|
+
if (indent > 4)
|
|
374
|
+
index = skipIndentedRegion(lines, index, 4);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const content = line.text.slice(4).trimEnd();
|
|
378
|
+
const inlineCommentStart = findInlineCommentStart(content);
|
|
379
|
+
if (inlineCommentStart !== undefined) {
|
|
380
|
+
diagnostics.push(inlineCommentDiagnostic(line, 4 + inlineCommentStart));
|
|
381
|
+
index += 1;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const match = /^([A-Za-z][A-Za-z0-9_-]*) +([0-9]+)$/.exec(content);
|
|
385
|
+
if (match === null) {
|
|
386
|
+
diagnostics.push(diagnostic("PTDSL-005", "resource requirementは`RESOURCE_ID units`で記述してください", lineSpan(line), "syntax.task"));
|
|
387
|
+
index += 1;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const resourceId = match[1];
|
|
391
|
+
const unitsRaw = match[2];
|
|
392
|
+
const units = parseInteger(unitsRaw);
|
|
393
|
+
const resourceOffset = line.text.indexOf(resourceId, 4);
|
|
394
|
+
const unitsOffset = line.text.lastIndexOf(unitsRaw);
|
|
395
|
+
const requirementSpan = lineSpan(line);
|
|
396
|
+
if (units === undefined) {
|
|
397
|
+
diagnostics.push(diagnostic("PTSEM-109", "resource requirement unitsが範囲外です", span(line, unitsOffset, unitsOffset + unitsRaw.length), "syntax.resource"));
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
requirements.push({
|
|
401
|
+
resourceId,
|
|
402
|
+
units,
|
|
403
|
+
span: requirementSpan,
|
|
404
|
+
resourceSpan: span(line, resourceOffset, resourceOffset + resourceId.length),
|
|
405
|
+
unitsSpan: span(line, unitsOffset, unitsOffset + unitsRaw.length),
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
endSpan = requirementSpan;
|
|
409
|
+
index += 1;
|
|
410
|
+
}
|
|
411
|
+
return { requirements, nextIndex: index, endSpan };
|
|
412
|
+
}
|
|
413
|
+
function parseBlockText(lines, startIndex, diagnostics) {
|
|
414
|
+
const markerSpan = lineSpan(lines[startIndex - 1]);
|
|
415
|
+
const blockLines = [];
|
|
416
|
+
let index = startIndex;
|
|
417
|
+
let errorEndSpan;
|
|
418
|
+
while (index < lines.length) {
|
|
419
|
+
const line = lines[index];
|
|
420
|
+
if (line.text.trim() === "") {
|
|
421
|
+
blockLines.push({ line, sourceIndex: index, spaces: undefined });
|
|
422
|
+
index += 1;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
const spaces = leadingSpaces(line);
|
|
426
|
+
const tabBeforeContent = line.text[spaces] === "\t" && spaces < 4;
|
|
427
|
+
if (!tabBeforeContent && spaces <= 2)
|
|
428
|
+
break;
|
|
429
|
+
if (tabBeforeContent || spaces < 4) {
|
|
430
|
+
diagnostics.push(diagnostic(tabBeforeContent ? "PTDSL-001" : "PTDSL-010", "block textはfieldより1 level以上深くindentしてください", span(line, 0, Math.max(spaces + (tabBeforeContent ? 1 : 0), 1)), "syntax.text"));
|
|
431
|
+
errorEndSpan = lineSpan(line);
|
|
432
|
+
index = skipIndentedRegion(lines, index + 1, 2);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
blockLines.push({ line, sourceIndex: index, spaces });
|
|
436
|
+
index += 1;
|
|
437
|
+
}
|
|
438
|
+
const firstContentIndex = blockLines.findIndex(({ spaces }) => spaces !== undefined);
|
|
439
|
+
const lastContentIndex = blockLines.findLastIndex(({ spaces }) => spaces !== undefined);
|
|
440
|
+
const leadingTrivia = blockLines
|
|
441
|
+
.slice(0, firstContentIndex === -1 ? blockLines.length : firstContentIndex)
|
|
442
|
+
.map(({ line }) => ({
|
|
443
|
+
kind: "blank",
|
|
444
|
+
text: line.text,
|
|
445
|
+
span: lineSpan(line),
|
|
446
|
+
}));
|
|
447
|
+
if (firstContentIndex === -1 || lastContentIndex === -1) {
|
|
448
|
+
if (errorEndSpan === undefined) {
|
|
449
|
+
diagnostics.push(diagnostic("PTDSL-010", "block textは1行以上のnonblank contentを必要とします", markerSpan, "syntax.text"));
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
value: "",
|
|
453
|
+
nextIndex: index,
|
|
454
|
+
endSpan: errorEndSpan ?? markerSpan,
|
|
455
|
+
leadingTrivia,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const contentRegion = blockLines.slice(firstContentIndex, lastContentIndex + 1);
|
|
459
|
+
const commonIndent = Math.min(...contentRegion.flatMap(({ spaces }) => (spaces === undefined ? [] : [spaces])));
|
|
460
|
+
const firstContentLine = blockLines[firstContentIndex].line;
|
|
461
|
+
const lastContent = blockLines[lastContentIndex];
|
|
462
|
+
const contentSpan = {
|
|
463
|
+
start: position(firstContentLine, commonIndent),
|
|
464
|
+
end: position(lastContent.line, lastContent.line.text.length),
|
|
465
|
+
};
|
|
466
|
+
return {
|
|
467
|
+
value: contentRegion
|
|
468
|
+
.map(({ line, spaces }) => (spaces === undefined ? "" : line.text.slice(commonIndent)))
|
|
469
|
+
.join("\n"),
|
|
470
|
+
nextIndex: errorEndSpan === undefined ? lastContent.sourceIndex + 1 : index,
|
|
471
|
+
endSpan: errorEndSpan ?? lineSpan(lastContent.line),
|
|
472
|
+
contentSpan,
|
|
473
|
+
leadingTrivia,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function skipIndentedRegion(lines, startIndex, parentIndent) {
|
|
477
|
+
let index = startIndex;
|
|
478
|
+
while (index < lines.length) {
|
|
479
|
+
const line = lines[index];
|
|
480
|
+
if (line.text.trim() === "") {
|
|
481
|
+
index += 1;
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (leadingIndent(line).indent <= parentIndent)
|
|
485
|
+
break;
|
|
486
|
+
index += 1;
|
|
487
|
+
}
|
|
488
|
+
return index;
|
|
489
|
+
}
|
|
490
|
+
function isKnownDeclarationHeader(text) {
|
|
491
|
+
const normalized = text.trimEnd();
|
|
492
|
+
return (/^(?:project|resource|milestone) +[A-Za-z][A-Za-z0-9_-]*:$/.test(normalized) ||
|
|
493
|
+
/^(?:task|gate) +[A-Za-z][A-Za-z0-9_-]* +[A-Za-z][A-Za-z0-9_-]* +-> +[A-Za-z][A-Za-z0-9_-]*:$/.test(normalized));
|
|
494
|
+
}
|
|
495
|
+
function skipInvalidTopLevelRegion(lines, startIndex, trivia) {
|
|
496
|
+
let index = startIndex;
|
|
497
|
+
while (index < lines.length) {
|
|
498
|
+
const line = lines[index];
|
|
499
|
+
const trimmed = line.text.trim();
|
|
500
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
501
|
+
trivia.push({
|
|
502
|
+
kind: trimmed === "" ? "blank" : "comment",
|
|
503
|
+
text: line.text,
|
|
504
|
+
span: lineSpan(line),
|
|
505
|
+
});
|
|
506
|
+
index += 1;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
const indentation = leadingIndent(line);
|
|
510
|
+
if (indentation.indent === 0 && isKnownDeclarationHeader(line.text))
|
|
511
|
+
break;
|
|
512
|
+
index += 1;
|
|
513
|
+
}
|
|
514
|
+
return index;
|
|
515
|
+
}
|
|
516
|
+
function parseDeclarationHeader(line, diagnostics) {
|
|
517
|
+
const normalized = line.text.trimEnd();
|
|
518
|
+
const edge = /^(task|gate) +([A-Za-z][A-Za-z0-9_-]*) +([A-Za-z][A-Za-z0-9_-]*) +-> +([A-Za-z][A-Za-z0-9_-]*):$/.exec(normalized);
|
|
519
|
+
if (edge !== null) {
|
|
520
|
+
const kind = edge[1];
|
|
521
|
+
const id = edge[2];
|
|
522
|
+
const from = edge[3];
|
|
523
|
+
const to = edge[4];
|
|
524
|
+
const idStart = line.text.indexOf(id, kind.length + 1);
|
|
525
|
+
const fromStart = line.text.indexOf(from, idStart + id.length);
|
|
526
|
+
const arrowStart = line.text.indexOf("->", fromStart + from.length);
|
|
527
|
+
const toStart = line.text.indexOf(to, arrowStart + 2);
|
|
528
|
+
return {
|
|
529
|
+
kind,
|
|
530
|
+
id,
|
|
531
|
+
idSpan: span(line, idStart, idStart + id.length),
|
|
532
|
+
headerSpan: lineSpan(line),
|
|
533
|
+
from,
|
|
534
|
+
fromSpan: span(line, fromStart, fromStart + from.length),
|
|
535
|
+
to,
|
|
536
|
+
toSpan: span(line, toStart, toStart + to.length),
|
|
537
|
+
arrowSpan: span(line, arrowStart, arrowStart + 2),
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
const simple = /^(project|resource|milestone) +([A-Za-z][A-Za-z0-9_-]*):$/.exec(normalized);
|
|
541
|
+
if (simple !== null) {
|
|
542
|
+
const kind = simple[1];
|
|
543
|
+
const id = simple[2];
|
|
544
|
+
const idStart = line.text.indexOf(id, kind.length + 1);
|
|
545
|
+
return {
|
|
546
|
+
kind,
|
|
547
|
+
id,
|
|
548
|
+
idSpan: span(line, idStart, idStart + id.length),
|
|
549
|
+
headerSpan: lineSpan(line),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
const firstWord = line.text.trim().split(/\s+/, 1)[0] ?? "";
|
|
553
|
+
diagnostics.push(diagnostic(declarationKinds.has(firstWord) ? "PTDSL-004" : "PTDSL-003", "top-level declaration headerが不正です", lineSpan(line), "syntax.top-level"));
|
|
554
|
+
return undefined;
|
|
555
|
+
}
|
|
556
|
+
export function parseDocument(text, options = {}) {
|
|
557
|
+
const maxDiagnostics = normalizeMaxDiagnostics(options.maxDiagnostics);
|
|
558
|
+
const diagnostics = [];
|
|
559
|
+
const declarations = [];
|
|
560
|
+
const trivia = [];
|
|
561
|
+
const lines = splitLines(text);
|
|
562
|
+
let index = 0;
|
|
563
|
+
while (index < lines.length) {
|
|
564
|
+
const headerLine = lines[index];
|
|
565
|
+
const trimmed = headerLine.text.trim();
|
|
566
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
567
|
+
trivia.push({
|
|
568
|
+
kind: trimmed === "" ? "blank" : "comment",
|
|
569
|
+
text: headerLine.text,
|
|
570
|
+
span: lineSpan(headerLine),
|
|
571
|
+
});
|
|
572
|
+
index += 1;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const { indent, hasTab } = leadingIndent(headerLine);
|
|
576
|
+
if (hasTab || indent !== 0) {
|
|
577
|
+
diagnostics.push(diagnostic(hasTab ? "PTDSL-001" : "PTDSL-002", "top-level declarationはcolumn 0から開始してください", span(headerLine, 0, indent), "syntax.indentation"));
|
|
578
|
+
index += 1;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const headerInlineCommentStart = findInlineCommentStart(headerLine.text);
|
|
582
|
+
if (headerInlineCommentStart !== undefined) {
|
|
583
|
+
diagnostics.push(inlineCommentDiagnostic(headerLine, headerInlineCommentStart));
|
|
584
|
+
index += 1;
|
|
585
|
+
index = skipInvalidTopLevelRegion(lines, index, trivia);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
const header = parseDeclarationHeader(headerLine, diagnostics);
|
|
589
|
+
index += 1;
|
|
590
|
+
if (header === undefined) {
|
|
591
|
+
index = skipInvalidTopLevelRegion(lines, index, trivia);
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
const fields = [];
|
|
595
|
+
let declarationEnd = header.headerSpan;
|
|
596
|
+
while (index < lines.length) {
|
|
597
|
+
const line = lines[index];
|
|
598
|
+
const bodyTrimmed = line.text.trim();
|
|
599
|
+
if (bodyTrimmed === "" || bodyTrimmed.startsWith("#")) {
|
|
600
|
+
trivia.push({
|
|
601
|
+
kind: bodyTrimmed === "" ? "blank" : "comment",
|
|
602
|
+
text: line.text,
|
|
603
|
+
span: lineSpan(line),
|
|
604
|
+
});
|
|
605
|
+
declarationEnd = lineSpan(line);
|
|
606
|
+
index += 1;
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
const indentation = leadingIndent(line);
|
|
610
|
+
if (indentation.indent === 0)
|
|
611
|
+
break;
|
|
612
|
+
if (indentation.hasTab || indentation.indent !== 2) {
|
|
613
|
+
diagnostics.push(diagnostic(indentation.hasTab ? "PTDSL-001" : "PTDSL-002", "declaration fieldは2 spacesでindentしてください", span(line, 0, indentation.indent), "syntax.indentation", header.id));
|
|
614
|
+
index += 1;
|
|
615
|
+
if (indentation.indent > 2) {
|
|
616
|
+
index = skipIndentedRegion(lines, index, 2);
|
|
617
|
+
}
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
const content = line.text.slice(2).trimEnd();
|
|
621
|
+
const inlineCommentStart = findInlineCommentStart(content);
|
|
622
|
+
if (inlineCommentStart !== undefined) {
|
|
623
|
+
diagnostics.push(inlineCommentDiagnostic(line, 2 + inlineCommentStart, header.id));
|
|
624
|
+
index += 1;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
const blockMatch = /^([a-z_]+):$/.exec(content);
|
|
628
|
+
if (blockMatch !== null) {
|
|
629
|
+
const name = blockMatch[1];
|
|
630
|
+
const isKnownBlock = name === "estimate" || name === "requires";
|
|
631
|
+
if (!isKnownBlock || !allowedFields[header.kind].has(name)) {
|
|
632
|
+
diagnostics.push(diagnostic("PTDSL-005", `${header.kind}にunknown block field ${name}があります`, span(line, 2, 2 + name.length), `syntax.${header.kind}`, header.id));
|
|
633
|
+
index += 1;
|
|
634
|
+
index = skipIndentedRegion(lines, index, 2);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const keywordStart = 2;
|
|
638
|
+
if (name === "estimate") {
|
|
639
|
+
const parsed = parseNestedEstimate(lines, index + 1, diagnostics, trivia);
|
|
640
|
+
fields.push({
|
|
641
|
+
name,
|
|
642
|
+
rawValue: "",
|
|
643
|
+
value: Object.fromEntries(parsed.children.map((child) => [child.name, child.value])),
|
|
644
|
+
span: joinSpan(lineSpan(line), parsed.endSpan),
|
|
645
|
+
valueSpan: span(line, keywordStart, keywordStart + name.length),
|
|
646
|
+
children: parsed.children,
|
|
647
|
+
});
|
|
648
|
+
declarationEnd = parsed.endSpan;
|
|
649
|
+
index = parsed.nextIndex;
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
const parsed = parseNestedRequirements(lines, index + 1, diagnostics, trivia);
|
|
653
|
+
fields.push({
|
|
654
|
+
name,
|
|
655
|
+
rawValue: "",
|
|
656
|
+
value: parsed.requirements,
|
|
657
|
+
span: joinSpan(lineSpan(line), parsed.endSpan),
|
|
658
|
+
valueSpan: span(line, keywordStart, keywordStart + name.length),
|
|
659
|
+
});
|
|
660
|
+
declarationEnd = parsed.endSpan;
|
|
661
|
+
index = parsed.nextIndex;
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
const textBlockMatch = /^(description|blocked_reason|reason) +\|$/.exec(content);
|
|
665
|
+
if (textBlockMatch !== null) {
|
|
666
|
+
const name = textBlockMatch[1];
|
|
667
|
+
if (!allowedFields[header.kind].has(name)) {
|
|
668
|
+
diagnostics.push(diagnostic("PTDSL-005", `${header.kind}に${name} fieldは使用できません`, lineSpan(line), `syntax.${header.kind}`, header.id));
|
|
669
|
+
index += 1;
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
const parsed = parseBlockText(lines, index + 1, diagnostics);
|
|
673
|
+
const valueStart = line.text.lastIndexOf("|");
|
|
674
|
+
trivia.push(...parsed.leadingTrivia);
|
|
675
|
+
fields.push({
|
|
676
|
+
name,
|
|
677
|
+
rawValue: "|",
|
|
678
|
+
value: parsed.value,
|
|
679
|
+
span: joinSpan(lineSpan(line), parsed.endSpan),
|
|
680
|
+
valueSpan: span(line, valueStart, valueStart + 1),
|
|
681
|
+
...(parsed.contentSpan === undefined ? {} : { contentSpan: parsed.contentSpan }),
|
|
682
|
+
});
|
|
683
|
+
declarationEnd = parsed.endSpan;
|
|
684
|
+
index = parsed.nextIndex;
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
const scalar = /^([a-z_]+) +(.+)$/.exec(content);
|
|
688
|
+
if (scalar === null) {
|
|
689
|
+
diagnostics.push(diagnostic("PTDSL-004", "field syntaxが不正です", lineSpan(line), `syntax.${header.kind}`, header.id));
|
|
690
|
+
index += 1;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const name = scalar[1];
|
|
694
|
+
const rawValue = scalar[2];
|
|
695
|
+
const nameStart = 2;
|
|
696
|
+
const valueStart = line.text.indexOf(rawValue, nameStart + name.length);
|
|
697
|
+
const valueSpan = span(line, valueStart, valueStart + rawValue.length);
|
|
698
|
+
if (!allowedFields[header.kind].has(name)) {
|
|
699
|
+
diagnostics.push(diagnostic("PTDSL-005", `${header.kind}にunknown field ${name}があります`, span(line, nameStart, nameStart + name.length), `syntax.${header.kind}`, header.id));
|
|
700
|
+
index += 1;
|
|
701
|
+
if (rawValue === "|")
|
|
702
|
+
index = skipIndentedRegion(lines, index, 2);
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
const parsed = scalarFieldValue(name, rawValue);
|
|
706
|
+
if (parsed.code !== undefined) {
|
|
707
|
+
diagnostics.push(diagnostic(parsed.code, `${name}の値が不正です`, valueSpan, parsed.topic ?? "syntax", header.id));
|
|
708
|
+
}
|
|
709
|
+
fields.push({
|
|
710
|
+
name,
|
|
711
|
+
rawValue,
|
|
712
|
+
value: parsed.value,
|
|
713
|
+
span: lineSpan(line),
|
|
714
|
+
valueSpan,
|
|
715
|
+
});
|
|
716
|
+
declarationEnd = lineSpan(line);
|
|
717
|
+
index += 1;
|
|
718
|
+
}
|
|
719
|
+
declarations.push({
|
|
720
|
+
...header,
|
|
721
|
+
fields,
|
|
722
|
+
span: joinSpan(header.headerSpan, declarationEnd),
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
const document = { text, declarations, trivia };
|
|
726
|
+
const sortedDiagnostics = sortDiagnostics(diagnostics);
|
|
727
|
+
const limited = limitDiagnostics(sortedDiagnostics, maxDiagnostics);
|
|
728
|
+
return {
|
|
729
|
+
document,
|
|
730
|
+
diagnostics: limited.diagnostics,
|
|
731
|
+
diagnosticCounts: countDiagnostics(sortedDiagnostics),
|
|
732
|
+
diagnosticsTruncated: limited.truncated,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
//# sourceMappingURL=document-parser.js.map
|