Skip to content

Commit 3d55fc7

Browse files
committed
Multiple functions to manipulate with PipelineString
1 parent 3f00f82 commit 3d55fc7

File tree

10 files changed

+303
-107
lines changed

10 files changed

+303
-107
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,12 +679,13 @@ Compile via remote server
679679
- Add `DEFAULT_TASK_TITLE`
680680
- Enforce LF (\n) lines
681681

682-
### `0.83.0` _(2025-01-20)_
682+
### `0.83.0` and `0.84.0` _(2025-01-20)_
683683

684684
`@promptbook/editable`
685685

686686
- Export parsing internals to `@promptbook/editable`
687687
- Rename `sourceContent` -> `knowledgeSourceContent`
688+
- Multiple functions to manipulate with `PipelineString`
688689

689690
## In pre-release
690691

src/_packages/editable.index.ts

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
22
// `@promptbook/editable`
33

4-
import { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION } from '../version';
54
import { getParserForCommand } from '../commands/_common/getParserForCommand';
65
import { parseCommand } from '../commands/_common/parseCommand';
7-
import type { CommandParser } from '../commands/_common/types/CommandParser';
8-
import type { PipelineBothCommandParser } from '../commands/_common/types/CommandParser';
9-
import type { PipelineHeadCommandParser } from '../commands/_common/types/CommandParser';
10-
import type { PipelineTaskCommandParser } from '../commands/_common/types/CommandParser';
6+
import type {
7+
CommandParser,
8+
PipelineBothCommandParser,
9+
PipelineHeadCommandParser,
10+
PipelineTaskCommandParser,
11+
} from '../commands/_common/types/CommandParser';
1112
import type { CommandUsagePlace } from '../commands/_common/types/CommandUsagePlaces';
1213
import type { BookVersionCommand } from '../commands/BOOK_VERSION/BookVersionCommand';
1314
import { bookVersionCommandParser } from '../commands/BOOK_VERSION/bookVersionCommandParser';
@@ -39,55 +40,58 @@ import type { ActionCommand } from '../commands/X_ACTION/ActionCommand';
3940
import { actionCommandParser } from '../commands/X_ACTION/actionCommandParser';
4041
import type { InstrumentCommand } from '../commands/X_INSTRUMENT/InstrumentCommand';
4142
import { instrumentCommandParser } from '../commands/X_INSTRUMENT/instrumentCommandParser';
43+
import { removePipelineCommand } from '../utils/editable/edit-pipeline-string/removePipelineCommand';
4244
import type { PipelineEditableSerialized } from '../utils/editable/types/PipelineEditableSerialized';
43-
import { removePipelineCommand } from '../utils/editable/utils/removePipelineCommand';
4445
import { renamePipelineParameter } from '../utils/editable/utils/renamePipelineParameter';
4546
import { stringifyPipelineJson } from '../utils/editable/utils/stringifyPipelineJson';
46-
47+
import { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION } from '../version';
4748

4849
// Note: Exporting version from each package
4950
export { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION };
5051

51-
5252
// Note: Entities of the `@promptbook/editable`
53-
export { getParserForCommand };
54-
export { parseCommand };
55-
export type { CommandParser };
56-
export type { PipelineBothCommandParser };
57-
export type { PipelineHeadCommandParser };
58-
export type { PipelineTaskCommandParser };
59-
export type { CommandUsagePlace };
60-
export type { BookVersionCommand };
61-
export { bookVersionCommandParser };
62-
export { expectCommandParser };
63-
export type { ForeachCommand };
64-
export { foreachCommandParser };
65-
export { formatCommandParser };
66-
export type { FormfactorCommand };
67-
export { formfactorCommandParser };
68-
export { COMMANDS };
69-
export type { JokerCommand };
70-
export { jokerCommandParser };
71-
export type { KnowledgeCommand };
72-
export { knowledgeCommandParser };
73-
export { knowledgeSourceContentToName };
74-
export type { ModelCommand };
75-
export { modelCommandParser };
76-
export type { ParameterCommand };
77-
export { parameterCommandParser };
78-
export type { PersonaCommand };
79-
export { personaCommandParser };
80-
export type { PostprocessCommand };
81-
export { postprocessCommandParser };
82-
export type { SectionCommand };
83-
export { sectionCommandParser };
84-
export type { UrlCommand };
85-
export { urlCommandParser };
86-
export type { ActionCommand };
87-
export { actionCommandParser };
88-
export type { InstrumentCommand };
89-
export { instrumentCommandParser };
90-
export type { PipelineEditableSerialized };
91-
export { removePipelineCommand };
92-
export { renamePipelineParameter };
93-
export { stringifyPipelineJson };
53+
export {
54+
actionCommandParser,
55+
bookVersionCommandParser,
56+
COMMANDS,
57+
expectCommandParser,
58+
foreachCommandParser,
59+
formatCommandParser,
60+
formfactorCommandParser,
61+
getParserForCommand,
62+
instrumentCommandParser,
63+
jokerCommandParser,
64+
knowledgeCommandParser,
65+
knowledgeSourceContentToName,
66+
modelCommandParser,
67+
parameterCommandParser,
68+
parseCommand,
69+
personaCommandParser,
70+
postprocessCommandParser,
71+
removePipelineCommand,
72+
renamePipelineParameter,
73+
sectionCommandParser,
74+
stringifyPipelineJson,
75+
urlCommandParser,
76+
};
77+
export type {
78+
ActionCommand,
79+
BookVersionCommand,
80+
CommandParser,
81+
CommandUsagePlace,
82+
ForeachCommand,
83+
FormfactorCommand,
84+
InstrumentCommand,
85+
JokerCommand,
86+
KnowledgeCommand,
87+
ModelCommand,
88+
ParameterCommand,
89+
PersonaCommand,
90+
PipelineBothCommandParser,
91+
PipelineEditableSerialized,
92+
PipelineHeadCommandParser,
93+
PipelineTaskCommandParser,
94+
PostprocessCommand,
95+
SectionCommand,
96+
UrlCommand,
97+
};

src/conversion/parsePipeline.ts

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import type { ParameterCommand } from '../commands/PARAMETER/ParameterCommand';
44
import { sectionCommandParser } from '../commands/SECTION/sectionCommandParser';
55
import { getParserForCommand } from '../commands/_common/getParserForCommand';
66
import { parseCommand } from '../commands/_common/parseCommand';
7-
import type { $PipelineJson } from '../commands/_common/types/CommandParser';
8-
import type { $TaskJson } from '../commands/_common/types/CommandParser';
9-
import type { CommandBase } from '../commands/_common/types/CommandParser';
10-
import type { PipelineHeadCommandParser } from '../commands/_common/types/CommandParser';
11-
import type { PipelineTaskCommandParser } from '../commands/_common/types/CommandParser';
12-
import { DEFAULT_BOOK_TITLE } from '../config';
13-
import { DEFAULT_TASK_TITLE } from '../config';
14-
import { ORDER_OF_PIPELINE_JSON } from '../constants';
15-
import { RESERVED_PARAMETER_NAMES } from '../constants';
7+
import type {
8+
$PipelineJson,
9+
$TaskJson,
10+
CommandBase,
11+
PipelineHeadCommandParser,
12+
PipelineTaskCommandParser,
13+
} from '../commands/_common/types/CommandParser';
14+
import { DEFAULT_BOOK_TITLE, DEFAULT_TASK_TITLE } from '../config';
15+
import { ORDER_OF_PIPELINE_JSON, RESERVED_PARAMETER_NAMES } from '../constants';
1616
import { ParseError } from '../errors/ParseError';
1717
import { UnexpectedError } from '../errors/UnexpectedError';
1818
import { HIGH_LEVEL_ABSTRACTIONS } from '../high-level-abstractions/index';
@@ -24,9 +24,8 @@ import type { PipelineString } from '../pipeline/PipelineString';
2424
import { validatePipelineString } from '../pipeline/validatePipelineString';
2525
import type { ScriptLanguage } from '../types/ScriptLanguage';
2626
import { SUPPORTED_SCRIPT_LANGUAGES } from '../types/ScriptLanguage';
27-
import type { number_integer } from '../types/typeAliases';
28-
import type { number_positive } from '../types/typeAliases';
29-
import type { string_name } from '../types/typeAliases';
27+
import type { number_integer, number_positive, string_name } from '../types/typeAliases';
28+
import { deflatePipeline } from '../utils/editable/edit-pipeline-string/deflatePipeline';
3029
import { extractAllListItemsFromMarkdown } from '../utils/markdown/extractAllListItemsFromMarkdown';
3130
import { extractOneBlockFromMarkdown } from '../utils/markdown/extractOneBlockFromMarkdown';
3231
import { flattenMarkdown } from '../utils/markdown/flattenMarkdown';
@@ -118,48 +117,12 @@ export function parsePipeline(pipelineString: PipelineString): PipelineJson {
118117
}
119118
pipelineString = removeMarkdownComments(pipelineString);
120119
pipelineString = spaceTrim(pipelineString) as PipelineString;
121-
// <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
122-
123-
// ==============
124-
// Note: 1️⃣◽2️⃣ Process flat pipeline
125-
126-
const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
127-
const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
128-
// TODO: Also (double)check
129-
// > const usedCommands
130-
// > const isBlocksUsed
131-
// > const returnStatementCount
132-
133-
const isFlatPipeline = !isMarkdownBeginningWithHeadline && isLastLineReturnStatement;
134-
135-
// console.log({ isMarkdownBeginningWithHeadline, isLastLineReturnStatement, isFlatPipeline });
136-
137-
if (isFlatPipeline) {
138-
const pipelineStringLines = pipelineString.split('\n');
139-
const returnStatement = pipelineStringLines.pop()!;
140-
const prompt = spaceTrim(pipelineStringLines.join('\n'));
141-
pipelineString = validatePipelineString(
142-
spaceTrim(
143-
(block) => `
144-
# ${DEFAULT_BOOK_TITLE}
145120

146-
## Prompt
147-
148-
\`\`\`
149-
${block(prompt)}
150-
\`\`\`
151-
152-
${returnStatement}
153-
`,
154-
),
155-
);
156-
// <- TODO: Maybe use book` notation
157-
158-
// console.log(pipelineString);
159-
}
121+
// <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
122+
pipelineString = deflatePipeline(pipelineString);
160123

161124
// ==============
162-
// Note: 1️⃣◽3️⃣ Parse the markdown
125+
// Note: 1️⃣◽2️⃣ Parse the markdown
163126
pipelineString = flattenMarkdown(pipelineString) /* <- Note: [🥞] */;
164127
pipelineString = pipelineString.replaceAll(
165128
/`\{(?<parameterName>[a-z0-9_]+)\}`/gi,
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { spaceTrim } from 'spacetrim';
3+
import { DEFAULT_BOOK_TITLE } from '../../../config';
4+
import type { PipelineString } from '../../../pipeline/PipelineString';
5+
import { just } from '../../organization/just';
6+
import { addPipelineCommand } from './addPipelineCommand';
7+
8+
describe('how `addPipelineCommand` works', () => {
9+
it('should add HEAD command', () =>
10+
expect(
11+
addPipelineCommand({
12+
commandString: 'KNOWLEDGE https://pavolhejny.com/',
13+
pipelineString: spaceTrim(`
14+
# Book
15+
`) as PipelineString,
16+
// <- TODO: [📼] Use`book\`` string literal notation
17+
}),
18+
).toBe(
19+
just(
20+
spaceTrim(`
21+
# Book
22+
23+
- KNOWLEDGE https://pavolhejny.com/
24+
`),
25+
),
26+
));
27+
28+
it('should add command to flat pipeline', () =>
29+
expect(
30+
addPipelineCommand({
31+
commandString: 'KNOWLEDGE https://pavolhejny.com/',
32+
pipelineString: spaceTrim(`
33+
Hello, how are you?
34+
35+
-> {answer}
36+
`) as PipelineString,
37+
// <- TODO: [📼] Use`book\`` string literal notation
38+
}),
39+
).toBe(
40+
just(
41+
spaceTrim(`
42+
# ${DEFAULT_BOOK_TITLE}
43+
44+
- KNOWLEDGE https://pavolhejny.com/
45+
46+
## Prompt
47+
48+
\`\`\`
49+
Hello, how are you?
50+
\`\`\`
51+
52+
-> {answer}
53+
`),
54+
// <- TODO: [📼] Use`book\`` string literal notation
55+
),
56+
));
57+
58+
it('should preserve existing commands', () =>
59+
expect(
60+
addPipelineCommand({
61+
commandString: 'KNOWLEDGE https://example.com/',
62+
pipelineString: spaceTrim(`
63+
# Book
64+
65+
- PERSONA Paul, developer
66+
- KNOWLEDGE https://pavolhejny.com/
67+
`) as PipelineString,
68+
// <- TODO: [📼] Use`book\`` string literal notation
69+
}),
70+
).toBe(
71+
just(
72+
spaceTrim(`
73+
# Book
74+
75+
- PERSONA Paul, developer
76+
- KNOWLEDGE https://pavolhejny.com/
77+
- KNOWLEDGE https://example.com/
78+
`),
79+
),
80+
));
81+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import spaceTrim from 'spacetrim';
2+
import type { PipelineString } from '../../../pipeline/PipelineString';
3+
import { string_markdown_text } from '../../../types/typeAliases';
4+
import { deflatePipeline } from './deflatePipeline';
5+
6+
type AddPipelineCommandOptions = {
7+
commandString: string_markdown_text;
8+
pipelineString: PipelineString;
9+
};
10+
11+
/**
12+
* @@@
13+
*
14+
* @public exported from `@promptbook/editable`
15+
*/
16+
export function addPipelineCommand(options: AddPipelineCommandOptions): PipelineString {
17+
const { commandString, pipelineString } = options;
18+
19+
const deflatedPipelineString = deflatePipeline(pipelineString);
20+
21+
const lines = deflatedPipelineString.split('\n');
22+
const newLines: Array<string> = [];
23+
let isCommandAdded = false;
24+
25+
for (const line of lines) {
26+
// Add command before second (or more) heading
27+
if (!isCommandAdded && line.startsWith('##')) {
28+
newLines.push(`- ${commandString}`);
29+
newLines.push('');
30+
isCommandAdded = true;
31+
}
32+
33+
newLines.push(line);
34+
}
35+
36+
if (!isCommandAdded) {
37+
// Note: Only situation when this should happen is when pipeline has no tasks
38+
39+
if ((newLines[newLines.length - 1] || '').startsWith('#')) {
40+
newLines.push('');
41+
}
42+
newLines.push(`- ${commandString}`);
43+
44+
/*
45+
TODO: [🧠] Is this error relevant:
46+
throw new UnexpectedError(
47+
spaceTrim(
48+
(block) => `
49+
Can not add command to pipeline because there is no second heading in the pipeline
50+
51+
This should never happen because pipeline is deflated before adding command
52+
53+
The command to add:
54+
${block(commandString)}
55+
56+
---
57+
The original pipeline:
58+
${block(pipelineString)}
59+
60+
---
61+
Deflated pipeline:
62+
${block(deflatedPipelineString)}
63+
64+
---
65+
`,
66+
),
67+
);
68+
*/
69+
}
70+
71+
return spaceTrim(newLines.join('\n')) as PipelineString;
72+
}
73+
74+
/**
75+
* TODO: [🧠] What is the better solution - `- xxx`, - `- xxx` or preserve (see also next TODO)
76+
* TODO: When existing commands 1) as 2) number 3) list, add 4) new command as next number
77+
*/

0 commit comments

Comments
 (0)