sommark 4.5.3 → 5.0.1

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.
Files changed (41) hide show
  1. package/README.md +315 -179
  2. package/cli/cli.mjs +1 -1
  3. package/cli/commands/color.js +36 -14
  4. package/cli/commands/help.js +3 -0
  5. package/cli/commands/init.js +1 -3
  6. package/cli/constants.js +5 -2
  7. package/constants/html_props.js +0 -5
  8. package/core/errors.js +5 -4
  9. package/core/evaluator.js +1 -2
  10. package/core/formats.js +7 -1
  11. package/core/helpers/config-loader.js +2 -4
  12. package/core/helpers/lib.js +1 -1
  13. package/core/labels.js +2 -15
  14. package/core/lexer.js +197 -313
  15. package/core/modules.js +13 -13
  16. package/core/parser.js +226 -535
  17. package/core/tokenTypes.js +6 -15
  18. package/core/transpiler.js +129 -110
  19. package/core/validator.js +6 -26
  20. package/dist/sommark.browser.js +1781 -2172
  21. package/dist/sommark.browser.lite.js +1779 -2169
  22. package/dist/sommark.lexer.js +392 -544
  23. package/dist/sommark.parser.js +604 -1200
  24. package/formatter/mark.js +34 -0
  25. package/formatter/tag.js +7 -33
  26. package/helpers/utils.js +15 -16
  27. package/index.js +9 -1
  28. package/index.shared.js +26 -16
  29. package/mappers/languages/csv.js +62 -0
  30. package/mappers/languages/html.js +12 -66
  31. package/mappers/languages/json.js +74 -156
  32. package/mappers/languages/jsonc.js +21 -63
  33. package/mappers/languages/markdown.js +159 -276
  34. package/mappers/languages/mdx.js +7 -62
  35. package/mappers/languages/text.js +2 -19
  36. package/mappers/languages/toml.js +231 -0
  37. package/mappers/languages/xml.js +25 -25
  38. package/mappers/languages/yaml.js +323 -0
  39. package/mappers/mapper.js +1 -22
  40. package/mappers/shared/index.js +3 -16
  41. package/package.json +5 -2
package/README.md CHANGED
@@ -5,283 +5,420 @@
5
5
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
6
6
  [![license](https://img.shields.io/npm/l/sommark.svg)](https://github.com/Adam-Elmi/SomMark/blob/master/LICENSE)
7
7
 
8
- SomMark is a high-performance markup language designed for structured content. It acts as an extensible source language that can be transformed into multiple formats like HTML, JSON, MDX, XML, and Markdown.
8
+ **SomMark** is a template language that compiles to multiple output formats HTML, JSON, YAML, TOML, CSV, Markdown, XML, and more.
9
9
 
10
- SomMark uses explicit structural boundaries to ensure your document remains stable and predictable. It enables infinite nesting and provides total control over your contents.
10
+ Write your content once with a single consistent block syntax. Add loops, compile-time logic, and file imports. Compile to whatever format your project needs.
11
11
 
12
- > **v4.2.0 Browser Support**: SomMark now compiles templates directly in the browser with no Node.js dependencies. Use the `sommark/browser` entry point with any bundler (Vite, Webpack, Rollup, esbuild). See [Browser API docs](docs/api/Browser/) for `resolveBaseDir` and `renderCompiledHTML`.
12
+ > **v5 is the official stable release and the recommended version to start with.**
13
+ > SomMark has reached its main goal — a single consistent block syntax that compiles to any output format. v5 is the last major version. Future releases will be minor updates or patches.
13
14
 
14
15
  ---
15
16
 
16
17
  ## Install
17
18
 
18
- #### 1. Global (Command Line)
19
- Install SomMark globally to use the `sommark` command.
20
19
  ```bash
20
+ # CLI
21
21
  npm install -g sommark
22
+
23
+ # Use it with your project
24
+ npm install sommark
22
25
  ```
23
26
 
24
- To verify it is working, check the version:
25
- ```bash
26
- sommark --version
27
+ ---
28
+
29
+ ## Showcase
30
+
31
+ **`team.smark`** (HTML mapper)
32
+
33
+ ```ini
34
+ [import = Card: "./components/Card.smark" !]
35
+
36
+ ${
37
+ const team = [
38
+ { name: "Adam", role: "Founder", avatar: "adam.jpg" },
39
+ { name: "Hawa", role: "Engineer", avatar: "hawa.jpg" },
40
+ { name: "Ilham", role: "Designer", avatar: "ilham.jpg" },
41
+ ];
42
+ const year = new Date().getFullYear();
43
+ }$
44
+
45
+ [main = class: "team-page"]
46
+ [h1]Our Team[end:h1]
47
+
48
+ [section = class: "grid"]
49
+ [for-each = ${ team }$, as: "member"]
50
+ [Card = name: ${ member.name }$, role: ${ member.role }$]
51
+ [img = src: ${ member.avatar }$, alt: ${ member.name }$ !]
52
+ [end:Card]
53
+ [end:for-each]
54
+ [end:section]
55
+
56
+ [footer]© ${ year }$ SomMark[end:footer]
57
+ [end:main]
58
+ ```
59
+
60
+ **`components/Card.smark`**
61
+
62
+ ```ini
63
+ [div = class: "card"]
64
+ [h2]v{name}[end:h2]
65
+ [p]v{role}[end:p]
66
+ [slot!]
67
+ [end:div]
27
68
  ```
28
69
 
29
- #### 2. Local (Project API)
30
- Add SomMark to your project as a dependency:
31
70
  ```bash
32
- npm install sommark
71
+ sommark --html team.smark
72
+ ```
73
+
74
+ ```html
75
+ <main class="team-page">
76
+ <h1>Our Team</h1>
77
+ <section class="grid">
78
+ <div class="card">
79
+ <h2>Adam</h2>
80
+ <p>Founder</p>
81
+ <img src="adam.jpg" alt="Adam">
82
+ </div>
83
+ <div class="card">
84
+ <h2>Hawa</h2>
85
+ <p>Engineer</p>
86
+ <img src="hawa.jpg" alt="Hawa">
87
+ </div>
88
+ <div class="card">
89
+ <h2>Ilham</h2>
90
+ <p>Designer</p>
91
+ <img src="ilham.jpg" alt="Ilham">
92
+ </div>
93
+ </section>
94
+ <footer>© 2026 SomMark</footer>
95
+ </main>
33
96
  ```
34
97
 
35
98
  ---
36
99
 
100
+ ## Output formats
101
+
102
+ | Format | CLI Flag |
103
+ | -------- | -------------- |
104
+ | HTML | `--html` |
105
+ | Markdown | `--markdown` |
106
+ | MDX | `--mdx` |
107
+ | JSON | `--json` |
108
+ | JSONC | `--jsonc` |
109
+ | YAML | `--yaml` |
110
+ | TOML | `--toml` |
111
+ | CSV | `--csv` |
112
+ | XML | `--xml` |
113
+ | Text | `--text` |
114
+
115
+ ---
116
+
37
117
  ## Features
38
118
 
39
119
  ### Blocks
40
120
 
41
- Blocks are the primary containers in SomMark, used to group, style, and organize structural content. A block starts with `[identifier]` and closes with a matching `[end]` or self-closing `!` if the block does not have any content, for example `[br!]` or `[img = src: "logo.png" !]`.
121
+ Every tag is a block. Open with `[name]`, close with `[end:name]`. A plain `[end]` also works, but `[end:name]` is recommended for readability.
42
122
 
43
123
  ```ini
44
- [div = class: "container"]
45
- [h1]Welcome to SomMark[end]
46
- [p]Structured content, zero guesswork.[end]
47
- [hr = class: "divider" !]
48
- [end]
124
+ [article = class: "post"]
125
+ [h1]Hello, SomMark[end:h1]
126
+ [p]Structured content, zero guesswork.[end:p]
127
+ [hr!]
128
+ [end:article]
49
129
  ```
50
- [Read more about blocks](./docs/syntax/block.md)
51
-
52
- ### Self-Closing Blocks
53
130
 
54
- Blocks that carry no body content close instantly with `!`.
131
+ Self-closing blocks carry no body append `!` inside the tag:
55
132
 
56
133
  ```ini
57
134
  [br!]
58
- [hr = class: "divider" !]
59
- [img = src: "logo.png", alt: "SomMark Logo" !]
135
+ [img = src: "logo.png", alt: "Logo" !]
136
+ [input = type: "text", name: "email" !]
60
137
  ```
61
- [Read more about self-closing blocks](./docs/syntax/self-closing.md)
62
138
 
63
- ### Inline Elements
139
+ ### Compile-time JavaScript
64
140
 
65
- Apply styling or formatting to specific spans of text within a block using `(inline text)->(identifier = args)` or `(inline text)->(identifier: args)`. Internal newlines and duplicate spaces are automatically collapsed into a single space.
141
+ `${ }$` runs JavaScript at build time inside a sandboxed QuickJS VM. The `static` keyword is optional `${ expr }$` and `static ${ expr }$` are identical.
142
+
143
+ The example below targets the **HTML mapper**:
66
144
 
67
145
  ```ini
68
- [p]
69
- This is (important text)->(bold).
70
- Visit the (SomMark Website)->(link = "https://sommark.org", target: "_blank").
71
- [end]
146
+ ${
147
+ import pkg from "./package.json";
148
+ const built = new Date().toISOString();
149
+ }$
150
+
151
+ [footer]
152
+ ${ pkg.name }$ v${ pkg.version }$ — built ${ built }$
153
+ [end:footer]
72
154
  ```
73
- [Read more about inline elements](./docs/syntax/inline.md)
74
155
 
75
- ### Props (Properties)
156
+ Variables declared in one `${ }$` block are available in all blocks that follow in the same file.
76
157
 
77
- Pass metadata (called **Props**, similar to component properties in React/Vue) to Blocks, Inline Elements, and At-Blocks. SomMark supports positional, named, and mixed props with multiple value types (JS data, placeholders, and variables).
158
+ ### Loops
78
159
 
79
- > [!NOTE]
80
- > In the current major version, SomMark passes these properties under the **`args`** key to custom JavaScript `render` functions for backward compatibility. This will be renamed to `props` in the next major version.
160
+ `[for-each]` iterates over any array. The current item is accessed via the `as:` alias. `${ i }$` gives the zero-based index.
81
161
 
82
- * **Blocks**: Passed after `=` (e.g., `[div = "container"][end]`).
83
- * **Inline Elements**: Passed after `=` or `:` inside the identifier parenthesis (e.g., `(text)->(link = "url")`).
84
- * **At-Blocks**: Passed after `:` and terminated with `;` (e.g., `@_code: lang: "js";`).
162
+ The example below targets the **HTML mapper**:
85
163
 
86
- **Blocks** — props come after `=`, separated by commas. Positional args have no key; named args use `key: value`.
87
164
  ```ini
88
- [div = "container", class: "flex"][end]
89
- # ↑ positional ↑ named
165
+ ${
166
+ const links = ["Home", "Docs", "Blog", "Contact"];
167
+ }$
168
+
169
+ [nav]
170
+ [ul]
171
+ [for-each = ${ links }$, as: "link"]
172
+ [li][a = href: "#"]${ link }$[end:a][end:li]
173
+ [end:for-each]
174
+ [end:ul]
175
+ [end:nav]
90
176
  ```
91
177
 
92
- **Inline Elements** — same prop syntax, after `=` or `:` inside the identifier.
93
- ```ini
94
- (Visit Website)->(link = "https://sommark.org", target: "_blank")
95
- # ↑ positional url ↑ named prop
178
+ ```html
179
+ <nav>
180
+ <ul>
181
+ <li><a href="#">Home</a></li>
182
+ <li><a href="#">Docs</a></li>
183
+ <li><a href="#">Blog</a></li>
184
+ <li><a href="#">Contact</a></li>
185
+ </ul>
186
+ </nav>
96
187
  ```
97
188
 
98
- **At-Blocks** props follow `:` on the opening line and are terminated with `;`. The body is captured as raw text.
99
- ```ini
100
- @_code: lang: "js", active: js{true}, user: v{userId};
101
- # ↑ string ↑ native JS value ↑ local variable
102
- console.log("Hello World");
103
- @_end_@
104
- ```
189
+ ### Shorthand key-value for data formats
190
+
191
+ When targeting JSON, YAML, or TOML, write key-value pairs using the tag name as the key. Type is inferred automatically — numbers stay numbers, `true`/`false` become booleans, everything else becomes a string.
192
+
193
+ The example below targets the **JSON mapper**:
105
194
 
106
- **Static logic as a prop value** — any prop value can be a compile-time expression.
107
195
  ```ini
108
- [Date = year: static ${ new Date().getFullYear() }$][end]
196
+ [Object]
197
+ [username = "Adam" !]
198
+ [age = 25 !]
199
+ [score = 9.8 !]
200
+ [isAdmin = false !]
201
+ [deletedAt = null !]
202
+ [end:Object]
109
203
  ```
110
204
 
111
- ### At-Blocks -- Raw Content
205
+ ```json
206
+ {
207
+ "username": "Adam",
208
+ "age": 25,
209
+ "score": 9.8,
210
+ "isAdmin": false,
211
+ "deletedAt": null
212
+ }
213
+ ```
112
214
 
113
- At-blocks capture raw text. Brackets, tags, and comments inside them are treated as literal characters and never parsed.
215
+ Body form also works useful for longer values:
114
216
 
115
217
  ```ini
116
- @_code_@: lang: "javascript";
117
- const items = [1, 2, 3];
118
- // This [div] won't be parsed
119
- @_end_@
218
+ [Object]
219
+ [bio]Software developer based in Hargeisa.[end:bio]
220
+ [end:Object]
120
221
  ```
121
222
 
122
- ### Comments
123
-
124
- Single-line and multi-line. Completely removed from the compiled output.
223
+ Generate config from data with a loop. The example below targets the **YAML mapper**:
125
224
 
126
225
  ```ini
127
- # This is a single-line comment
226
+ ${
227
+ const services = [
228
+ { name: "api", port: 8080, replicas: 3 },
229
+ { name: "worker", port: 8081, replicas: 2 },
230
+ ];
231
+ }$
232
+
233
+ [seq = "services"]
234
+ [for-each = ${ services }$, as: "s"]
235
+ [map-item]
236
+ [name = ${ s.name }$ !]
237
+ [port = ${ s.port }$ !]
238
+ [replicas = ${ s.replicas }$ !]
239
+ [end:map-item]
240
+ [end:for-each]
241
+ [end:seq]
242
+ ```
128
243
 
129
- ###
130
- This is a multi-line comment.
131
- Nothing here reaches the output.
132
- ###
244
+ ```yaml
245
+ services:
246
+ - name: "api"
247
+ port: 8080
248
+ replicas: 3
249
+ - name: "worker"
250
+ port: 8081
251
+ replicas: 2
133
252
  ```
134
253
 
135
- ### Static Logic -- Compile-Time JavaScript
254
+ ### Placeholders
255
+
256
+ Inject values at build time from your JavaScript config using `p{}`. Add a fallback with `|` in case a value is not set.
136
257
 
137
- Run JavaScript during compilation inside a sandboxed QuickJS VM. The result replaces the block inline.
258
+ The example below targets the **HTML mapper**:
138
259
 
139
260
  ```ini
140
- [footer]
141
- Copyright static ${ new Date().getFullYear() }$
142
- [end]
143
- ```
261
+ [div = class: "env-badge"]
262
+ Environment: p{NODE_ENV}
263
+ [end:div]
144
264
 
145
- Use it in props too:
265
+ [footer]Built with p{engine | "SomMark"}[end:footer]
266
+ ```
146
267
 
147
- ```ini
148
- [Date = year: static ${ new Date().getFullYear() }$][end]
268
+ ```js
269
+ new SomMark({
270
+ src,
271
+ format: "html",
272
+ placeholders: { NODE_ENV: "production" }
273
+ });
149
274
  ```
150
275
 
151
- ### Runtime Logic -- Client-Side JavaScript
276
+ ### Module system
277
+
278
+ Split templates into reusable `.smark` files. All `[import]` declarations must appear at the top of the file.
152
279
 
153
- Preserve JavaScript in the compiled output. It runs in the browser, not during compilation.
280
+ **Static injection** insert a module with no props or body content:
154
281
 
155
282
  ```ini
156
- [button]
157
- runtime ${
158
- self.addEventListener("click", () => alert("Hello from SomMark"))
159
- }$
160
- Click Me
161
- [end]
283
+ [import = Nav: "./components/Nav.smark" !]
284
+ [import = Footer: "./components/Footer.smark" !]
285
+
286
+ [body]
287
+ [$use-module = Nav !]
288
+ [main]
289
+ [p]Page content.[end:p]
290
+ [end:main]
291
+ [$use-module = Footer !]
292
+ [end:body]
162
293
  ```
163
294
 
164
- ### For-Each Loop
165
-
166
- Iterate over arrays and render blocks for each item. Access the current item and its index.
295
+ **Component block** — pass props and body content. Inside the component, `v{}` reads the props and `[slot]` marks where the body goes:
167
296
 
168
297
  ```ini
169
- [for-each = static ${ [{name: "Adam"}, {name: "Hawa"}, {name: "Ilham"}] }$, as: "user"]
170
- [li]static ${ user.name }$ -- position static ${ user_index }$[end]
171
- [end]
172
- ```
298
+ [import = Card: "./components/Card.smark" !]
173
299
 
174
- ### Modules and Components
300
+ [Card = title: "Featured Post"]
301
+ This content fills the slot inside the card.
302
+ [end:Card]
303
+ ```
175
304
 
176
- Split your project into reusable `.smark` files. Import them, pass props, and inject body content through slots.
305
+ `Card.smark`:
177
306
 
178
- **`components/Card.smark`**
179
307
  ```ini
180
308
  [div = class: "card"]
181
- [h2]v{title}[end]
182
- [div = class: "card-body"]
183
- [slot][end]
184
- [end]
185
- [end]
309
+ [h2]v{title}[end:h2]
310
+ [div = class: "body"]
311
+ [slot!]
312
+ [end:div]
313
+ [end:div]
186
314
  ```
187
315
 
188
- **`page.smark`**
189
- ```ini
190
- [import = Card: "./components/Card.smark"][end]
191
-
192
- [Card = title: "Featured Product"]
193
- This content fills the slot inside the card.
194
- [end]
195
- ```
316
+ ### Comments
196
317
 
197
- You can also inject a module without passing body content:
318
+ Completely removed at build time never appear in the output:
198
319
 
199
320
  ```ini
200
- [import = Card: "./components/Card.smark"][end]
201
- [$use-module = Card][end]
321
+ # single-line comment
322
+
323
+ ###
324
+ multi-line comment
325
+ write as much as you need
326
+ ###
202
327
  ```
203
328
 
204
329
  ---
205
330
 
206
- ## Output Formats
331
+ ## CLI
207
332
 
208
- Write once, compile to any of these:
333
+ ### Global
209
334
 
210
- | Format | CLI Flag | Extension |
211
- |----------|--------------|-----------|
212
- | HTML | `--html` | `.html` |
213
- | Markdown | `--markdown` | `.md` |
214
- | MDX | `--mdx` | `.mdx` |
215
- | JSON | `--json` | `.json` |
216
- | JSONC | `--jsonc` | `.jsonc` |
217
- | XML | `--xml` | `.xml` |
218
- | Text | `--text` | `.txt` |
335
+ ```bash
336
+ sommark -h, --help # show help message
337
+ sommark -v, --version # show version
338
+ sommark init # generate smark.config.js
339
+ sommark show config [file] # show resolved config
340
+ sommark show --path-config [file] # show path to active config file
341
+ sommark color on|off # help on enabling terminal colors
342
+ ```
219
343
 
220
- ---
344
+ ### Transpile
221
345
 
222
- ## CLI
346
+ ```bash
347
+ sommark --html input.smark # compile to HTML
348
+ sommark --markdown input.smark # compile to Markdown
349
+ sommark --mdx input.smark # compile to MDX
350
+ sommark --xml input.smark # compile to XML
351
+ sommark --json input.smark # compile to JSON
352
+ sommark --jsonc input.smark # compile to JSONC
353
+ sommark --toml input.smark # compile to TOML
354
+ sommark --yaml input.smark # compile to YAML
355
+ sommark --csv input.smark # compile to CSV
356
+ sommark --text input.smark # compile to plain text
357
+ sommark --lex input.smark # print lexer token stream
358
+ sommark --parse input.smark # print parser AST
359
+ ```
360
+
361
+ ### Output
223
362
 
363
+ ```bash
364
+ sommark --html -p input.smark # print output to console
365
+ sommark --html input.smark -o name ./dir/ # set output filename and directory
224
366
  ```
225
- sommark init Create a smark.config.js file
226
- sommark --html <file> Compile to HTML
227
- sommark --markdown <file> Compile to Markdown
228
- sommark --html <file> -o <name> <dir> Set output filename and directory
229
- sommark --html --print <file> Print compiled output to terminal
230
- sommark --lex <file> Show the token stream
231
- sommark --parse <file> Show the syntax tree
232
- sommark show config [file] Show the resolved configuration
233
- sommark -v Show version
234
- sommark -h Show help
367
+
368
+ ### Browser bundle
369
+
370
+ ```bash
371
+ sommark bundle ./dist/ # copy full bundle (JS + WASM)
372
+ sommark bundle ./dist/ --lite # lite bundle no WASM
373
+ sommark bundle ./dist/ --only-lexer # lexer only
374
+ sommark bundle ./dist/ --only-parser # lexer + parser only
235
375
  ```
236
376
 
237
377
  ---
238
378
 
239
- ## Programmatic Usage
379
+ ## Programmatic API
240
380
 
241
381
  **Node.js**
242
382
  ```js
243
383
  import SomMark from "sommark";
244
384
 
245
- const engine = new SomMark({
246
- src: '[h1]Hello World[end]',
385
+ const sm = new SomMark({
386
+ src,
247
387
  format: "html",
388
+ placeholders: { title: "My App" }
248
389
  });
249
390
 
250
- const output = await engine.transpile();
251
- // <h1>Hello World</h1>
391
+ const output = await sm.transpile();
252
392
  ```
253
393
 
254
- **Browser** (v4.2.0+)
394
+ **Browser**
255
395
  ```js
256
396
  import SomMark, { resolveBaseDir, renderCompiledHTML } from "sommark/browser";
257
397
 
258
398
  const src = await fetch("./main.smark").then(r => r.text());
259
399
 
260
- const engine = new SomMark({
400
+ const sm = new SomMark({
261
401
  src,
262
402
  format: "html",
263
- baseDir: resolveBaseDir("./templates/"), // resolves imports via fetch
403
+ baseDir: resolveBaseDir("./templates/"),
264
404
  });
265
405
 
266
- renderCompiledHTML(document.getElementById("output"), await engine.transpile());
406
+ renderCompiledHTML(document.getElementById("app"), await sm.transpile());
267
407
  ```
268
408
 
269
409
  ---
270
410
 
271
411
  ## Configuration
272
412
 
273
- Run `sommark init` to generate a `smark.config.js` with all available settings:
413
+ Run `sommark init` to generate `smark.config.js`:
274
414
 
275
415
  ```js
276
416
  export default {
277
417
  format: "html",
278
418
  removeComments: true,
279
- generateRuntimeOutput: false,
280
- hideRuntimeOutput: false,
281
- customProps: [],
282
419
  placeholders: {},
283
420
  importAliases: { "@": "./" },
284
- fallbackTarget: "style",
421
+ fallbackTarget: true,
285
422
  outputValidator: null,
286
423
  baseDir: null,
287
424
  showSpinner: true,
@@ -304,62 +441,61 @@ export default {
304
441
 
305
442
  ## Security
306
443
 
307
- All embedded JavaScript runs inside a **QuickJS sandbox** with strict restrictions:
444
+ All `${ }$` expressions run inside a **QuickJS sandbox** isolated from the host process:
308
445
 
309
- | Setting | Default | What it does |
310
- |---------------------|---------|----------------------------------------------|
311
- | `allowRaw` | `true` | Allow raw code in static blocks |
312
- | `maxDepth` | `5` | Maximum import nesting depth |
313
- | `timeout` | `5000` | Script execution time limit (ms) |
314
- | `allowFetch` | `true` | Allow network requests from scripts |
315
- | `allowHttp` | `false` | Block insecure HTTP (HTTPS only by default) |
316
- | `allowedOrigins` | `null` | Restrict fetch to specific domains |
317
- | `allowedExtensions` | `null` | Restrict which file types can be imported |
318
- | `sanitize` | `null` | Custom function to sanitize HTML output |
446
+ | Setting | Default | Description |
447
+ | ------------------- | ------- | ----------------------------------------- |
448
+ | `allowRaw` | `true` | Allow JavaScript in compile-time blocks |
449
+ | `maxDepth` | `5` | Maximum import nesting depth |
450
+ | `timeout` | `5000` | Max execution time per script (ms) |
451
+ | `allowFetch` | `true` | Allow network requests from scripts |
452
+ | `allowHttp` | `false` | Block plain HTTP HTTPS only by default |
453
+ | `allowedOrigins` | `[]` | Restrict fetch to specific domains |
454
+ | `allowedExtensions` | `[]` | Restrict which file types can be imported |
455
+ | `sanitize` | `null` | Custom function to sanitize HTML output |
319
456
 
320
457
  ---
321
458
 
322
- ## Custom Output Rules
459
+ ## Custom mappers
323
460
 
324
461
  Define your own tags and rendering logic with the Mapper API:
325
462
 
326
463
  ```js
327
464
  import SomMark, { Mapper } from "sommark";
328
465
 
329
- const mapper = new Mapper("custom");
466
+ const mapper = new Mapper();
330
467
 
331
- mapper.register("alert", (node) => {
332
- return `<div class="alert">${node.body}</div>`;
468
+ mapper.register("alert", function({ content, props }) {
469
+ const type = props.type || "info";
470
+ return `<div class="alert alert-${type}">${content}</div>`;
333
471
  });
334
472
 
335
- const engine = new SomMark({
336
- src: '[alert]Check your configuration.[end]',
473
+ const sm = new SomMark({
474
+ src: `[alert = type: "warning"]Check your config.[end:alert]`,
337
475
  format: "html",
338
476
  mapperFile: mapper,
339
477
  });
340
-
341
- const output = await engine.transpile();
342
478
  ```
343
479
 
344
- Full reference in [`docs/api/Mapper`](docs/api/Mapper).
480
+ Full reference: [`docs/api/Mapper`](docs/api/Mapper)
345
481
 
346
482
  ---
347
483
 
348
484
  ## Documentation
349
485
 
350
- | Topic | Location |
351
- |------------------|-----------------------------------------------|
352
- | Syntax Reference | [`docs/syntax/`](docs/syntax) |
353
- | Core API | [`docs/api/Core/`](docs/api/Core) |
354
- | Browser API | [`docs/api/Browser/`](docs/api/Browser) |
355
- | Mapper API | [`docs/api/Mapper/`](docs/api/Mapper) |
356
- | Sandbox API | [`docs/api/Sandbox/`](docs/api/Sandbox) |
357
- | Output Formats | [`docs/languages/`](docs/languages) |
358
- | CLI Guide | [`docs/cli/`](docs/cli) |
359
- | Configuration | [`docs/cli/config.md`](docs/cli/config.md) |
486
+ | Topic | Location |
487
+ | ---------------- | ------------------------------------------ |
488
+ | Syntax Reference | [`docs/syntax/`](docs/syntax) |
489
+ | Output Formats | [`docs/languages/`](docs/languages) |
490
+ | Core API | [`docs/api/Core/`](docs/api/Core) |
491
+ | Browser API | [`docs/api/Browser/`](docs/api/Browser) |
492
+ | Mapper API | [`docs/api/Mapper/`](docs/api/Mapper) |
493
+ | Sandbox API | [`docs/api/Sandbox/`](docs/api/Sandbox) |
494
+ | CLI Guide | [`docs/cli/`](docs/cli) |
495
+ | Configuration | [`docs/cli/config.md`](docs/cli/config.md) |
360
496
 
361
497
  ---
362
498
 
363
499
  ## License
364
500
 
365
- [MIT](LICENSE) -- Adam Elmi
501
+ [MIT](LICENSE) Adam Elmi
package/cli/cli.mjs CHANGED
@@ -76,7 +76,7 @@ async function main() {
76
76
 
77
77
  // 5.5. Color
78
78
  if (command === "color") {
79
- runColor(args[1]);
79
+ await runColor(args[1]);
80
80
  return;
81
81
  }
82
82