@onlineapps/cookbook-template-helpers 1.0.2 → 1.0.4
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 +25 -102
- package/package.json +1 -1
- package/src/helpers/fileHelpers.js +55 -63
- package/src/index.js +2 -0
package/README.md
CHANGED
|
@@ -15,104 +15,54 @@ Helper functions can be used in cookbook template variables using the syntax:
|
|
|
15
15
|
{{helper_name(argument)}}
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Arguments can be template variables themselves:
|
|
19
|
-
```
|
|
20
|
-
{{helper_name(steps.step_id.output.field)}}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
18
|
## Available Helpers
|
|
24
19
|
|
|
25
|
-
###
|
|
26
|
-
|
|
27
|
-
Converts string content or inline descriptor to file descriptor. Uploads content to MinIO storage.
|
|
20
|
+
### normalizeString
|
|
21
|
+
Removes nebezpečné / ne-print znaky, ponechá písmena (včetně diakritiky), čísla, mezery a základní interpunkci. Zachová diakritiku a case.
|
|
28
22
|
|
|
29
23
|
**Signature:**
|
|
30
24
|
```javascript
|
|
31
|
-
|
|
25
|
+
function normalizeString(value)
|
|
32
26
|
```
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- `context` (Object) - Workflow context (for storage access)
|
|
28
|
+
### webalizeString
|
|
29
|
+
Normalizuje řetězec pro URL/slug: odstraní diakritiku, interpunkci, nahradí mezery pomlčkami, převede na lowercase, zkolabuje vícenásobné pomlčky.
|
|
37
30
|
|
|
38
|
-
**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**Examples:**
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"input": {
|
|
46
|
-
"file": "{{string2file(steps.markdown.output.content)}}"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
31
|
+
**Signature:**
|
|
32
|
+
```javascript
|
|
33
|
+
function webalizeString(value)
|
|
49
34
|
```
|
|
50
35
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
### string2file
|
|
37
|
+
Převede string nebo inline descriptor na file descriptor (přes ContentResolver). Ukládá do storage podle nastavení ContentResolveru.
|
|
38
|
+
|
|
39
|
+
**Signature:**
|
|
40
|
+
```javascript
|
|
41
|
+
async function string2file(input, context)
|
|
57
42
|
```
|
|
58
43
|
|
|
59
44
|
### file2string
|
|
60
|
-
|
|
61
|
-
Converts file descriptor to string. Downloads content from MinIO if needed.
|
|
45
|
+
Převede file/inline descriptor na string (přes ContentResolver). File stáhne z MinIO, inline vrátí přímo.
|
|
62
46
|
|
|
63
47
|
**Signature:**
|
|
64
48
|
```javascript
|
|
65
49
|
async function file2string(descriptor, context)
|
|
66
50
|
```
|
|
67
51
|
|
|
68
|
-
|
|
69
|
-
- `descriptor` (Object|string) - File descriptor or string
|
|
70
|
-
- `context` (Object) - Workflow context (for storage access)
|
|
71
|
-
|
|
72
|
-
**Returns:**
|
|
73
|
-
- `Promise<string>` - String content
|
|
74
|
-
|
|
75
|
-
**Examples:**
|
|
52
|
+
## Usage in Cookbook
|
|
76
53
|
|
|
54
|
+
Helpers jsou k dispozici při resolvování template proměnných:
|
|
77
55
|
```json
|
|
78
56
|
{
|
|
79
57
|
"input": {
|
|
80
|
-
"
|
|
58
|
+
"title": "{{normalizeString(api_input.title)}}",
|
|
59
|
+
"slug": "{{webalizeString(api_input.title)}}",
|
|
60
|
+
"file": "{{string2file(api_input.content)}}",
|
|
61
|
+
"content": "{{file2string(steps.prepare.output.file_descriptor)}}"
|
|
81
62
|
}
|
|
82
63
|
}
|
|
83
64
|
```
|
|
84
65
|
|
|
85
|
-
## Usage in Cookbook
|
|
86
|
-
|
|
87
|
-
Helper functions are integrated into the cookbook executor. They are automatically available when resolving template variables.
|
|
88
|
-
|
|
89
|
-
**Example cookbook:**
|
|
90
|
-
|
|
91
|
-
```json
|
|
92
|
-
{
|
|
93
|
-
"version": "2.0.0",
|
|
94
|
-
"steps": [
|
|
95
|
-
{
|
|
96
|
-
"step_id": "get_markdown",
|
|
97
|
-
"type": "task",
|
|
98
|
-
"service": "hello-service",
|
|
99
|
-
"operation": "generate-markdown",
|
|
100
|
-
"input": { "name": "Karel" }
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"step_id": "create_pdf",
|
|
104
|
-
"type": "task",
|
|
105
|
-
"service": "pdfgen-service",
|
|
106
|
-
"operation": "md2pdf",
|
|
107
|
-
"depends_on": ["get_markdown"],
|
|
108
|
-
"input": {
|
|
109
|
-
"markdown": "{{file2string(steps.get_markdown.output.file_descriptor)}}"
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
66
|
## Integration
|
|
117
67
|
|
|
118
68
|
Helper functions are passed to the cookbook executor:
|
|
@@ -146,40 +96,13 @@ const executor = new CookbookExecutor(cookbook, {
|
|
|
146
96
|
|
|
147
97
|
## Helper Function Requirements
|
|
148
98
|
|
|
149
|
-
- **
|
|
150
|
-
- **
|
|
151
|
-
- **
|
|
152
|
-
- **Error handling**: Should throw descriptive errors
|
|
99
|
+
- **Deterministic**: Stejný vstup = stejný výstup
|
|
100
|
+
- **Bez vedlejších efektů**: String helpery jsou čisté; file helpery používají ContentResolver
|
|
101
|
+
- **Chyby**: Měly by být jasné a srozumitelné
|
|
153
102
|
|
|
154
103
|
## Dependencies
|
|
155
104
|
|
|
156
|
-
- `@onlineapps/content-resolver`
|
|
157
|
-
|
|
158
|
-
## Environment Variables
|
|
159
|
-
|
|
160
|
-
Helper functions use the following environment variables for storage access:
|
|
161
|
-
|
|
162
|
-
- `MINIO_HOST` - MinIO endpoint (required unless you inject `contentResolver`)
|
|
163
|
-
- `MINIO_PORT` - MinIO port (required unless you inject `contentResolver`)
|
|
164
|
-
- `MINIO_ACCESS_KEY` - MinIO access key (required unless you inject `contentResolver`)
|
|
165
|
-
- `MINIO_SECRET_KEY` - MinIO secret key (required unless you inject `contentResolver`)
|
|
166
|
-
|
|
167
|
-
## File Descriptor Format
|
|
168
|
-
|
|
169
|
-
File descriptors have the following structure:
|
|
170
|
-
|
|
171
|
-
```javascript
|
|
172
|
-
{
|
|
173
|
-
_descriptor: true,
|
|
174
|
-
type: 'file', // or 'inline'
|
|
175
|
-
storage_ref: 'minio://workflow/path/to/file', // for type='file'
|
|
176
|
-
content: '...', // for type='inline'
|
|
177
|
-
filename: 'document.txt',
|
|
178
|
-
content_type: 'text/plain',
|
|
179
|
-
size: 1234,
|
|
180
|
-
fingerprint: 'sha256...'
|
|
181
|
-
}
|
|
182
|
-
```
|
|
105
|
+
- `@onlineapps/content-resolver` (pro string2file/file2string)
|
|
183
106
|
|
|
184
107
|
## License
|
|
185
108
|
|
package/package.json
CHANGED
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Helper functions for cookbook template resolution.
|
|
5
|
+
* Includes safe string normalization and descriptor/string conversions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const ContentResolver = require('@onlineapps/content-resolver');
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Normalize string: remove control/unsafe chars, keep letters (incl. diacritics), numbers,
|
|
12
|
+
* whitespace and basic punctuation .,!?;:-_
|
|
13
|
+
* @param {string} value
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
function normalizeString(value) {
|
|
17
|
+
if (value === null || value === undefined) return '';
|
|
18
|
+
const str = String(value);
|
|
19
|
+
// Allow common Latin ranges (including diacritics), numbers, whitespace and basic punctuation
|
|
20
|
+
const cleaned = str.replace(/[^\x20-\x7E\u00A0-\u024F\u1E00-\u1EFF\s\.\,\!\?\;\:\-\_]/g, '');
|
|
21
|
+
// Explicitly drop angle brackets to avoid HTML/script injection noise
|
|
22
|
+
const noAngles = cleaned.replace(/[<>]/g, '');
|
|
23
|
+
// Collapse repeated whitespace to a single space and trim edges
|
|
24
|
+
return noAngles.replace(/\s+/g, ' ').trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Webalize string: normalize, strip diacritics, remove punctuation, lowercase, replace spaces with hyphens.
|
|
29
|
+
* @param {string} value
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
function webalizeString(value) {
|
|
33
|
+
const normalized = normalizeString(value);
|
|
34
|
+
const noPunct = normalized.replace(/[\.\,\!\?\;\:]/g, '');
|
|
35
|
+
const withoutDiacritics = noPunct.normalize('NFD').replace(/\p{Diacritic}/gu, '');
|
|
36
|
+
const withHyphens = withoutDiacritics.trim().replace(/\s+/g, '-');
|
|
37
|
+
return withHyphens.toLowerCase().replace(/-+/g, '-');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get ContentResolver instance (DI first, else new).
|
|
13
42
|
* @private
|
|
14
|
-
* @param {Object} helperContext - Helper context
|
|
15
|
-
* @returns {ContentResolver}
|
|
16
43
|
*/
|
|
17
|
-
function
|
|
44
|
+
function getContentResolver(helperContext) {
|
|
18
45
|
if (!helperContext || typeof helperContext !== 'object') {
|
|
19
|
-
throw new Error('[cookbook-template-helpers] Helper context is required
|
|
46
|
+
throw new Error('[cookbook-template-helpers] Helper context is required');
|
|
20
47
|
}
|
|
21
48
|
|
|
22
49
|
if (
|
|
@@ -39,47 +66,33 @@ function getContentResolverFromContext(helperContext) {
|
|
|
39
66
|
helperContext.data?.step_id ||
|
|
40
67
|
null;
|
|
41
68
|
|
|
42
|
-
return new ContentResolver({
|
|
43
|
-
context: { workflow_id, step_id }
|
|
44
|
-
});
|
|
69
|
+
return new ContentResolver({ context: { workflow_id, step_id } });
|
|
45
70
|
}
|
|
46
71
|
|
|
47
72
|
/**
|
|
48
|
-
* Convert string or inline descriptor to file descriptor
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @
|
|
52
|
-
* @param {Object} context - Workflow context (for storage access)
|
|
53
|
-
* @returns {Promise<Object>} File descriptor
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* // String input
|
|
57
|
-
* const descriptor = await string2file('Hello world', context);
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* // Inline descriptor input
|
|
61
|
-
* const descriptor = await string2file({
|
|
62
|
-
* _descriptor: true,
|
|
63
|
-
* type: 'inline',
|
|
64
|
-
* content: 'Hello world',
|
|
65
|
-
* filename: 'greeting.txt'
|
|
66
|
-
* }, context);
|
|
73
|
+
* Convert string or inline descriptor to file descriptor (uploads via ContentResolver).
|
|
74
|
+
* @param {string|Object} input
|
|
75
|
+
* @param {Object} context
|
|
76
|
+
* @returns {Promise<Object>}
|
|
67
77
|
*/
|
|
68
78
|
async function string2file(input, context) {
|
|
69
|
-
|
|
79
|
+
if (input === null || input === undefined) {
|
|
80
|
+
throw new Error('[string2file] Input is required');
|
|
81
|
+
}
|
|
70
82
|
|
|
71
|
-
//
|
|
83
|
+
// Already a file descriptor
|
|
72
84
|
if (input && input._descriptor === true && input.type === 'file') {
|
|
73
85
|
return input;
|
|
74
86
|
}
|
|
75
87
|
|
|
76
|
-
|
|
88
|
+
const resolver = getContentResolver(context);
|
|
89
|
+
|
|
90
|
+
// Inline descriptor -> file
|
|
77
91
|
if (input && input._descriptor === true && input.type === 'inline') {
|
|
78
92
|
const content = input.content;
|
|
79
93
|
if (typeof content !== 'string') {
|
|
80
94
|
throw new Error('[string2file] Inline descriptor content must be a string');
|
|
81
95
|
}
|
|
82
|
-
|
|
83
96
|
return await resolver.createDescriptor(content, {
|
|
84
97
|
filename: input.filename,
|
|
85
98
|
content_type: input.content_type,
|
|
@@ -88,7 +101,7 @@ async function string2file(input, context) {
|
|
|
88
101
|
});
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
//
|
|
104
|
+
// Raw string -> file descriptor
|
|
92
105
|
if (typeof input === 'string') {
|
|
93
106
|
return await resolver.createDescriptor(input, {
|
|
94
107
|
filename: 'content.txt',
|
|
@@ -98,44 +111,23 @@ async function string2file(input, context) {
|
|
|
98
111
|
});
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
if (input === null || input === undefined) {
|
|
102
|
-
throw new Error('[string2file] Input is required');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
114
|
throw new Error('[string2file] Invalid input - expected string or descriptor');
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
/**
|
|
109
|
-
* Convert file descriptor to string
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* @
|
|
113
|
-
* @param {Object} context - Workflow context (for storage access)
|
|
114
|
-
* @returns {Promise<string>} String content
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* // File descriptor input
|
|
118
|
-
* const content = await file2string({
|
|
119
|
-
* _descriptor: true,
|
|
120
|
-
* type: 'file',
|
|
121
|
-
* storage_ref: 'minio://workflow/path/to/file',
|
|
122
|
-
* fingerprint: 'abc123...'
|
|
123
|
-
* }, context);
|
|
124
|
-
*
|
|
125
|
-
* @example
|
|
126
|
-
* // Inline descriptor input
|
|
127
|
-
* const content = await file2string({
|
|
128
|
-
* _descriptor: true,
|
|
129
|
-
* type: 'inline',
|
|
130
|
-
* content: 'Hello world'
|
|
131
|
-
* }, context);
|
|
118
|
+
* Convert file descriptor to string (downloads via ContentResolver).
|
|
119
|
+
* @param {Object|string} descriptor
|
|
120
|
+
* @param {Object} context
|
|
121
|
+
* @returns {Promise<string>}
|
|
132
122
|
*/
|
|
133
123
|
async function file2string(descriptor, context) {
|
|
134
|
-
const resolver =
|
|
124
|
+
const resolver = getContentResolver(context);
|
|
135
125
|
return await resolver.getAsString(descriptor);
|
|
136
126
|
}
|
|
137
127
|
|
|
138
128
|
module.exports = {
|
|
129
|
+
normalizeString,
|
|
130
|
+
webalizeString,
|
|
139
131
|
string2file,
|
|
140
132
|
file2string
|
|
141
133
|
};
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
const fileHelpers = require('./helpers/fileHelpers');
|
|
16
16
|
|
|
17
17
|
module.exports = {
|
|
18
|
+
normalizeString: fileHelpers.normalizeString,
|
|
19
|
+
webalizeString: fileHelpers.webalizeString,
|
|
18
20
|
string2file: fileHelpers.string2file,
|
|
19
21
|
file2string: fileHelpers.file2string
|
|
20
22
|
};
|