sommark 4.0.3 → 4.2.0
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 +304 -73
- package/cli/cli.mjs +1 -1
- package/cli/commands/build.js +3 -1
- package/cli/commands/help.js +2 -0
- package/cli/commands/init.js +25 -6
- package/cli/constants.js +2 -1
- package/cli/helpers/transpile.js +5 -2
- package/constants/html_props.js +1 -0
- package/core/evaluator.js +1061 -0
- package/core/formats.js +15 -7
- package/core/helpers/config-loader.js +16 -8
- package/core/helpers/lib.js +72 -0
- package/core/helpers/preprocessor.js +202 -0
- package/core/helpers/runtimeOutput.js +28 -0
- package/core/helpers/url.js +12 -0
- package/core/labels.js +9 -2
- package/core/lexer.js +228 -61
- package/core/modules.js +338 -60
- package/core/parser.js +275 -55
- package/core/tokenTypes.js +11 -0
- package/core/transpiler.js +352 -66
- package/core/validator.js +70 -7
- package/formatter/tag.js +31 -7
- package/grammar.ebnf +21 -10
- package/helpers/fetch-fs.js +37 -0
- package/helpers/safeDataParser.js +3 -3
- package/helpers/spinner.js +97 -0
- package/helpers/utils.js +46 -0
- package/helpers/virtual-fs.js +29 -0
- package/index.browser.js +87 -0
- package/index.js +23 -332
- package/index.shared.js +443 -0
- package/mappers/languages/html.js +50 -9
- package/mappers/languages/json.js +81 -38
- package/mappers/languages/jsonc.js +82 -0
- package/mappers/languages/markdown.js +88 -48
- package/mappers/languages/mdx.js +50 -15
- package/mappers/languages/text.js +67 -0
- package/mappers/languages/xml.js +6 -6
- package/mappers/mapper.js +36 -4
- package/mappers/shared/index.js +12 -13
- package/package.json +11 -2
- package/core/formatter.js +0 -215
package/README.md
CHANGED
|
@@ -1,134 +1,365 @@
|
|
|
1
|
-
# SomMark
|
|
1
|
+
# SomMark <img src="assets/smark.logo.png" width="80" align="right">
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/sommark)
|
|
4
|
+
[](https://www.npmjs.com/package/sommark)
|
|
5
|
+
[](https://nodejs.org)
|
|
4
6
|
[](https://github.com/Adam-Elmi/SomMark/blob/master/LICENSE)
|
|
5
7
|
|
|
6
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.
|
|
7
9
|
|
|
8
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.
|
|
9
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`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
#### 1. Global (Command Line)
|
|
19
|
+
Install SomMark globally to use the `sommark` command.
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g sommark
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To verify it is working, check the version:
|
|
25
|
+
```bash
|
|
26
|
+
sommark --version
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### 2. Local (Project API)
|
|
30
|
+
Add SomMark to your project as a dependency:
|
|
31
|
+
```bash
|
|
32
|
+
npm install sommark
|
|
33
|
+
```
|
|
34
|
+
|
|
10
35
|
---
|
|
11
36
|
|
|
12
|
-
##
|
|
37
|
+
## Features
|
|
13
38
|
|
|
14
|
-
|
|
39
|
+
### Blocks
|
|
40
|
+
|
|
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" !]`.
|
|
15
42
|
|
|
16
|
-
### HTML
|
|
17
43
|
```ini
|
|
18
|
-
[
|
|
44
|
+
[div = class: "container"]
|
|
45
|
+
[h1]Welcome to SomMark[end]
|
|
46
|
+
[p]Structured content, zero guesswork.[end]
|
|
47
|
+
[hr = class: "divider" !]
|
|
48
|
+
[end]
|
|
49
|
+
```
|
|
50
|
+
[Read more about blocks](./docs/syntax/block.md)
|
|
19
51
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
52
|
+
### Self-Closing Blocks
|
|
53
|
+
|
|
54
|
+
Blocks that carry no body content close instantly with `!`.
|
|
55
|
+
|
|
56
|
+
```ini
|
|
57
|
+
[br!]
|
|
58
|
+
[hr = class: "divider" !]
|
|
59
|
+
[img = src: "logo.png", alt: "SomMark Logo" !]
|
|
60
|
+
```
|
|
61
|
+
[Read more about self-closing blocks](./docs/syntax/self-closing.md)
|
|
62
|
+
|
|
63
|
+
### Inline Elements
|
|
64
|
+
|
|
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.
|
|
66
|
+
|
|
67
|
+
```ini
|
|
68
|
+
[p]
|
|
69
|
+
This is (important text)->(bold).
|
|
70
|
+
Visit the (SomMark Website)->(link = "https://sommark.org", target: "_blank").
|
|
26
71
|
[end]
|
|
27
72
|
```
|
|
73
|
+
[Read more about inline elements](./docs/syntax/inline.md)
|
|
74
|
+
|
|
75
|
+
### Props (Properties)
|
|
76
|
+
|
|
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).
|
|
78
|
+
|
|
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.
|
|
81
|
+
|
|
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";`).
|
|
85
|
+
|
|
86
|
+
**Blocks** — props come after `=`, separated by commas. Positional args have no key; named args use `key: value`.
|
|
87
|
+
```ini
|
|
88
|
+
[div = "container", class: "flex"][end]
|
|
89
|
+
# ↑ positional ↑ named
|
|
90
|
+
```
|
|
28
91
|
|
|
29
|
-
|
|
30
|
-
SomMark can represent complex data structures through its specialized mappers.
|
|
92
|
+
**Inline Elements** — same prop syntax, after `=` or `:` inside the identifier.
|
|
31
93
|
```ini
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
94
|
+
(Visit Website)->(link = "https://sommark.org", target: "_blank")
|
|
95
|
+
# ↑ positional url ↑ named prop
|
|
96
|
+
```
|
|
97
|
+
|
|
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
|
+
```
|
|
105
|
+
|
|
106
|
+
**Static logic as a prop value** — any prop value can be a compile-time expression.
|
|
107
|
+
```ini
|
|
108
|
+
[Date = year: static ${ new Date().getFullYear() }$][end]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### At-Blocks -- Raw Content
|
|
112
|
+
|
|
113
|
+
At-blocks capture raw text. Brackets, tags, and comments inside them are treated as literal characters and never parsed.
|
|
114
|
+
|
|
115
|
+
```ini
|
|
116
|
+
@_code_@: lang: "javascript";
|
|
117
|
+
const items = [1, 2, 3];
|
|
118
|
+
// This [div] won't be parsed
|
|
119
|
+
@_end_@
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Comments
|
|
123
|
+
|
|
124
|
+
Single-line and multi-line. Completely removed from the compiled output.
|
|
125
|
+
|
|
126
|
+
```ini
|
|
127
|
+
# This is a single-line comment
|
|
128
|
+
|
|
129
|
+
###
|
|
130
|
+
This is a multi-line comment.
|
|
131
|
+
Nothing here reaches the output.
|
|
132
|
+
###
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Static Logic -- Compile-Time JavaScript
|
|
136
|
+
|
|
137
|
+
Run JavaScript during compilation inside a sandboxed QuickJS VM. The result replaces the block inline.
|
|
138
|
+
|
|
139
|
+
```ini
|
|
140
|
+
[footer]
|
|
141
|
+
Copyright static ${ new Date().getFullYear() }$
|
|
39
142
|
[end]
|
|
40
143
|
```
|
|
41
144
|
|
|
42
|
-
|
|
43
|
-
|
|
145
|
+
Use it in props too:
|
|
146
|
+
|
|
44
147
|
```ini
|
|
45
|
-
[
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
[Date = year: static ${ new Date().getFullYear() }$][end]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Runtime Logic -- Client-Side JavaScript
|
|
152
|
+
|
|
153
|
+
Preserve JavaScript in the compiled output. It runs in the browser, not during compilation.
|
|
154
|
+
|
|
155
|
+
```ini
|
|
156
|
+
[button]
|
|
157
|
+
runtime ${
|
|
158
|
+
self.addEventListener("click", () => alert("Hello from SomMark"))
|
|
159
|
+
}$
|
|
160
|
+
Click Me
|
|
57
161
|
[end]
|
|
58
162
|
```
|
|
59
163
|
|
|
60
|
-
###
|
|
61
|
-
|
|
164
|
+
### For-Each Loop
|
|
165
|
+
|
|
166
|
+
Iterate over arrays and render blocks for each item. Access the current item and its index.
|
|
167
|
+
|
|
62
168
|
```ini
|
|
63
|
-
[
|
|
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
|
+
```
|
|
173
|
+
|
|
174
|
+
### Modules and Components
|
|
175
|
+
|
|
176
|
+
Split your project into reusable `.smark` files. Import them, pass props, and inject body content through slots.
|
|
64
177
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
]
|
|
69
|
-
|
|
178
|
+
**`components/Card.smark`**
|
|
179
|
+
```ini
|
|
180
|
+
[div = class: "card"]
|
|
181
|
+
[h2]v{title}[end]
|
|
182
|
+
[div = class: "card-body"]
|
|
183
|
+
[slot][end]
|
|
184
|
+
[end]
|
|
70
185
|
[end]
|
|
71
186
|
```
|
|
72
187
|
|
|
73
|
-
|
|
74
|
-
Use placeholders to inject dynamic text into your templates.
|
|
188
|
+
**`page.smark`**
|
|
75
189
|
```ini
|
|
76
|
-
[
|
|
190
|
+
[import = Card: "./components/Card.smark"][end]
|
|
77
191
|
|
|
78
|
-
[
|
|
79
|
-
|
|
80
|
-
SomMark is an extensible language.
|
|
192
|
+
[Card = title: "Featured Product"]
|
|
193
|
+
This content fills the slot inside the card.
|
|
81
194
|
[end]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
You can also inject a module without passing body content:
|
|
82
198
|
|
|
83
|
-
|
|
199
|
+
```ini
|
|
200
|
+
[import = Card: "./components/Card.smark"][end]
|
|
201
|
+
[$use-module = Card][end]
|
|
84
202
|
```
|
|
85
203
|
|
|
86
204
|
---
|
|
87
205
|
|
|
88
|
-
##
|
|
89
|
-
|
|
90
|
-
SomMark is an extensible language that processes content through a four-stage pipeline:
|
|
206
|
+
## Output Formats
|
|
91
207
|
|
|
92
|
-
|
|
93
|
-
2. **Parsing**: Tokens are organized into a hierarchical tree called an **AST** (Abstract Syntax Tree).
|
|
94
|
-
3. **Mapping**: This is the translation layer. You define how identifiers (like `[h1]`) look in the target language.
|
|
95
|
-
4. **Transpilation**: The engine walks the AST and uses the Mapper to generate the final string output.
|
|
208
|
+
Write once, compile to any of these:
|
|
96
209
|
|
|
97
|
-
|
|
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` |
|
|
98
219
|
|
|
99
220
|
---
|
|
100
221
|
|
|
101
|
-
##
|
|
102
|
-
|
|
103
|
-
Install the SomMark CLI globally:
|
|
222
|
+
## CLI
|
|
104
223
|
|
|
105
|
-
```
|
|
106
|
-
|
|
224
|
+
```
|
|
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
|
|
107
235
|
```
|
|
108
236
|
|
|
109
237
|
---
|
|
110
238
|
|
|
111
|
-
## Usage
|
|
239
|
+
## Programmatic Usage
|
|
112
240
|
|
|
113
|
-
|
|
241
|
+
**Node.js**
|
|
242
|
+
```js
|
|
114
243
|
import SomMark from "sommark";
|
|
115
244
|
|
|
116
|
-
const
|
|
117
|
-
src:
|
|
118
|
-
format: "html"
|
|
245
|
+
const engine = new SomMark({
|
|
246
|
+
src: '[h1]Hello World[end]',
|
|
247
|
+
format: "html",
|
|
119
248
|
});
|
|
120
249
|
|
|
121
|
-
const output = await
|
|
250
|
+
const output = await engine.transpile();
|
|
122
251
|
// <h1>Hello World</h1>
|
|
123
252
|
```
|
|
124
253
|
|
|
254
|
+
**Browser** (v4.2.0+)
|
|
255
|
+
```js
|
|
256
|
+
import SomMark, { resolveBaseDir, renderCompiledHTML } from "sommark/browser";
|
|
257
|
+
|
|
258
|
+
const src = await fetch("./main.smark").then(r => r.text());
|
|
259
|
+
|
|
260
|
+
const engine = new SomMark({
|
|
261
|
+
src,
|
|
262
|
+
format: "html",
|
|
263
|
+
baseDir: resolveBaseDir("./templates/"), // resolves imports via fetch
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
renderCompiledHTML(document.getElementById("output"), await engine.transpile());
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Configuration
|
|
272
|
+
|
|
273
|
+
Run `sommark init` to generate a `smark.config.js` with all available settings:
|
|
274
|
+
|
|
275
|
+
```js
|
|
276
|
+
export default {
|
|
277
|
+
format: "html",
|
|
278
|
+
removeComments: true,
|
|
279
|
+
generateRuntimeOutput: false,
|
|
280
|
+
hideRuntimeOutput: false,
|
|
281
|
+
customProps: [],
|
|
282
|
+
placeholders: {},
|
|
283
|
+
importAliases: { "@": "./" },
|
|
284
|
+
fallbackTarget: "style",
|
|
285
|
+
outputValidator: null,
|
|
286
|
+
baseDir: null,
|
|
287
|
+
showSpinner: true,
|
|
288
|
+
security: {
|
|
289
|
+
allowRaw: true,
|
|
290
|
+
maxDepth: 5,
|
|
291
|
+
timeout: 5000,
|
|
292
|
+
allowFetch: true,
|
|
293
|
+
allowHttp: false,
|
|
294
|
+
allowedOrigins: [],
|
|
295
|
+
allowedExtensions: [],
|
|
296
|
+
sanitize: null,
|
|
297
|
+
},
|
|
298
|
+
outputDir: "./",
|
|
299
|
+
outputFile: "output",
|
|
300
|
+
};
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Security
|
|
306
|
+
|
|
307
|
+
All embedded JavaScript runs inside a **QuickJS sandbox** with strict restrictions:
|
|
308
|
+
|
|
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 |
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Custom Output Rules
|
|
323
|
+
|
|
324
|
+
Define your own tags and rendering logic with the Mapper API:
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
import SomMark, { Mapper } from "sommark";
|
|
328
|
+
|
|
329
|
+
const mapper = new Mapper("custom");
|
|
330
|
+
|
|
331
|
+
mapper.register("alert", (node) => {
|
|
332
|
+
return `<div class="alert">${node.body}</div>`;
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const engine = new SomMark({
|
|
336
|
+
src: '[alert]Check your configuration.[end]',
|
|
337
|
+
format: "html",
|
|
338
|
+
mapperFile: mapper,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const output = await engine.transpile();
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Full reference in [`docs/api/Mapper`](docs/api/Mapper).
|
|
345
|
+
|
|
125
346
|
---
|
|
126
347
|
|
|
127
348
|
## Documentation
|
|
128
349
|
|
|
129
|
-
|
|
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) |
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## License
|
|
130
364
|
|
|
131
|
-
|
|
132
|
-
* **[Core Logic](docs/core/core.md)**: Deep dive into the engine architecture.
|
|
133
|
-
* **[Mapper API](docs/core/mapper.md)**: How to create your own translation layers.
|
|
134
|
-
* **[Module System](docs/core/module-system.md)**: Managing multi-file projects.
|
|
365
|
+
[MIT](LICENSE) -- Adam Elmi
|
package/cli/cli.mjs
CHANGED
package/cli/commands/build.js
CHANGED
|
@@ -5,7 +5,9 @@ import HTML from "../../mappers/languages/html.js";
|
|
|
5
5
|
import MARKDOWN from "../../mappers/languages/markdown.js";
|
|
6
6
|
import MDX from "../../mappers/languages/mdx.js";
|
|
7
7
|
import Json from "../../mappers/languages/json.js";
|
|
8
|
+
import Jsonc from "../../mappers/languages/jsonc.js";
|
|
8
9
|
import XML from "../../mappers/languages/xml.js";
|
|
10
|
+
import TEXT from "../../mappers/languages/text.js";
|
|
9
11
|
import { extensions } from "../constants.js";
|
|
10
12
|
import { isExist, readContent, createFile } from "../helpers/file.js";
|
|
11
13
|
import { loadConfig } from "../helpers/config.js";
|
|
@@ -78,7 +80,7 @@ export async function runBuild(format_option, sourcePath, outputFlag, outputFile
|
|
|
78
80
|
let mapperFile = config.mapperFile || config.mappingFile;
|
|
79
81
|
|
|
80
82
|
if (!mapperFile) {
|
|
81
|
-
mapperFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : format === "json" ? Json : format === "xml" ? XML : null;
|
|
83
|
+
mapperFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : format === "json" ? Json : format === "jsonc" ? Jsonc : format === "xml" ? XML : format === "text" ? TEXT : null;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
// CLI Overrides
|
package/cli/commands/help.js
CHANGED
|
@@ -28,7 +28,9 @@ export function getHelp(unknown_option = true) {
|
|
|
28
28
|
"{N} <$green:--html$> <$cyan: Transpile to HTML$>",
|
|
29
29
|
"{N} <$green:--markdown$> <$cyan: Transpile to Markdown$>",
|
|
30
30
|
"{N} <$green:--mdx$> <$cyan: Transpile to MDX$>",
|
|
31
|
+
"{N} <$green:--xml$> <$cyan: Transpile to XML$>",
|
|
31
32
|
"{N} <$green:--json$> <$cyan: Transpile to JSON$>",
|
|
33
|
+
"{N} <$green:--jsonc$> <$cyan: Transpile to JSON with Comments (JSONC)$>",
|
|
32
34
|
"{N} <$green:--text$> <$cyan: Transpile to plain text$>",
|
|
33
35
|
"{N} <$green:--lex$> <$cyan: Print lexer tokens to console$>",
|
|
34
36
|
"{N} <$green:--parse$> <$cyan: Print parser AST to console$>",
|
package/cli/commands/init.js
CHANGED
|
@@ -19,12 +19,31 @@ export async function runInit() {
|
|
|
19
19
|
* Generated by 'smark init'
|
|
20
20
|
*/
|
|
21
21
|
export default {
|
|
22
|
-
format: "html",
|
|
23
|
-
removeComments: true,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
format: "html", // Target output format (html, markdown, mdx, json, xml, jsonc, text)
|
|
23
|
+
removeComments: true, // Strip SomMark comments from the final output
|
|
24
|
+
generateRuntimeOutput: false, // Generate only VM script bundles, ignoring markup layouts
|
|
25
|
+
hideRuntimeOutput: false, // Strip all <script> tags from final compiled HTML outputs
|
|
26
|
+
customProps: [], // Whitelisted HTML attributes
|
|
27
|
+
placeholders: {}, // Global p{key} placeholders for content injection
|
|
28
|
+
importAliases: { // Custom path aliases for modules (e.g. { "@": "./src/components" })
|
|
29
|
+
"@": "./"
|
|
30
|
+
},
|
|
31
|
+
fallbackTarget: "style", // Where unrecognized attributes go: "style", "class", or false to disable
|
|
32
|
+
outputValidator: null, // Custom callback function: async (transpiledOutput) => { ... }
|
|
33
|
+
baseDir: null, // Base directory for resolving relative module imports
|
|
34
|
+
showSpinner: true, // Display a dynamic spinner in the terminal during transpilation
|
|
35
|
+
security: { // Sandbox and security restrictions for module execution
|
|
36
|
+
allowRaw: true, // Permit raw code blocks in static logic blocks
|
|
37
|
+
maxDepth: 5, // Maximum allowed import nesting depth
|
|
38
|
+
timeout: 5000, // Timeout in milliseconds for scripts to execute
|
|
39
|
+
allowFetch: true, // Allow fetch queries inside runtime logic block execution
|
|
40
|
+
allowHttp: false, // Disallow http requests (highly recommended to keep false)
|
|
41
|
+
allowedOrigins: [], // Whitelisted HTTP origins/domains for fetch requests (e.g. ["api.github.com"])
|
|
42
|
+
allowedExtensions: [], // Whitelisted file extensions for local module imports (e.g. [".smark", ".json"])
|
|
43
|
+
sanitize: null, // Custom output HTML string sanitization function: (html) => { ... }
|
|
44
|
+
},
|
|
45
|
+
outputDir: "./", // Where to save the transpiled files
|
|
46
|
+
outputFile: "output", // Default output filename
|
|
28
47
|
};
|
|
29
48
|
`;
|
|
30
49
|
|
package/cli/constants.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/** @type {Array<string>} List of recognized CLI flags and commands. */
|
|
7
|
-
export const options = ["-v", "--version", "-h", "--help", "--html", "--markdown", "--mdx", "--json", "--text", "--xml", "--print", "-p", "--lex", "--parse", "list"];
|
|
7
|
+
export const options = ["-v", "--version", "-h", "--help", "--html", "--markdown", "--mdx", "--json", "--jsonc", "--text", "--xml", "--print", "-p", "--lex", "--parse", "list"];
|
|
8
8
|
|
|
9
9
|
/** @type {Object<string, string>} Map of output formats to their respective file extensions. */
|
|
10
10
|
export const extensions = {
|
|
@@ -13,5 +13,6 @@ export const extensions = {
|
|
|
13
13
|
markdown: "md",
|
|
14
14
|
mdx: "mdx",
|
|
15
15
|
json: "json",
|
|
16
|
+
jsonc: "jsonc",
|
|
16
17
|
xml: "xml"
|
|
17
18
|
};
|
package/cli/helpers/transpile.js
CHANGED
|
@@ -6,11 +6,13 @@ import HTML from "../../mappers/languages/html.js";
|
|
|
6
6
|
import MARKDOWN from "../../mappers/languages/markdown.js";
|
|
7
7
|
import MDX from "../../mappers/languages/mdx.js";
|
|
8
8
|
import Json from "../../mappers/languages/json.js";
|
|
9
|
+
import Jsonc from "../../mappers/languages/jsonc.js";
|
|
10
|
+
import XML from "../../mappers/languages/xml.js";
|
|
9
11
|
import { isExist } from "./file.js";
|
|
10
12
|
import { loadConfig } from "./config.js";
|
|
11
|
-
import { htmlFormat, markdownFormat, mdxFormat, jsonFormat, textFormat } from "../../core/formats.js";
|
|
13
|
+
import { htmlFormat, markdownFormat, mdxFormat, jsonFormat, jsoncFormat, xmlFormat, textFormat } from "../../core/formats.js";
|
|
12
14
|
|
|
13
|
-
const default_mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX, [jsonFormat]: Json, [textFormat]: null };
|
|
15
|
+
const default_mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX, [jsonFormat]: Json, [jsoncFormat]: Jsonc, [xmlFormat]: XML, [textFormat]: null };
|
|
14
16
|
|
|
15
17
|
// ========================================================================== //
|
|
16
18
|
// Transpile Function //
|
|
@@ -50,6 +52,7 @@ export async function transpile({ src, format, filename = null, mapperFile = "",
|
|
|
50
52
|
format,
|
|
51
53
|
filename,
|
|
52
54
|
mapperFile: finalMapper,
|
|
55
|
+
showSpinner: finalConfig.showSpinner !== false
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
return await smark.transpile();
|