patram 0.5.0 → 0.6.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/lib/build-graph-identity.js +42 -1
- package/lib/build-graph.js +1 -1
- package/lib/check-directive-metadata.js +160 -5
- package/lib/check-directive-path-target.js +173 -0
- package/lib/check-directive-value.js +122 -125
- package/lib/directive-validation-test-helpers.js +87 -0
- package/lib/load-patram-config.js +95 -8
- package/lib/load-project-graph.js +16 -6
- package/lib/parse-claims.js +95 -8
- package/lib/parse-claims.types.ts +7 -0
- package/lib/parse-markdown-claims.js +9 -3
- package/lib/parse-markdown-directives.js +48 -25
- package/lib/parse-yaml-claims.js +472 -0
- package/lib/patram.js +3 -0
- package/lib/source-file-defaults.js +3 -0
- package/package.json +2 -1
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/** @import * as yaml from 'yaml'; */
|
|
2
|
+
/* eslint-disable max-lines */
|
|
3
|
+
/**
|
|
4
|
+
* @import { PatramDiagnostic } from './load-patram-config.types.ts';
|
|
5
|
+
* @import { ParseClaimsInput, ParseSourceFileResult, PatramClaimFields } from './parse-claims.types.ts';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { isMap, isScalar, isSeq, LineCounter, parseAllDocuments } from 'yaml';
|
|
9
|
+
|
|
10
|
+
import { createClaim, getFileExtension } from './claim-helpers.js';
|
|
11
|
+
import { YAML_SOURCE_FILE_EXTENSIONS } from './source-file-defaults.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* YAML claim parsing.
|
|
15
|
+
*
|
|
16
|
+
* Parses standalone YAML metadata files and front matter with one projection
|
|
17
|
+
* model for top-level scalar directives.
|
|
18
|
+
*
|
|
19
|
+
* Kind: parse
|
|
20
|
+
* Status: active
|
|
21
|
+
* Tracked in: ../docs/plans/v0/yaml-source-and-front-matter.md
|
|
22
|
+
* Decided by: ../docs/decisions/yaml-source-and-front-matter.md
|
|
23
|
+
* @patram
|
|
24
|
+
* @see {@link ./parse-claims.js}
|
|
25
|
+
* @see {@link ./parse-markdown-directives.js}
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const YAML_EXTENSIONS = new Set(YAML_SOURCE_FILE_EXTENSIONS);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse standalone YAML source into neutral directive claims.
|
|
32
|
+
*
|
|
33
|
+
* @param {ParseClaimsInput} parse_input
|
|
34
|
+
* @param {{ multi_value_directive_names?: ReadonlySet<string> }} [parse_options]
|
|
35
|
+
* @returns {ParseSourceFileResult}
|
|
36
|
+
*/
|
|
37
|
+
export function parseYamlClaims(parse_input, parse_options) {
|
|
38
|
+
if (!YAML_EXTENSIONS.has(getFileExtension(parse_input.path))) {
|
|
39
|
+
return {
|
|
40
|
+
claims: [],
|
|
41
|
+
diagnostics: [],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const parse_result = parseYamlDirectiveFields({
|
|
46
|
+
file_path: parse_input.path,
|
|
47
|
+
parser: 'yaml',
|
|
48
|
+
source_text: parse_input.source,
|
|
49
|
+
start_line: 1,
|
|
50
|
+
multi_value_directive_names: parse_options?.multi_value_directive_names,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
claims: parse_result.directive_fields.map((directive_fields, claim_index) =>
|
|
55
|
+
createClaim(
|
|
56
|
+
parse_input.path,
|
|
57
|
+
claim_index + 1,
|
|
58
|
+
'directive',
|
|
59
|
+
directive_fields,
|
|
60
|
+
),
|
|
61
|
+
),
|
|
62
|
+
diagnostics: parse_result.diagnostics,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse YAML metadata into neutral directive fields.
|
|
68
|
+
*
|
|
69
|
+
* @param {{
|
|
70
|
+
* file_path: string,
|
|
71
|
+
* parser: 'markdown' | 'yaml',
|
|
72
|
+
* source_text: string,
|
|
73
|
+
* start_line: number,
|
|
74
|
+
* markdown_style?: 'front_matter',
|
|
75
|
+
* multi_value_directive_names?: ReadonlySet<string>,
|
|
76
|
+
* }} parse_input
|
|
77
|
+
* @returns {{ diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] }}
|
|
78
|
+
*/
|
|
79
|
+
export function parseYamlDirectiveFields(parse_input) {
|
|
80
|
+
const line_counter = new LineCounter();
|
|
81
|
+
const yaml_documents = parseAllDocuments(parse_input.source_text, {
|
|
82
|
+
lineCounter: line_counter,
|
|
83
|
+
prettyErrors: false,
|
|
84
|
+
});
|
|
85
|
+
const parse_result = resolveYamlParseResult(
|
|
86
|
+
parse_input,
|
|
87
|
+
yaml_documents,
|
|
88
|
+
line_counter,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!parse_result.success) {
|
|
92
|
+
return parse_result.value;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
diagnostics: [],
|
|
97
|
+
directive_fields: collectDirectiveFields(
|
|
98
|
+
parse_input,
|
|
99
|
+
parse_result.value,
|
|
100
|
+
line_counter,
|
|
101
|
+
),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {{
|
|
107
|
+
* file_path: string,
|
|
108
|
+
* start_line: number,
|
|
109
|
+
* }} parse_input
|
|
110
|
+
* @param {any[]} yaml_documents
|
|
111
|
+
* @param {LineCounter} line_counter
|
|
112
|
+
* @returns {{
|
|
113
|
+
success: true,
|
|
114
|
+
value: yaml.YAMLMap<unknown, unknown>
|
|
115
|
+
} | {
|
|
116
|
+
success: false,
|
|
117
|
+
value: {diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[]}
|
|
118
|
+
}}
|
|
119
|
+
* success: true,
|
|
120
|
+
* value: import('yaml').YAMLMap<unknown, unknown>,
|
|
121
|
+
* } | {
|
|
122
|
+
* success: false,
|
|
123
|
+
* value: { diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] },
|
|
124
|
+
* }}
|
|
125
|
+
*/
|
|
126
|
+
function resolveYamlParseResult(parse_input, yaml_documents, line_counter) {
|
|
127
|
+
if (yaml_documents.length !== 1) {
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
value: createDiagnosticResult([
|
|
131
|
+
createYamlDiagnostic(
|
|
132
|
+
parse_input.file_path,
|
|
133
|
+
line_counter,
|
|
134
|
+
yaml_documents[1]?.range?.[0] ?? 0,
|
|
135
|
+
parse_input.start_line,
|
|
136
|
+
'yaml.multiple_documents',
|
|
137
|
+
'Patram YAML sources must contain exactly one document.',
|
|
138
|
+
),
|
|
139
|
+
]),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const yaml_document = yaml_documents[0];
|
|
144
|
+
|
|
145
|
+
if (yaml_document.errors.length > 0) {
|
|
146
|
+
return {
|
|
147
|
+
success: false,
|
|
148
|
+
value: createDiagnosticResult(
|
|
149
|
+
yaml_document.errors.map(
|
|
150
|
+
/** @param {{ message: string, pos: [number, number] }} yaml_error */
|
|
151
|
+
(yaml_error) =>
|
|
152
|
+
createYamlDiagnostic(
|
|
153
|
+
parse_input.file_path,
|
|
154
|
+
line_counter,
|
|
155
|
+
yaml_error.pos[0] ?? 0,
|
|
156
|
+
parse_input.start_line,
|
|
157
|
+
'yaml.invalid_syntax',
|
|
158
|
+
yaml_error.message,
|
|
159
|
+
),
|
|
160
|
+
),
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!isMap(yaml_document.contents)) {
|
|
166
|
+
return {
|
|
167
|
+
success: false,
|
|
168
|
+
value: createDiagnosticResult([
|
|
169
|
+
createYamlDiagnostic(
|
|
170
|
+
parse_input.file_path,
|
|
171
|
+
line_counter,
|
|
172
|
+
resolveNodeRangeStart(yaml_document.contents),
|
|
173
|
+
parse_input.start_line,
|
|
174
|
+
'yaml.invalid_root',
|
|
175
|
+
'Patram YAML metadata must use one top-level mapping.',
|
|
176
|
+
),
|
|
177
|
+
]),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
success: true,
|
|
183
|
+
value: yaml_document.contents,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param {{
|
|
189
|
+
* file_path: string,
|
|
190
|
+
* parser: 'markdown' | 'yaml',
|
|
191
|
+
* start_line: number,
|
|
192
|
+
* markdown_style?: 'front_matter',
|
|
193
|
+
* multi_value_directive_names?: ReadonlySet<string>,
|
|
194
|
+
* }} parse_input
|
|
195
|
+
* @param {import('yaml').YAMLMap<unknown, unknown>} yaml_map
|
|
196
|
+
* @param {LineCounter} line_counter
|
|
197
|
+
* @returns {PatramClaimFields[]}
|
|
198
|
+
*/
|
|
199
|
+
function collectDirectiveFields(parse_input, yaml_map, line_counter) {
|
|
200
|
+
/** @type {PatramClaimFields[]} */
|
|
201
|
+
const directive_fields = [];
|
|
202
|
+
|
|
203
|
+
for (const pair of yaml_map.items) {
|
|
204
|
+
const pair_fields = createPairDirectiveFields(
|
|
205
|
+
parse_input,
|
|
206
|
+
pair,
|
|
207
|
+
line_counter,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
directive_fields.push(...pair_fields);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return directive_fields;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @param {{
|
|
218
|
+
* file_path: string,
|
|
219
|
+
* parser: 'markdown' | 'yaml',
|
|
220
|
+
* start_line: number,
|
|
221
|
+
* markdown_style?: 'front_matter',
|
|
222
|
+
* multi_value_directive_names?: ReadonlySet<string>,
|
|
223
|
+
* }} parse_input
|
|
224
|
+
* @param {any} yaml_pair
|
|
225
|
+
* @param {LineCounter} line_counter
|
|
226
|
+
* @returns {PatramClaimFields[]}
|
|
227
|
+
*/
|
|
228
|
+
function createPairDirectiveFields(parse_input, yaml_pair, line_counter) {
|
|
229
|
+
const directive_name = resolveDirectiveName(yaml_pair.key);
|
|
230
|
+
|
|
231
|
+
if (!directive_name || yaml_pair.value === null) {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (isScalar(yaml_pair.value)) {
|
|
236
|
+
return createScalarDirectiveFields(
|
|
237
|
+
parse_input,
|
|
238
|
+
directive_name,
|
|
239
|
+
yaml_pair.key,
|
|
240
|
+
yaml_pair.value.value,
|
|
241
|
+
line_counter,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!shouldCollectSequence(parse_input, directive_name, yaml_pair.value)) {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const sequence_items =
|
|
250
|
+
/** @type {Array<{ range?: [number, number, number], value: unknown }>} */ (
|
|
251
|
+
yaml_pair.value.items
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
return sequence_items.flatMap((sequence_item) =>
|
|
255
|
+
createScalarDirectiveFields(
|
|
256
|
+
parse_input,
|
|
257
|
+
directive_name,
|
|
258
|
+
sequence_item,
|
|
259
|
+
sequence_item.value,
|
|
260
|
+
line_counter,
|
|
261
|
+
),
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @param {{
|
|
267
|
+
* file_path: string,
|
|
268
|
+
* parser: 'markdown' | 'yaml',
|
|
269
|
+
* start_line: number,
|
|
270
|
+
* markdown_style?: 'front_matter',
|
|
271
|
+
* }} parse_input
|
|
272
|
+
* @param {string} directive_name
|
|
273
|
+
* @param {{ range?: [number, number, number] }} yaml_node
|
|
274
|
+
* @param {unknown} scalar_value
|
|
275
|
+
* @param {LineCounter} line_counter
|
|
276
|
+
* @returns {PatramClaimFields[]}
|
|
277
|
+
*/
|
|
278
|
+
function createScalarDirectiveFields(
|
|
279
|
+
parse_input,
|
|
280
|
+
directive_name,
|
|
281
|
+
yaml_node,
|
|
282
|
+
scalar_value,
|
|
283
|
+
line_counter,
|
|
284
|
+
) {
|
|
285
|
+
const normalized_value = normalizeScalarValue(scalar_value);
|
|
286
|
+
|
|
287
|
+
if (normalized_value === null) {
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return [
|
|
292
|
+
{
|
|
293
|
+
...createDirectiveBaseFields(parse_input, yaml_node, line_counter),
|
|
294
|
+
name: directive_name,
|
|
295
|
+
value: normalized_value,
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* @param {{
|
|
302
|
+
* multi_value_directive_names?: ReadonlySet<string>,
|
|
303
|
+
* }} parse_input
|
|
304
|
+
* @param {string} directive_name
|
|
305
|
+
* @param {unknown} yaml_value
|
|
306
|
+
* @returns {boolean}
|
|
307
|
+
*/
|
|
308
|
+
function shouldCollectSequence(parse_input, directive_name, yaml_value) {
|
|
309
|
+
return (
|
|
310
|
+
isSeq(yaml_value) &&
|
|
311
|
+
parse_input.multi_value_directive_names?.has(directive_name) === true &&
|
|
312
|
+
yaml_value.items.every(isNonNullScalarNode)
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @param {{
|
|
318
|
+
* file_path: string,
|
|
319
|
+
* parser: 'markdown' | 'yaml',
|
|
320
|
+
* start_line: number,
|
|
321
|
+
* markdown_style?: 'front_matter',
|
|
322
|
+
* }} parse_input
|
|
323
|
+
* @param {{ range?: [number, number, number] }} yaml_node
|
|
324
|
+
* @param {LineCounter} line_counter
|
|
325
|
+
* @returns {PatramClaimFields}
|
|
326
|
+
*/
|
|
327
|
+
function createDirectiveBaseFields(parse_input, yaml_node, line_counter) {
|
|
328
|
+
/** @type {PatramClaimFields} */
|
|
329
|
+
const directive_fields = {
|
|
330
|
+
name: '',
|
|
331
|
+
origin: createOrigin(
|
|
332
|
+
parse_input.file_path,
|
|
333
|
+
yaml_node.range?.[0] ?? 0,
|
|
334
|
+
parse_input.start_line,
|
|
335
|
+
line_counter,
|
|
336
|
+
),
|
|
337
|
+
parser: parse_input.parser,
|
|
338
|
+
value: '',
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
if (parse_input.markdown_style !== undefined) {
|
|
342
|
+
directive_fields.markdown_style = parse_input.markdown_style;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return directive_fields;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @param {unknown} yaml_key
|
|
350
|
+
* @returns {string | null}
|
|
351
|
+
*/
|
|
352
|
+
function resolveDirectiveName(yaml_key) {
|
|
353
|
+
if (!isScalar(yaml_key) || typeof yaml_key.value !== 'string') {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return normalizeDirectiveName(yaml_key.value);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @param {unknown} scalar_value
|
|
362
|
+
* @returns {string | null}
|
|
363
|
+
*/
|
|
364
|
+
function normalizeScalarValue(scalar_value) {
|
|
365
|
+
if (scalar_value === null) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (typeof scalar_value === 'string') {
|
|
370
|
+
return scalar_value;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (typeof scalar_value === 'boolean' || typeof scalar_value === 'number') {
|
|
374
|
+
return String(scalar_value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* @param {unknown} yaml_node
|
|
382
|
+
* @returns {boolean}
|
|
383
|
+
*/
|
|
384
|
+
function isNonNullScalarNode(yaml_node) {
|
|
385
|
+
return isScalar(yaml_node) && normalizeScalarValue(yaml_node.value) !== null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @param {string} file_path
|
|
390
|
+
* @param {number} offset
|
|
391
|
+
* @param {number} start_line
|
|
392
|
+
* @param {LineCounter} line_counter
|
|
393
|
+
* @returns {{ column: number, line: number, path: string }}
|
|
394
|
+
*/
|
|
395
|
+
function createOrigin(file_path, offset, start_line, line_counter) {
|
|
396
|
+
const location = line_counter.linePos(offset);
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
column: location?.col ?? 1,
|
|
400
|
+
line: (location?.line ?? 1) + start_line - 1,
|
|
401
|
+
path: file_path,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* @param {string} file_path
|
|
407
|
+
* @param {LineCounter} line_counter
|
|
408
|
+
* @param {number} offset
|
|
409
|
+
* @param {number} start_line
|
|
410
|
+
* @param {string} code
|
|
411
|
+
* @param {string} message
|
|
412
|
+
* @returns {PatramDiagnostic}
|
|
413
|
+
*/
|
|
414
|
+
function createYamlDiagnostic(
|
|
415
|
+
file_path,
|
|
416
|
+
line_counter,
|
|
417
|
+
offset,
|
|
418
|
+
start_line,
|
|
419
|
+
code,
|
|
420
|
+
message,
|
|
421
|
+
) {
|
|
422
|
+
const origin = createOrigin(file_path, offset, start_line, line_counter);
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
code,
|
|
426
|
+
column: origin.column,
|
|
427
|
+
level: 'error',
|
|
428
|
+
line: origin.line,
|
|
429
|
+
message,
|
|
430
|
+
path: file_path,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* @param {PatramDiagnostic[]} diagnostics
|
|
436
|
+
* @returns {{ diagnostics: PatramDiagnostic[], directive_fields: PatramClaimFields[] }}
|
|
437
|
+
*/
|
|
438
|
+
function createDiagnosticResult(diagnostics) {
|
|
439
|
+
return {
|
|
440
|
+
diagnostics,
|
|
441
|
+
directive_fields: [],
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* @param {unknown} yaml_node
|
|
447
|
+
* @returns {number}
|
|
448
|
+
*/
|
|
449
|
+
function resolveNodeRangeStart(yaml_node) {
|
|
450
|
+
if (
|
|
451
|
+
yaml_node &&
|
|
452
|
+
typeof yaml_node === 'object' &&
|
|
453
|
+
'range' in yaml_node &&
|
|
454
|
+
Array.isArray(yaml_node.range) &&
|
|
455
|
+
typeof yaml_node.range[0] === 'number'
|
|
456
|
+
) {
|
|
457
|
+
return yaml_node.range[0];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* @param {string} directive_label
|
|
465
|
+
* @returns {string}
|
|
466
|
+
*/
|
|
467
|
+
function normalizeDirectiveName(directive_label) {
|
|
468
|
+
return directive_label
|
|
469
|
+
.trim()
|
|
470
|
+
.toLowerCase()
|
|
471
|
+
.replaceAll(/[\s-]+/dgu, '_');
|
|
472
|
+
}
|
package/lib/patram.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const MARKDOWN_SOURCE_FILE_EXTENSIONS = ['.markdown', '.md'];
|
|
2
2
|
|
|
3
|
+
export const YAML_SOURCE_FILE_EXTENSIONS = ['.yaml', '.yml'];
|
|
4
|
+
|
|
3
5
|
export const JSDOC_SOURCE_FILE_EXTENSIONS = [
|
|
4
6
|
'.cjs',
|
|
5
7
|
'.cts',
|
|
@@ -14,6 +16,7 @@ export const JSDOC_SOURCE_FILE_EXTENSIONS = [
|
|
|
14
16
|
export const SUPPORTED_SOURCE_FILE_EXTENSIONS = [
|
|
15
17
|
...JSDOC_SOURCE_FILE_EXTENSIONS,
|
|
16
18
|
...MARKDOWN_SOURCE_FILE_EXTENSIONS,
|
|
19
|
+
...YAML_SOURCE_FILE_EXTENSIONS,
|
|
17
20
|
];
|
|
18
21
|
|
|
19
22
|
export const DEFAULT_INCLUDE_PATTERNS =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/patram.js",
|
|
6
6
|
"exports": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"shiki": "^4.0.2",
|
|
61
61
|
"string-width": "^8.2.0",
|
|
62
62
|
"wrap-ansi": "^10.0.0",
|
|
63
|
+
"yaml": "^2.8.3",
|
|
63
64
|
"zod": "^4.3.6"
|
|
64
65
|
},
|
|
65
66
|
"devDependencies": {
|