busy-cli 0.1.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/README.md +129 -0
- package/dist/builders/context.d.ts +50 -0
- package/dist/builders/context.d.ts.map +1 -0
- package/dist/builders/context.js +190 -0
- package/dist/cache/index.d.ts +100 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +270 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +463 -0
- package/dist/commands/package.d.ts +96 -0
- package/dist/commands/package.d.ts.map +1 -0
- package/dist/commands/package.js +285 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/loader.d.ts +6 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +361 -0
- package/dist/merge.d.ts +16 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +102 -0
- package/dist/package/manifest.d.ts +59 -0
- package/dist/package/manifest.d.ts.map +1 -0
- package/dist/package/manifest.js +265 -0
- package/dist/parser.d.ts +28 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +220 -0
- package/dist/parsers/frontmatter.d.ts +14 -0
- package/dist/parsers/frontmatter.d.ts.map +1 -0
- package/dist/parsers/frontmatter.js +110 -0
- package/dist/parsers/imports.d.ts +48 -0
- package/dist/parsers/imports.d.ts.map +1 -0
- package/dist/parsers/imports.js +147 -0
- package/dist/parsers/links.d.ts +12 -0
- package/dist/parsers/links.d.ts.map +1 -0
- package/dist/parsers/links.js +79 -0
- package/dist/parsers/localdefs.d.ts +6 -0
- package/dist/parsers/localdefs.d.ts.map +1 -0
- package/dist/parsers/localdefs.js +132 -0
- package/dist/parsers/operations.d.ts +32 -0
- package/dist/parsers/operations.d.ts.map +1 -0
- package/dist/parsers/operations.js +313 -0
- package/dist/parsers/sections.d.ts +15 -0
- package/dist/parsers/sections.d.ts.map +1 -0
- package/dist/parsers/sections.js +173 -0
- package/dist/parsers/tools.d.ts +30 -0
- package/dist/parsers/tools.d.ts.map +1 -0
- package/dist/parsers/tools.js +178 -0
- package/dist/parsers/triggers.d.ts +35 -0
- package/dist/parsers/triggers.d.ts.map +1 -0
- package/dist/parsers/triggers.js +219 -0
- package/dist/providers/base.d.ts +60 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +34 -0
- package/dist/providers/github.d.ts +18 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +109 -0
- package/dist/providers/gitlab.d.ts +18 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +101 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +17 -0
- package/dist/providers/local.d.ts +31 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +116 -0
- package/dist/providers/url.d.ts +16 -0
- package/dist/providers/url.d.ts.map +1 -0
- package/dist/providers/url.js +45 -0
- package/dist/registry/index.d.ts +99 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +320 -0
- package/dist/types/schema.d.ts +3259 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +258 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +23 -0
- package/dist/utils/slugify.d.ts +14 -0
- package/dist/utils/slugify.d.ts.map +1 -0
- package/dist/utils/slugify.js +28 -0
- package/package.json +61 -0
- package/src/__tests__/cache.test.ts +393 -0
- package/src/__tests__/cli-package.test.ts +667 -0
- package/src/__tests__/fixtures/automated-workflow.busy.md +84 -0
- package/src/__tests__/fixtures/concept.busy.md +30 -0
- package/src/__tests__/fixtures/document.busy.md +44 -0
- package/src/__tests__/fixtures/simple-operation.busy.md +45 -0
- package/src/__tests__/fixtures/tool-document.busy.md +71 -0
- package/src/__tests__/fixtures/tool.busy.md +54 -0
- package/src/__tests__/imports.test.ts +244 -0
- package/src/__tests__/integration.test.ts +432 -0
- package/src/__tests__/operations.test.ts +408 -0
- package/src/__tests__/package-manifest.test.ts +455 -0
- package/src/__tests__/providers.test.ts +672 -0
- package/src/__tests__/registry.test.ts +402 -0
- package/src/__tests__/schema.test.ts +467 -0
- package/src/__tests__/tools.test.ts +376 -0
- package/src/__tests__/triggers.test.ts +312 -0
- package/src/builders/context.ts +294 -0
- package/src/cache/index.ts +312 -0
- package/src/cli/index.ts +514 -0
- package/src/commands/package.ts +392 -0
- package/src/index.ts +46 -0
- package/src/loader.ts +474 -0
- package/src/merge.ts +126 -0
- package/src/package/manifest.ts +349 -0
- package/src/parser.ts +278 -0
- package/src/parsers/frontmatter.ts +135 -0
- package/src/parsers/imports.ts +196 -0
- package/src/parsers/links.ts +108 -0
- package/src/parsers/localdefs.ts +166 -0
- package/src/parsers/operations.ts +404 -0
- package/src/parsers/sections.ts +230 -0
- package/src/parsers/tools.ts +215 -0
- package/src/parsers/triggers.ts +252 -0
- package/src/providers/base.ts +77 -0
- package/src/providers/github.ts +129 -0
- package/src/providers/gitlab.ts +121 -0
- package/src/providers/index.ts +25 -0
- package/src/providers/local.ts +129 -0
- package/src/providers/url.ts +56 -0
- package/src/registry/index.ts +408 -0
- package/src/types/schema.ts +369 -0
- package/src/utils/logger.ts +25 -0
- package/src/utils/slugify.ts +31 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operations Parsing Tests - Match busy-python Operation model
|
|
3
|
+
*
|
|
4
|
+
* Operations in busy-python have:
|
|
5
|
+
* - name: string
|
|
6
|
+
* - inputs: list[str]
|
|
7
|
+
* - outputs: list[str]
|
|
8
|
+
* - steps: list[Step] where Step has stepNumber, instruction, operationReferences
|
|
9
|
+
* - checklist: Optional[Checklist] with items list
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { parseOperations, parseSteps, parseChecklist } from '../parsers/operations';
|
|
14
|
+
import type { Operation, Step } from '../types/schema';
|
|
15
|
+
|
|
16
|
+
describe('parseSteps', () => {
|
|
17
|
+
it('should parse numbered steps with step numbers', () => {
|
|
18
|
+
const content = `
|
|
19
|
+
### [Steps]
|
|
20
|
+
1. Parse the document frontmatter
|
|
21
|
+
2. Resolve all imports
|
|
22
|
+
3. Execute the setup section
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const steps = parseSteps(content);
|
|
26
|
+
expect(steps).toHaveLength(3);
|
|
27
|
+
expect(steps[0]).toEqual({
|
|
28
|
+
stepNumber: 1,
|
|
29
|
+
instruction: 'Parse the document frontmatter',
|
|
30
|
+
operationReferences: undefined, // undefined when no references (matches busy-python Optional)
|
|
31
|
+
});
|
|
32
|
+
expect(steps[1].stepNumber).toBe(2);
|
|
33
|
+
expect(steps[2].stepNumber).toBe(3);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should extract operation references from step text', () => {
|
|
37
|
+
const content = `
|
|
38
|
+
### [Steps]
|
|
39
|
+
1. Run [ValidateInput] to check data
|
|
40
|
+
2. Execute [ProcessData] and then [SaveResults]
|
|
41
|
+
3. Call [SendNotification] on completion
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const steps = parseSteps(content);
|
|
45
|
+
expect(steps[0].operationReferences).toEqual(['ValidateInput']);
|
|
46
|
+
expect(steps[1].operationReferences).toEqual(['ProcessData', 'SaveResults']);
|
|
47
|
+
expect(steps[2].operationReferences).toEqual(['SendNotification']);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle multi-line step instructions', () => {
|
|
51
|
+
const content = `
|
|
52
|
+
### [Steps]
|
|
53
|
+
1. First step that continues
|
|
54
|
+
on the next line with more detail
|
|
55
|
+
2. Second step is single line
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const steps = parseSteps(content);
|
|
59
|
+
expect(steps).toHaveLength(2);
|
|
60
|
+
expect(steps[0].instruction).toContain('continues');
|
|
61
|
+
expect(steps[0].instruction).toContain('more detail');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle steps without Steps heading (just numbered list)', () => {
|
|
65
|
+
const content = `
|
|
66
|
+
## OperationName
|
|
67
|
+
|
|
68
|
+
1. Do first thing
|
|
69
|
+
2. Do second thing
|
|
70
|
+
3. Do third thing
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const steps = parseSteps(content);
|
|
74
|
+
expect(steps).toHaveLength(3);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return empty array for content with no steps', () => {
|
|
78
|
+
const content = `
|
|
79
|
+
## OperationName
|
|
80
|
+
|
|
81
|
+
Just some description without steps.
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
const steps = parseSteps(content);
|
|
85
|
+
expect(steps).toHaveLength(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should not include checklist items as steps', () => {
|
|
89
|
+
const content = `
|
|
90
|
+
### [Steps]
|
|
91
|
+
1. Execute task
|
|
92
|
+
|
|
93
|
+
### [Checklist]
|
|
94
|
+
- Task completed
|
|
95
|
+
- Output verified
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
const steps = parseSteps(content);
|
|
99
|
+
expect(steps).toHaveLength(1);
|
|
100
|
+
expect(steps[0].instruction).toBe('Execute task');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should handle operation references with various formats', () => {
|
|
104
|
+
const content = `
|
|
105
|
+
### [Steps]
|
|
106
|
+
1. Run [Simple]
|
|
107
|
+
2. Execute [Multi Word Operation]
|
|
108
|
+
3. Call [run-with-dashes]
|
|
109
|
+
4. Use [CamelCase123]
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const steps = parseSteps(content);
|
|
113
|
+
expect(steps[0].operationReferences).toEqual(['Simple']);
|
|
114
|
+
expect(steps[1].operationReferences).toEqual(['Multi Word Operation']);
|
|
115
|
+
expect(steps[2].operationReferences).toEqual(['run-with-dashes']);
|
|
116
|
+
expect(steps[3].operationReferences).toEqual(['CamelCase123']);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('parseChecklist', () => {
|
|
121
|
+
it('should parse checklist items from bullet list', () => {
|
|
122
|
+
const content = `
|
|
123
|
+
### [Checklist]
|
|
124
|
+
- Input validated
|
|
125
|
+
- Processing complete
|
|
126
|
+
- Output written
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
const checklist = parseChecklist(content);
|
|
130
|
+
expect(checklist).not.toBeNull();
|
|
131
|
+
expect(checklist?.items).toHaveLength(3);
|
|
132
|
+
expect(checklist?.items).toEqual([
|
|
133
|
+
'Input validated',
|
|
134
|
+
'Processing complete',
|
|
135
|
+
'Output written',
|
|
136
|
+
]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should handle checklist with asterisk bullets', () => {
|
|
140
|
+
const content = `
|
|
141
|
+
### [Checklist]
|
|
142
|
+
* First item
|
|
143
|
+
* Second item
|
|
144
|
+
`;
|
|
145
|
+
|
|
146
|
+
const checklist = parseChecklist(content);
|
|
147
|
+
expect(checklist?.items).toHaveLength(2);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should return null for content without checklist', () => {
|
|
151
|
+
const content = `
|
|
152
|
+
### [Steps]
|
|
153
|
+
1. Do something
|
|
154
|
+
`;
|
|
155
|
+
|
|
156
|
+
const checklist = parseChecklist(content);
|
|
157
|
+
expect(checklist).toBeNull();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should handle checklist without bracket notation', () => {
|
|
161
|
+
const content = `
|
|
162
|
+
### Checklist
|
|
163
|
+
- Item one
|
|
164
|
+
- Item two
|
|
165
|
+
`;
|
|
166
|
+
|
|
167
|
+
const checklist = parseChecklist(content);
|
|
168
|
+
expect(checklist?.items).toHaveLength(2);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should handle multi-line checklist items', () => {
|
|
172
|
+
const content = `
|
|
173
|
+
### [Checklist]
|
|
174
|
+
- First item that continues
|
|
175
|
+
on the next line
|
|
176
|
+
- Second item
|
|
177
|
+
`;
|
|
178
|
+
|
|
179
|
+
const checklist = parseChecklist(content);
|
|
180
|
+
expect(checklist?.items).toHaveLength(2);
|
|
181
|
+
expect(checklist?.items[0]).toContain('continues');
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('parseOperations', () => {
|
|
186
|
+
it('should parse operation with all sections', () => {
|
|
187
|
+
const content = `
|
|
188
|
+
# [Operations]
|
|
189
|
+
|
|
190
|
+
## EvaluateDocument
|
|
191
|
+
|
|
192
|
+
Load and evaluate a BUSY document.
|
|
193
|
+
|
|
194
|
+
### [Inputs]
|
|
195
|
+
- document_path: Path to the document
|
|
196
|
+
- context: Execution context
|
|
197
|
+
|
|
198
|
+
### [Outputs]
|
|
199
|
+
- parsed_document: The parsed document object
|
|
200
|
+
- errors: List of any errors
|
|
201
|
+
|
|
202
|
+
### [Steps]
|
|
203
|
+
1. Parse frontmatter
|
|
204
|
+
2. Resolve imports
|
|
205
|
+
3. Execute setup
|
|
206
|
+
|
|
207
|
+
### [Checklist]
|
|
208
|
+
- Frontmatter valid
|
|
209
|
+
- Imports resolved
|
|
210
|
+
- Setup complete
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
const operations = parseOperations(content);
|
|
214
|
+
expect(operations).toHaveLength(1);
|
|
215
|
+
|
|
216
|
+
const op = operations[0];
|
|
217
|
+
expect(op.name).toBe('EvaluateDocument');
|
|
218
|
+
expect(op.inputs).toHaveLength(2);
|
|
219
|
+
expect(op.inputs[0]).toBe('document_path: Path to the document');
|
|
220
|
+
expect(op.outputs).toHaveLength(2);
|
|
221
|
+
expect(op.steps).toHaveLength(3);
|
|
222
|
+
expect(op.steps[0].stepNumber).toBe(1);
|
|
223
|
+
expect(op.checklist?.items).toHaveLength(3);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should parse multiple operations', () => {
|
|
227
|
+
const content = `
|
|
228
|
+
# [Operations]
|
|
229
|
+
|
|
230
|
+
## FirstOperation
|
|
231
|
+
|
|
232
|
+
### [Steps]
|
|
233
|
+
1. Do first thing
|
|
234
|
+
|
|
235
|
+
## SecondOperation
|
|
236
|
+
|
|
237
|
+
### [Steps]
|
|
238
|
+
1. Do second thing
|
|
239
|
+
|
|
240
|
+
## ThirdOperation
|
|
241
|
+
|
|
242
|
+
### [Steps]
|
|
243
|
+
1. Do third thing
|
|
244
|
+
`;
|
|
245
|
+
|
|
246
|
+
const operations = parseOperations(content);
|
|
247
|
+
expect(operations).toHaveLength(3);
|
|
248
|
+
expect(operations.map((o) => o.name)).toEqual([
|
|
249
|
+
'FirstOperation',
|
|
250
|
+
'SecondOperation',
|
|
251
|
+
'ThirdOperation',
|
|
252
|
+
]);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should handle operation without inputs/outputs', () => {
|
|
256
|
+
const content = `
|
|
257
|
+
# [Operations]
|
|
258
|
+
|
|
259
|
+
## SimpleOp
|
|
260
|
+
|
|
261
|
+
### [Steps]
|
|
262
|
+
1. Just do it
|
|
263
|
+
`;
|
|
264
|
+
|
|
265
|
+
const operations = parseOperations(content);
|
|
266
|
+
expect(operations).toHaveLength(1);
|
|
267
|
+
expect(operations[0].inputs).toEqual([]);
|
|
268
|
+
expect(operations[0].outputs).toEqual([]);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should handle operation without checklist', () => {
|
|
272
|
+
const content = `
|
|
273
|
+
# [Operations]
|
|
274
|
+
|
|
275
|
+
## NoChecklist
|
|
276
|
+
|
|
277
|
+
### [Steps]
|
|
278
|
+
1. Do something
|
|
279
|
+
2. Do something else
|
|
280
|
+
`;
|
|
281
|
+
|
|
282
|
+
const operations = parseOperations(content);
|
|
283
|
+
expect(operations).toHaveLength(1);
|
|
284
|
+
expect(operations[0].checklist).toBeUndefined();
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should parse inputs and outputs as string arrays', () => {
|
|
288
|
+
const content = `
|
|
289
|
+
# [Operations]
|
|
290
|
+
|
|
291
|
+
## ProcessData
|
|
292
|
+
|
|
293
|
+
### [Inputs]
|
|
294
|
+
- data: The input data to process
|
|
295
|
+
- options: Processing options (optional)
|
|
296
|
+
|
|
297
|
+
### [Outputs]
|
|
298
|
+
- result: Processed result
|
|
299
|
+
- metadata: Processing metadata
|
|
300
|
+
`;
|
|
301
|
+
|
|
302
|
+
const operations = parseOperations(content);
|
|
303
|
+
const op = operations[0];
|
|
304
|
+
|
|
305
|
+
expect(op.inputs).toEqual([
|
|
306
|
+
'data: The input data to process',
|
|
307
|
+
'options: Processing options (optional)',
|
|
308
|
+
]);
|
|
309
|
+
expect(op.outputs).toEqual([
|
|
310
|
+
'result: Processed result',
|
|
311
|
+
'metadata: Processing metadata',
|
|
312
|
+
]);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should handle Operations section without bracket notation', () => {
|
|
316
|
+
const content = `
|
|
317
|
+
# Operations
|
|
318
|
+
|
|
319
|
+
## TestOp
|
|
320
|
+
|
|
321
|
+
### Steps
|
|
322
|
+
1. Test step
|
|
323
|
+
`;
|
|
324
|
+
|
|
325
|
+
const operations = parseOperations(content);
|
|
326
|
+
expect(operations).toHaveLength(1);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('should return empty array for document without Operations section', () => {
|
|
330
|
+
const content = `
|
|
331
|
+
# [Setup]
|
|
332
|
+
|
|
333
|
+
Just setup content.
|
|
334
|
+
|
|
335
|
+
# [Local Definitions]
|
|
336
|
+
|
|
337
|
+
## SomeDef
|
|
338
|
+
|
|
339
|
+
Definition content.
|
|
340
|
+
`;
|
|
341
|
+
|
|
342
|
+
const operations = parseOperations(content);
|
|
343
|
+
expect(operations).toHaveLength(0);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should extract operation references from all steps', () => {
|
|
347
|
+
const content = `
|
|
348
|
+
# [Operations]
|
|
349
|
+
|
|
350
|
+
## Orchestrator
|
|
351
|
+
|
|
352
|
+
### [Steps]
|
|
353
|
+
1. First run [ValidateInput]
|
|
354
|
+
2. Then execute [ProcessData] with [Transform]
|
|
355
|
+
3. Finally call [SaveOutput]
|
|
356
|
+
`;
|
|
357
|
+
|
|
358
|
+
const operations = parseOperations(content);
|
|
359
|
+
const op = operations[0];
|
|
360
|
+
|
|
361
|
+
expect(op.steps[0].operationReferences).toEqual(['ValidateInput']);
|
|
362
|
+
expect(op.steps[1].operationReferences).toEqual(['ProcessData', 'Transform']);
|
|
363
|
+
expect(op.steps[2].operationReferences).toEqual(['SaveOutput']);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should handle operation names with spaces (using bracket notation)', () => {
|
|
367
|
+
const content = `
|
|
368
|
+
# [Operations]
|
|
369
|
+
|
|
370
|
+
## [Run Full Analysis][Operation]
|
|
371
|
+
|
|
372
|
+
### [Steps]
|
|
373
|
+
1. Analyze data
|
|
374
|
+
`;
|
|
375
|
+
|
|
376
|
+
const operations = parseOperations(content);
|
|
377
|
+
expect(operations).toHaveLength(1);
|
|
378
|
+
// Should extract "Run Full Analysis" as the name
|
|
379
|
+
expect(operations[0].name).toBe('Run Full Analysis');
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe('Operation Step Number Validation', () => {
|
|
384
|
+
it('should ensure step numbers are sequential starting from 1', () => {
|
|
385
|
+
const content = `
|
|
386
|
+
### [Steps]
|
|
387
|
+
1. First
|
|
388
|
+
2. Second
|
|
389
|
+
3. Third
|
|
390
|
+
`;
|
|
391
|
+
|
|
392
|
+
const steps = parseSteps(content);
|
|
393
|
+
expect(steps.map((s) => s.stepNumber)).toEqual([1, 2, 3]);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('should handle non-sequential step numbers (preserve original)', () => {
|
|
397
|
+
const content = `
|
|
398
|
+
### [Steps]
|
|
399
|
+
1. First
|
|
400
|
+
3. Third (skipped 2)
|
|
401
|
+
5. Fifth
|
|
402
|
+
`;
|
|
403
|
+
|
|
404
|
+
const steps = parseSteps(content);
|
|
405
|
+
// Should preserve the actual numbers from the document
|
|
406
|
+
expect(steps.map((s) => s.stepNumber)).toEqual([1, 3, 5]);
|
|
407
|
+
});
|
|
408
|
+
});
|