markdown_exec 3.5.1 → 3.5.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.
- checksums.yaml +4 -4
- data/.ai-agent-instructions +54 -0
- data/.cursorrules +198 -0
- data/.rubocop.wide.yml +5 -0
- data/.rubocop.yml +7 -2
- data/CHANGELOG.md +12 -1
- data/Gemfile.lock +1 -1
- data/Rakefile +2 -0
- data/ai-principles.md +516 -0
- data/architecture-decisions.md +190 -0
- data/bats/block-hide.bats +1 -1
- data/bats/block-type-bash.bats +5 -5
- data/bats/block-type-link.bats +1 -1
- data/bats/block-type-opts.bats +3 -3
- data/bats/block-type-port.bats +2 -2
- data/bats/block-type-shell-require-ux.bats +2 -2
- data/bats/block-type-ux-allowed.bats +4 -4
- data/bats/block-type-ux-auto.bats +1 -1
- data/bats/block-type-ux-chained.bats +1 -1
- data/bats/block-type-ux-default.bats +1 -1
- data/bats/block-type-ux-echo-hash-transform.bats +1 -1
- data/bats/block-type-ux-echo-hash.bats +2 -2
- data/bats/block-type-ux-echo.bats +3 -3
- data/bats/block-type-ux-exec-hash-transform.bats +1 -1
- data/bats/block-type-ux-exec-hash.bats +2 -2
- data/bats/block-type-ux-exec.bats +1 -1
- data/bats/block-type-ux-force.bats +1 -1
- data/bats/block-type-ux-formats.bats +1 -1
- data/bats/block-type-ux-hidden.bats +1 -1
- data/bats/block-type-ux-invalid.bats +1 -1
- data/bats/block-type-ux-readonly.bats +1 -1
- data/bats/block-type-ux-require-chained.bats +2 -2
- data/bats/block-type-ux-require-context.bats +2 -2
- data/bats/block-type-ux-require.bats +2 -2
- data/bats/block-type-ux-required-variables.bats +1 -1
- data/bats/block-type-ux-row-format.bats +1 -1
- data/bats/block-type-ux-sources.bats +4 -4
- data/bats/block-type-ux-transform.bats +1 -1
- data/bats/block-type-vars.bats +3 -3
- data/bats/border.bats +1 -1
- data/bats/cli.bats +11 -11
- data/bats/command-substitution-options.bats +2 -2
- data/bats/command-substitution.bats +1 -1
- data/bats/document-shell.bats +1 -1
- data/bats/history.bats +5 -5
- data/bats/import-conflict.bats +1 -1
- data/bats/import-directive-line-continuation.bats +1 -1
- data/bats/import-directive-parameter-symbols.bats +1 -1
- data/bats/import-duplicates.bats +6 -6
- data/bats/import-parameter-symbols.bats +1 -1
- data/bats/import-with-text-substitution.bats +1 -1
- data/bats/import.bats +3 -3
- data/bats/indented-block-type-vars.bats +1 -1
- data/bats/indented-multi-line-output.bats +1 -1
- data/bats/line-decor-dynamic.bats +1 -1
- data/bats/line-wrapping.bats +1 -1
- data/bats/load-vars-state-demo.bats +4 -4
- data/bats/markup.bats +4 -4
- data/bats/mde.bats +4 -4
- data/bats/option-expansion.bats +1 -1
- data/bats/options-collapse.bats +4 -4
- data/bats/options.bats +47 -17
- data/bats/plain.bats +1 -1
- data/bats/publish.bats +2 -2
- data/bats/table-column-truncate.bats +1 -1
- data/bats/table.bats +2 -2
- data/bats/variable-expansion-multiline.bats +1 -1
- data/bats/variable-expansion.bats +6 -6
- data/conversation-template.md +611 -0
- data/docs/block-execution-modes.md +177 -0
- data/docs/block-filtering.md +252 -0
- data/docs/block-naming-patterns.md +210 -0
- data/docs/block-scanning-patterns.md +248 -0
- data/docs/cli-reference.md +370 -0
- data/docs/dev/block-hide.md +1 -1
- data/docs/dev/block-type-ux-transform.md +5 -4
- data/docs/dev/print_bytes.md +3 -0
- data/docs/dev/shebang.md +6 -0
- data/docs/docker-testing.md +5 -0
- data/docs/execution-control.md +384 -0
- data/docs/getting-started.md +209 -0
- data/docs/import-options.md +391 -0
- data/docs/tab-completion.md +7 -0
- data/docs/ux-blocks.md +376 -0
- data/examples/linked1.md +8 -1
- data/implementation-decisions.md +212 -0
- data/lib/cached_nested_file_reader.rb +138 -1
- data/lib/command_result.rb +27 -6
- data/lib/executed_shell_command.rb +512 -0
- data/lib/filter.rb +7 -7
- data/lib/hash_delegator.rb +403 -350
- data/lib/link_history.rb +22 -11
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/mdoc.rb +103 -44
- data/lib/menu.src.yml +110 -83
- data/lib/menu.yml +149 -83
- data/lib/transformed_shell_command.rb +449 -0
- data/lib/wl.rb +15 -0
- data/lib/ww.rb +16 -5
- data/requirements.md +111 -0
- data/semantic-tokens.md +132 -0
- data/tasks.md +69 -0
- metadata +26 -4
- data/docs/ux-blocks-examples.md +0 -120
- data/docs/ux-blocks-init-act.md +0 -100
data/docs/ux-blocks.md
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
# UX Blocks
|
|
2
|
+
|
|
3
|
+
UX blocks create interactive forms that prompt users for input, validate values, and initialize from various sources. This document covers the complete UX block system.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
UX blocks provide an interactive form system for markdown_exec that allows you to:
|
|
8
|
+
- Prompt users for input with custom prompts
|
|
9
|
+
- Validate input using regex patterns
|
|
10
|
+
- Transform validated input using format strings
|
|
11
|
+
- Initialize values from environment variables, commands, or allowed lists
|
|
12
|
+
- Create dynamic selection menus from command output
|
|
13
|
+
- Chain UX blocks with dependencies
|
|
14
|
+
|
|
15
|
+
## Block Structure
|
|
16
|
+
|
|
17
|
+
A UX block is a fenced code block with type `ux`:
|
|
18
|
+
|
|
19
|
+
```ux
|
|
20
|
+
name: VARIABLE_NAME
|
|
21
|
+
prompt: Enter a value
|
|
22
|
+
init: Default value
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Key Fields
|
|
26
|
+
|
|
27
|
+
### Required Fields
|
|
28
|
+
|
|
29
|
+
- **`name`**: The variable name that will be set (required)
|
|
30
|
+
|
|
31
|
+
### Optional Fields
|
|
32
|
+
|
|
33
|
+
- **`prompt`**: Text displayed when prompting for input
|
|
34
|
+
- **`init`**: Initial value or initialization method (see Init Phase below)
|
|
35
|
+
- **`act`**: Activation method (see Act Phase below)
|
|
36
|
+
- **`allow`**: List of allowed values for selection
|
|
37
|
+
- **`validate`**: Regex pattern for input validation
|
|
38
|
+
- **`transform`**: Format string for transforming validated input
|
|
39
|
+
- **`format`**: Format string for displaying the value
|
|
40
|
+
- **`echo`**: Shell expression to evaluate
|
|
41
|
+
- **`exec`**: Command to execute
|
|
42
|
+
- **`require`**: List of other UX block names that must be set first
|
|
43
|
+
|
|
44
|
+
## Init and Act Behavior
|
|
45
|
+
|
|
46
|
+
The `init` and `act` keys determine which other key is read for processing during initialization (when document is loaded) and activation (when block is selected) respectively.
|
|
47
|
+
|
|
48
|
+
### Init Phase
|
|
49
|
+
|
|
50
|
+
The init phase runs when the document is loaded. The behavior depends on the `init` value:
|
|
51
|
+
|
|
52
|
+
1. **`init: false`**: No initialization occurs
|
|
53
|
+
2. **`init: "string"`**: That string becomes the initial value
|
|
54
|
+
3. **`init: :allow`**: First value from `allow` list is used
|
|
55
|
+
4. **`init: :echo`**: Value from `echo` key is evaluated and returned
|
|
56
|
+
5. **`init: :exec`**: Command from `exec` key is executed and stdout is returned
|
|
57
|
+
6. **`init` not present**: Defaults to first available in order:
|
|
58
|
+
- `:allow` if `allow` exists
|
|
59
|
+
- `:default` if `default` exists
|
|
60
|
+
- `:echo` if `echo` exists
|
|
61
|
+
- `:exec` if `exec` exists
|
|
62
|
+
- `false` if none of the above exist
|
|
63
|
+
|
|
64
|
+
### Act Phase
|
|
65
|
+
|
|
66
|
+
The act phase runs when the block is activated (selected). The behavior depends on the `act` value:
|
|
67
|
+
|
|
68
|
+
1. **`act: false`**: Block cannot be activated
|
|
69
|
+
2. **`act: :allow`**: User selects from `allow` list
|
|
70
|
+
3. **`act: :echo`**: Value from `echo` key is evaluated and returned
|
|
71
|
+
4. **`act: :edit`**: User is prompted for input
|
|
72
|
+
5. **`act: :exec`**: Command from `exec` key is executed and stdout is returned
|
|
73
|
+
6. **`act` not present**: Defaults to:
|
|
74
|
+
- If `init` is `false`: First available in order: `:allow`, `:echo`, `:edit`, `:exec`
|
|
75
|
+
- Otherwise:
|
|
76
|
+
- `:allow` if `allow` exists
|
|
77
|
+
- `:edit` if `allow` does not exist
|
|
78
|
+
|
|
79
|
+
## Examples
|
|
80
|
+
|
|
81
|
+
### Simple Variable Display and Edit
|
|
82
|
+
|
|
83
|
+
```ux
|
|
84
|
+
init: Guest
|
|
85
|
+
name: USER_NAME
|
|
86
|
+
prompt: Enter your name
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- On init: Sets `USER_NAME` to "Guest"
|
|
90
|
+
- On act: Prompts user to enter their name
|
|
91
|
+
|
|
92
|
+
### Command Output Initialization
|
|
93
|
+
|
|
94
|
+
```ux
|
|
95
|
+
name: CURRENT_DIR
|
|
96
|
+
init: :exec
|
|
97
|
+
exec: basename $(pwd)
|
|
98
|
+
transform: :chomp
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- On init: Executes `basename $(pwd)` and uses output as value
|
|
102
|
+
- On act: Prompts for input (default behavior)
|
|
103
|
+
|
|
104
|
+
### Echo-based Initialization
|
|
105
|
+
|
|
106
|
+
```ux
|
|
107
|
+
name: SHELL_VERSION
|
|
108
|
+
init: :echo
|
|
109
|
+
echo: $SHELL
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- On init: Evaluates `$SHELL` and uses result as value
|
|
113
|
+
- On act: Evaluates echo string (default behavior)
|
|
114
|
+
|
|
115
|
+
### Selection from Allowed Values
|
|
116
|
+
|
|
117
|
+
```ux
|
|
118
|
+
name: ENVIRONMENT
|
|
119
|
+
allow:
|
|
120
|
+
- development
|
|
121
|
+
- staging
|
|
122
|
+
- production
|
|
123
|
+
prompt: Select environment
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- On init: Uses first allowed value (development)
|
|
127
|
+
- On act: Shows menu of allowed values for selection
|
|
128
|
+
|
|
129
|
+
### Email Validation
|
|
130
|
+
|
|
131
|
+
```ux
|
|
132
|
+
name: USER_EMAIL
|
|
133
|
+
prompt: Enter email address
|
|
134
|
+
validate: '(?<local>[^@]+)@(?<domain>[^@]+)'
|
|
135
|
+
transform: '%{local}@%{domain}'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- Validates input matches email pattern
|
|
139
|
+
- Transforms using captured groups from validation regex
|
|
140
|
+
|
|
141
|
+
### Version Number Validation
|
|
142
|
+
|
|
143
|
+
```ux
|
|
144
|
+
name: VERSION
|
|
145
|
+
prompt: Enter version number
|
|
146
|
+
validate: '(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)'
|
|
147
|
+
transform: '%{major}.%{minor}.%{patch}'
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- Validates version number format
|
|
151
|
+
- Normalizes format using captured groups
|
|
152
|
+
|
|
153
|
+
### Git Branch Selection with Validation
|
|
154
|
+
|
|
155
|
+
```ux
|
|
156
|
+
name: BRANCH_NAME
|
|
157
|
+
init: ":exec"
|
|
158
|
+
exec: "git branch --format='%(refname:short)'"
|
|
159
|
+
validate: '^(?<type>feature|bugfix|hotfix)/(?<ticket>[A-Z]+-\d+)-(?<desc>.+)$'
|
|
160
|
+
transform: "${type}/${ticket}-${desc}"
|
|
161
|
+
prompt: "Select or enter branch name"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- On init: Executes git command to get branch list
|
|
165
|
+
- Validates branch name format
|
|
166
|
+
- Transforms to normalized format
|
|
167
|
+
|
|
168
|
+
### Environment Configuration with Dependencies
|
|
169
|
+
|
|
170
|
+
```ux
|
|
171
|
+
name: DATABASE_URL
|
|
172
|
+
require:
|
|
173
|
+
- ENVIRONMENT
|
|
174
|
+
- DB_HOST
|
|
175
|
+
- DB_PORT
|
|
176
|
+
format: "postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- Requires other UX blocks to be set first
|
|
180
|
+
- Formats final value using required variables
|
|
181
|
+
|
|
182
|
+
### Multi-step Configuration
|
|
183
|
+
|
|
184
|
+
```ux
|
|
185
|
+
name: DEPLOY_CONFIG
|
|
186
|
+
require:
|
|
187
|
+
- ENVIRONMENT
|
|
188
|
+
- VERSION
|
|
189
|
+
init: ":echo"
|
|
190
|
+
echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
|
|
191
|
+
act: ":exec"
|
|
192
|
+
exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- On init: Evaluates echo string with dependencies
|
|
196
|
+
- On act: Executes deploy script with parameters
|
|
197
|
+
|
|
198
|
+
### Conditional Initialization
|
|
199
|
+
|
|
200
|
+
```ux
|
|
201
|
+
name: API_KEY
|
|
202
|
+
init: ":allow"
|
|
203
|
+
allow:
|
|
204
|
+
- ${PROD_API_KEY}
|
|
205
|
+
- ${STAGING_API_KEY}
|
|
206
|
+
- ${DEV_API_KEY}
|
|
207
|
+
require:
|
|
208
|
+
- ENVIRONMENT
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- On init: Uses first allowed API key
|
|
212
|
+
- On act: Shows menu of allowed API keys for selection
|
|
213
|
+
- Requires ENVIRONMENT to be set first
|
|
214
|
+
|
|
215
|
+
### Formatted Output with Validation
|
|
216
|
+
|
|
217
|
+
```ux
|
|
218
|
+
name: PHONE_NUMBER
|
|
219
|
+
prompt: "Enter phone number"
|
|
220
|
+
validate: '(?<country>\d{1,3})(?<area>\d{3})(?<number>\d{7})'
|
|
221
|
+
transform: "+${country} (${area}) ${number}"
|
|
222
|
+
format: "Phone: ${PHONE_NUMBER}"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
- Validates phone number format
|
|
226
|
+
- Transforms to formatted display
|
|
227
|
+
- Uses format string for final display
|
|
228
|
+
|
|
229
|
+
### Command Output with Transformation
|
|
230
|
+
|
|
231
|
+
```ux
|
|
232
|
+
name: GIT_STATUS
|
|
233
|
+
init: ":exec"
|
|
234
|
+
exec: "git status --porcelain"
|
|
235
|
+
validate: '(?<status>[AMDR])\s+(?<file>.+)'
|
|
236
|
+
transform: "${status}: ${file}"
|
|
237
|
+
format: "Changes: ${GIT_STATUS}"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- On init: Executes git status command
|
|
241
|
+
- Validates and transforms output
|
|
242
|
+
- Formats for display
|
|
243
|
+
|
|
244
|
+
## Advanced Patterns
|
|
245
|
+
|
|
246
|
+
### Echo on Init, Exec on Act
|
|
247
|
+
|
|
248
|
+
```ux
|
|
249
|
+
name: DEPLOY_CONFIG
|
|
250
|
+
init: :echo
|
|
251
|
+
echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
|
|
252
|
+
act: :exec
|
|
253
|
+
exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Behavior:**
|
|
257
|
+
- On init: Evaluates echo string "Deploying ${VERSION} to ${ENVIRONMENT}"
|
|
258
|
+
- On act: Executes deploy.sh with environment and version parameters
|
|
259
|
+
|
|
260
|
+
### Allow on Init, Edit on Act
|
|
261
|
+
|
|
262
|
+
```ux
|
|
263
|
+
name: ENVIRONMENT
|
|
264
|
+
init: :allow
|
|
265
|
+
allow:
|
|
266
|
+
- development
|
|
267
|
+
- staging
|
|
268
|
+
- production
|
|
269
|
+
act: :edit
|
|
270
|
+
prompt: Select environment
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Behavior:**
|
|
274
|
+
- On init: Uses first allowed value (development)
|
|
275
|
+
- On act: Prompts user to select from allowed values
|
|
276
|
+
|
|
277
|
+
### Exec on Init, Echo on Act
|
|
278
|
+
|
|
279
|
+
```ux
|
|
280
|
+
name: CURRENT_DIR
|
|
281
|
+
init: :exec
|
|
282
|
+
exec: basename $(pwd)
|
|
283
|
+
act: :echo
|
|
284
|
+
echo: "Current directory: ${CURRENT_DIR}"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Behavior:**
|
|
288
|
+
- On init: Executes basename command on current directory
|
|
289
|
+
- On act: Evaluates echo string with current directory value
|
|
290
|
+
|
|
291
|
+
### Allow on Both
|
|
292
|
+
|
|
293
|
+
```ux
|
|
294
|
+
name: API_KEY
|
|
295
|
+
init: :allow
|
|
296
|
+
allow:
|
|
297
|
+
- ${PROD_API_KEY}
|
|
298
|
+
- ${STAGING_API_KEY}
|
|
299
|
+
- ${DEV_API_KEY}
|
|
300
|
+
act: :allow
|
|
301
|
+
require:
|
|
302
|
+
- ENVIRONMENT
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Behavior:**
|
|
306
|
+
- On init: Uses first allowed API key
|
|
307
|
+
- On act: Shows menu of allowed API keys for selection
|
|
308
|
+
|
|
309
|
+
### Echo on Both
|
|
310
|
+
|
|
311
|
+
```ux
|
|
312
|
+
name: SHELL_VERSION
|
|
313
|
+
init: :echo
|
|
314
|
+
echo: $SHELL
|
|
315
|
+
act: :echo
|
|
316
|
+
echo: "Using shell: ${SHELL_VERSION}"
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Behavior:**
|
|
320
|
+
- On init: Gets shell value from environment
|
|
321
|
+
- On act: Evaluates echo string with current shell value
|
|
322
|
+
|
|
323
|
+
## Validation and Transformation
|
|
324
|
+
|
|
325
|
+
### Validation Regex
|
|
326
|
+
|
|
327
|
+
The `validate` field uses Ruby regex syntax with named capture groups:
|
|
328
|
+
|
|
329
|
+
```ux
|
|
330
|
+
validate: '(?<local>[^@]+)@(?<domain>[^@]+)'
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
This creates capture groups that can be referenced in the `transform` field.
|
|
334
|
+
|
|
335
|
+
### Transformation Format
|
|
336
|
+
|
|
337
|
+
The `transform` field uses format string syntax with capture group references:
|
|
338
|
+
|
|
339
|
+
```ux
|
|
340
|
+
transform: '%{local}@%{domain}'
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Or with shell variable expansion:
|
|
344
|
+
|
|
345
|
+
```ux
|
|
346
|
+
transform: "${local}@${domain}"
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Format Display
|
|
350
|
+
|
|
351
|
+
The `format` field controls how the value is displayed in menus:
|
|
352
|
+
|
|
353
|
+
```ux
|
|
354
|
+
format: "Phone: ${PHONE_NUMBER}"
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Dependencies
|
|
358
|
+
|
|
359
|
+
UX blocks can depend on other UX blocks using the `require` field:
|
|
360
|
+
|
|
361
|
+
```ux
|
|
362
|
+
name: DATABASE_URL
|
|
363
|
+
require:
|
|
364
|
+
- ENVIRONMENT
|
|
365
|
+
- DB_HOST
|
|
366
|
+
- DB_PORT
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
When a UX block has dependencies, those blocks must be initialized or activated first before this block can be used.
|
|
370
|
+
|
|
371
|
+
## Related Documentation
|
|
372
|
+
|
|
373
|
+
- [Block Naming Patterns](block-naming-patterns.md) - How block names are parsed
|
|
374
|
+
- [Block Execution Modes](block-execution-modes.md) - Execution mode configuration
|
|
375
|
+
- [Import Options](import-options.md) - Using UX blocks with imports
|
|
376
|
+
|
data/examples/linked1.md
CHANGED
|
@@ -40,5 +40,12 @@ file: examples/linked2.md
|
|
|
40
40
|
```link :linked2_import_vars +(vars2)
|
|
41
41
|
file: examples/linked2.md
|
|
42
42
|
vars:
|
|
43
|
-
page2_var_via_environment:
|
|
43
|
+
page2_var_via_environment: ${PAGE2_VAR_VIA_INHERIT}
|
|
44
|
+
page2_var_via_environment1: ${d1_v1}
|
|
45
|
+
page2_var_via_environment2: for_page2_from_page1_via_current_environment
|
|
44
46
|
```
|
|
47
|
+
```vars :(document_vars)
|
|
48
|
+
d1_v1: 1
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Implementation Decisions
|
|
2
|
+
|
|
3
|
+
**STDD Methodology Version**: 1.0.0
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
This document captures detailed implementation decisions for your project, including specific APIs, data structures, and algorithms. All decisions are cross-referenced with architecture decisions using `[ARCH:*]` tokens and requirements using `[REQ:*]` tokens for traceability.
|
|
7
|
+
|
|
8
|
+
## 1. Configuration Structure [IMPL:CONFIG_STRUCT] [ARCH:CONFIG_STRUCTURE] [REQ:CONFIGURATION]
|
|
9
|
+
|
|
10
|
+
### Config Type
|
|
11
|
+
```[your-language]
|
|
12
|
+
type Config struct {
|
|
13
|
+
// Add your configuration fields here
|
|
14
|
+
Field1 string
|
|
15
|
+
Field2 int
|
|
16
|
+
Field3 bool
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Default Values
|
|
21
|
+
- Field1: default value
|
|
22
|
+
- Field2: default value
|
|
23
|
+
- Field3: default value
|
|
24
|
+
|
|
25
|
+
## 2. Core Implementation [IMPL:EXAMPLE_IMPLEMENTATION] [ARCH:EXAMPLE_DECISION] [REQ:EXAMPLE_FEATURE]
|
|
26
|
+
|
|
27
|
+
### Data Structure
|
|
28
|
+
```[your-language]
|
|
29
|
+
type ExampleStruct struct {
|
|
30
|
+
Field1 string
|
|
31
|
+
Field2 int
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Implementation Approach
|
|
36
|
+
- Approach description
|
|
37
|
+
- Key algorithms
|
|
38
|
+
- Performance considerations
|
|
39
|
+
|
|
40
|
+
### Platform-Specific Considerations
|
|
41
|
+
- Platform 1: Specific considerations
|
|
42
|
+
- Platform 2: Specific considerations
|
|
43
|
+
|
|
44
|
+
## 3. Error Handling Implementation [IMPL:ERROR_HANDLING] [ARCH:ERROR_HANDLING] [REQ:ERROR_HANDLING]
|
|
45
|
+
|
|
46
|
+
### Error Types
|
|
47
|
+
```[your-language]
|
|
48
|
+
var (
|
|
49
|
+
ErrExampleError = errors.New("example error message")
|
|
50
|
+
ErrAnotherError = errors.New("another error message")
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Error Wrapping
|
|
55
|
+
```[your-language]
|
|
56
|
+
if err != nil {
|
|
57
|
+
return fmt.Errorf("context: %w", err)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Error Reporting
|
|
62
|
+
- Error logging approach
|
|
63
|
+
- Error propagation pattern
|
|
64
|
+
- User-facing error messages
|
|
65
|
+
|
|
66
|
+
## 4. Testing Implementation [IMPL:TESTING] [ARCH:TESTING_STRATEGY] [REQ:*]
|
|
67
|
+
|
|
68
|
+
**Note**: This implementation realizes the validation criteria specified in `requirements.md` and follows the testing strategy defined in `architecture-decisions.md`. Each test validates specific satisfaction criteria from requirements.
|
|
69
|
+
|
|
70
|
+
### Unit Test Structure
|
|
71
|
+
```[your-language]
|
|
72
|
+
func TestExampleFeature(t *testing.T) {
|
|
73
|
+
tests := []struct {
|
|
74
|
+
name string
|
|
75
|
+
input InputType
|
|
76
|
+
expected OutputType
|
|
77
|
+
}{
|
|
78
|
+
{
|
|
79
|
+
name: "test case 1",
|
|
80
|
+
input: inputValue,
|
|
81
|
+
expected: expectedValue,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for _, tt := range tests {
|
|
86
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
87
|
+
result := functionUnderTest(tt.input)
|
|
88
|
+
if result != tt.expected {
|
|
89
|
+
t.Errorf("expected %v, got %v", tt.expected, result)
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Integration Test Structure
|
|
97
|
+
```[your-language]
|
|
98
|
+
func TestIntegrationScenario(t *testing.T) {
|
|
99
|
+
// Setup
|
|
100
|
+
// Execute
|
|
101
|
+
// Verify
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 5. Code Style and Conventions [IMPL:CODE_STYLE]
|
|
106
|
+
|
|
107
|
+
### Naming
|
|
108
|
+
- Use descriptive names
|
|
109
|
+
- Follow language naming conventions
|
|
110
|
+
- Exported types/functions: PascalCase (or language equivalent)
|
|
111
|
+
- Unexported: camelCase (or language equivalent)
|
|
112
|
+
|
|
113
|
+
### Documentation
|
|
114
|
+
- Package-level documentation
|
|
115
|
+
- Exported function documentation
|
|
116
|
+
- Inline comments for complex logic
|
|
117
|
+
- Examples in test files
|
|
118
|
+
|
|
119
|
+
### Formatting
|
|
120
|
+
- Use standard formatter for chosen language
|
|
121
|
+
- Use linter for code quality
|
|
122
|
+
|
|
123
|
+
## 6. Shebang Line Detection Logic [IMPL:SHEBANG_DETECTION] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
|
|
124
|
+
|
|
125
|
+
### Detection Algorithm
|
|
126
|
+
```ruby
|
|
127
|
+
# [REQ:SHEBANG_HIDING] Detect shebang lines at the start of file content
|
|
128
|
+
# [IMPL:SHEBANG_DETECTION] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
|
|
129
|
+
# Matches the beginning of the first line as '#!' - anything after that matches a shebang
|
|
130
|
+
# Works directly with raw string segments (not NestedLine objects)
|
|
131
|
+
def is_shebang_line?(line, is_first_line)
|
|
132
|
+
return false unless is_first_line
|
|
133
|
+
line.start_with?('#!')
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Detection Rules
|
|
138
|
+
- Shebang lines must start with `#!` at the beginning of the line (no leading whitespace)
|
|
139
|
+
- Only the first line of file content is considered (index 0)
|
|
140
|
+
- The line must begin with `#!` - anything after that matches a shebang
|
|
141
|
+
- Detection occurs before import directive processing
|
|
142
|
+
- Each file in nested imports is checked independently
|
|
143
|
+
|
|
144
|
+
### Edge Cases
|
|
145
|
+
- Empty files: No shebang (no first line)
|
|
146
|
+
- Files starting with whitespace before `#!`: Not recognized as shebang (must be at beginning)
|
|
147
|
+
- Files with only shebang: File becomes effectively empty after filtering
|
|
148
|
+
- Import directives on first line: Shebang takes precedence (shebang is first)
|
|
149
|
+
|
|
150
|
+
## 7. Shebang Line Filtering Implementation [IMPL:SHEBANG_FILTERING] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
|
|
151
|
+
|
|
152
|
+
### Filtering Logic
|
|
153
|
+
```ruby
|
|
154
|
+
# [REQ:SHEBANG_HIDING] Filter shebang lines from processed output
|
|
155
|
+
# [IMPL:SHEBANG_FILTERING] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
|
|
156
|
+
# Filtering occurs inline during segment reading
|
|
157
|
+
File.readlines(filename, chomp: true).each.with_index do |segment, ind|
|
|
158
|
+
# Skip shebang lines at the beginning of the file
|
|
159
|
+
next if @hide_shebang && is_shebang_line?(segment, ind == 0)
|
|
160
|
+
|
|
161
|
+
# Process remaining lines normally
|
|
162
|
+
# ...
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Implementation Details
|
|
167
|
+
- Filtering occurs inline in `CachedNestedFileReader#readlines` during segment reading
|
|
168
|
+
- Shebang lines are skipped before they are processed into `NestedLine` objects
|
|
169
|
+
- Applied to both direct file reads and nested imports (via recursive calls)
|
|
170
|
+
- Option `hide_shebang` controls filtering behavior
|
|
171
|
+
- When disabled (`hide_shebang: false`), all lines included
|
|
172
|
+
- When enabled (`hide_shebang: true`), first line (index 0) is skipped if it's a shebang
|
|
173
|
+
- Filtering happens at the source, preventing shebang lines from entering the processing pipeline
|
|
174
|
+
- More efficient than post-processing as it avoids creating `NestedLine` objects for shebang lines
|
|
175
|
+
|
|
176
|
+
### Integration with CachedNestedFileReader
|
|
177
|
+
- Option stored as instance variable `@hide_shebang` set during initialization
|
|
178
|
+
- Filtering applied inline during the `File.readlines` loop before segment processing
|
|
179
|
+
- Shebang detection uses `is_shebang_line?(segment, ind == 0)` where `segment` is the raw string line
|
|
180
|
+
- Cached results already have shebang filtered (if option was enabled during cache)
|
|
181
|
+
- Recursive calls to `readlines` use the same `@hide_shebang` instance variable, ensuring consistent behavior across nested imports
|
|
182
|
+
|
|
183
|
+
## 8. CLI Option Implementation in Menu System [IMPL:CLI_OPTION_IMPLEMENTATION] [ARCH:CLI_OPTION_DESIGN] [REQ:SHEBANG_HIDING]
|
|
184
|
+
|
|
185
|
+
### Menu Configuration
|
|
186
|
+
```yaml
|
|
187
|
+
# [REQ:SHEBANG_HIDING] CLI option for hiding shebang lines
|
|
188
|
+
# [IMPL:CLI_OPTION_IMPLEMENTATION] [ARCH:CLI_OPTION_DESIGN] [REQ:SHEBANG_HIDING]
|
|
189
|
+
- :opt_name: hide_shebang
|
|
190
|
+
:env_var: MDE_HIDE_SHEBANG
|
|
191
|
+
:description: Hide shebang lines in document output
|
|
192
|
+
:arg_name: BOOL
|
|
193
|
+
:default: true
|
|
194
|
+
:procname: val_as_bool
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Option Access
|
|
198
|
+
- CLI: `--hide-shebang` (enables) / `--no-hide-shebang` (disables)
|
|
199
|
+
- Environment: `MDE_HIDE_SHEBANG=true` or `MDE_HIDE_SHEBANG=false`
|
|
200
|
+
- Configuration file: `hide_shebang: true` in `.mde.yml`
|
|
201
|
+
- Default: `true` (shebang lines hidden by default)
|
|
202
|
+
|
|
203
|
+
### Option Propagation
|
|
204
|
+
- Option available in `@options` hash via `MarkParse#base_options`
|
|
205
|
+
- Option passed to `CachedNestedFileReader` during initialization or read calls
|
|
206
|
+
- Option value accessible as `options[:hide_shebang]` (boolean)
|
|
207
|
+
|
|
208
|
+
### Integration Points
|
|
209
|
+
- `MarkParse#base_options`: Includes option in base options hash
|
|
210
|
+
- `CachedNestedFileReader#initialize`: Option passed as parameter (or via options hash)
|
|
211
|
+
- `CachedNestedFileReader#readlines`: Option used to control filtering behavior
|
|
212
|
+
|