@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 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
- ### string2file
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
- async function string2file(input, context)
25
+ function normalizeString(value)
32
26
  ```
33
27
 
34
- **Parameters:**
35
- - `input` (string|Object) - String content or inline descriptor
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
- **Returns:**
39
- - `Promise<Object>` - File descriptor
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
- ```json
52
- {
53
- "input": {
54
- "file": "{{string2file('Hello world')}}"
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
- **Parameters:**
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
- "markdown": "{{file2string(steps.pdf.output.file_descriptor)}}"
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
- - **Async**: All helpers must be async functions (return Promise)
150
- - **Context**: Helpers receive workflow context as last parameter
151
- - **Idempotent**: Same input should produce same output
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` - Unified access to Content Descriptors (MinIO download/upload)
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/cookbook-template-helpers",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Template helper functions for cookbook variable resolution - string2file, file2string, and more",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -1,22 +1,49 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * File helper functions for cookbook template resolution
5
- * Converts between string content and file descriptors
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
- * Get ContentResolver instance from helper context.
12
- * Uses DI if provided; otherwise relies on required MINIO_* env vars enforced by ContentResolver.
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 getContentResolverFromContext(helperContext) {
44
+ function getContentResolver(helperContext) {
18
45
  if (!helperContext || typeof helperContext !== 'object') {
19
- throw new Error('[cookbook-template-helpers] Helper context is required - Expected { data, workflow_id, step_id, contentResolver? }');
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
- * Uploads content to MinIO and returns file descriptor
50
- *
51
- * @param {string|Object} input - String content or inline descriptor
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
- const resolver = getContentResolverFromContext(context);
79
+ if (input === null || input === undefined) {
80
+ throw new Error('[string2file] Input is required');
81
+ }
70
82
 
71
- // Pokud je file descriptor, vrať ho
83
+ // Already a file descriptor
72
84
  if (input && input._descriptor === true && input.type === 'file') {
73
85
  return input;
74
86
  }
75
87
 
76
- // Pokud je inline descriptor, převeď na file
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
- // Pokud je string, vytvoř file descriptor
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
- * Downloads content from MinIO if needed
111
- *
112
- * @param {Object|string} descriptor - File descriptor or string
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 = getContentResolverFromContext(context);
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
  };