sommark 2.3.1 → 3.0.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.
Files changed (45) hide show
  1. package/README.md +47 -42
  2. package/SOMMARK-SPEC.md +483 -0
  3. package/cli/cli.mjs +42 -2
  4. package/cli/commands/color.js +36 -0
  5. package/cli/commands/help.js +7 -0
  6. package/cli/commands/init.js +2 -0
  7. package/cli/commands/list.js +119 -0
  8. package/cli/commands/print.js +61 -6
  9. package/cli/commands/show.js +24 -27
  10. package/cli/constants.js +1 -1
  11. package/cli/helpers/config.js +14 -4
  12. package/cli/helpers/transpile.js +28 -33
  13. package/constants/html_props.js +100 -0
  14. package/constants/html_tags.js +146 -0
  15. package/constants/void_elements.js +26 -0
  16. package/core/lexer.js +70 -39
  17. package/core/parser.js +102 -81
  18. package/core/pluginManager.js +139 -0
  19. package/core/plugins/comment-remover.js +47 -0
  20. package/core/plugins/module-system.js +137 -0
  21. package/core/plugins/quote-escaper.js +37 -0
  22. package/core/plugins/raw-content-plugin.js +72 -0
  23. package/core/plugins/rules-validation-plugin.js +197 -0
  24. package/core/plugins/sommark-format.js +211 -0
  25. package/core/transpiler.js +65 -198
  26. package/debug.js +9 -4
  27. package/format.js +23 -0
  28. package/formatter/mark.js +3 -3
  29. package/formatter/tag.js +6 -2
  30. package/grammar.ebnf +5 -5
  31. package/helpers/camelize.js +2 -0
  32. package/helpers/colorize.js +20 -14
  33. package/helpers/kebabize.js +2 -0
  34. package/helpers/utils.js +161 -0
  35. package/index.js +243 -44
  36. package/mappers/languages/html.js +200 -105
  37. package/mappers/languages/json.js +23 -4
  38. package/mappers/languages/markdown.js +88 -67
  39. package/mappers/languages/mdx.js +130 -2
  40. package/mappers/mapper.js +77 -246
  41. package/package.json +7 -5
  42. package/unformatted.smark +90 -0
  43. package/v3-todo.smark +75 -0
  44. package/CHANGELOG.md +0 -113
  45. package/helpers/loadCss.js +0 -46
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <img width="2000" height="491" alt="SomMark Cover" src="https://raw.githubusercontent.com/Adam-Elmi/SomMark/master/assets/smark_bg.png" />
2
2
 
3
3
  <p align="center">
4
- SomMark is a declarative, extensible markup language for structured content that can be converted to HTML, Markdown, MDX, JSON, and more.
4
+ SomMark v3 is a simple, flexible markup language for structured content.
5
5
  </p>
6
6
 
7
7
  <p align="center">
@@ -16,7 +16,7 @@ SomMark is a declarative, extensible markup language for structured content that
16
16
  </a>
17
17
 
18
18
  <!--Language Type-->
19
- <img src="https://img.shields.io/badge/type-markup%20language-white?style=flat-square" />
19
+ <img src="https://img.shields.io/badge/type-markup%20language-orange?style=flat-square" />
20
20
 
21
21
  <!--SomMark Playground-->
22
22
  <a href="https://adam-elmi.github.io/SomMark-Playground" target="_blank">
@@ -26,81 +26,86 @@ alt="SomMark Playground Badge" />
26
26
  </a>
27
27
  </p>
28
28
 
29
-
30
29
  ----
31
30
 
32
31
  ## Try SomMark Playground
33
32
 
34
- Test SomMark features live here:
33
+ Test SomMark live in your browser:
35
34
  [https://adam-elmi.github.io/SomMark-Playground/](https://adam-elmi.github.io/SomMark-Playground/)
36
35
 
37
36
  ----
38
37
 
39
- # SomMark v2
38
+ # What's new in v3?
40
39
 
41
- > [!WARNING]
42
- > Old version(v1) is no longer supported.
40
+ SomMark v3 is faster, more powerful, and easier to extend.
43
41
 
44
- **SomMark** lets you write structured content that can be converted to HTML, Markdown, JSON, or other formats. Unlike standard Markdown, it uses explicit syntax for blocks and elements, making content easier to process, customize, and transform.
42
+ - **HTML Support**: Full HTML5 Support
43
+ - **Markdown Support**: Full Markdown Support
44
+ - **JSON Support**: Full JSON Support
45
+ - **MDX Support**: Full MDX Support
46
+ - **Plugin System**: Add new features without changing the core code.
47
+ - **Modular Support**: Easily import files and use variables.
48
+ - **Type-Safe Rules**: Set requirements for tags and attributes.
49
+ - **Clean Syntax**: Simplified block, atblock & inline rules and better error handling.
45
50
 
46
51
  # Installation
47
52
 
48
- To install the Command Line Interface (CLI) globally:
49
-
50
53
  ```bash
51
54
  npm install -g sommark
52
55
  ```
53
56
 
54
57
  # Usage
55
58
 
56
- ## Using the CLI
59
+ ## v3 Syntax Example
57
60
 
58
- You can convert files using the terminal.
61
+ SomMark is designed to be readable and clear.
59
62
 
60
- ```bash
61
- # Convert to HTML
62
- sommark --html input.smark -o output
63
+ ```ini
64
+ # Html
65
+ [h1]Welcome to SomMark v3[end]
63
66
 
64
- # Convert to Markdown
65
- sommark --markdown input.smark -o output.md
66
- ```
67
+ [section = class: "hero", id: "main"]
68
+ [a = href: "https://sommark.org"]Visit Website[end]
69
+ [end]
70
+
71
+ # Markdown
72
+ [quote]
73
+ SomMark is simple and powerful.
74
+ [end]
75
+
76
+ [bold]Check out our syntax guide![end]
67
77
 
68
- ## Using in Code
78
+ # Json
79
+ [Json= object]
80
+ [Object = "user"]
81
+ (name)->(string: "Adam Elmi")
82
+ (age)->(number: 25)
83
+ (is_active_user)->(bool: true)
84
+ [end]
85
+ [end]
86
+ ```
69
87
 
70
- You can use SomMark in your JavaScript or Node.js projects.
88
+ ## Using in JavaScript
71
89
 
72
90
  ```javascript
73
91
  import SomMark from "sommark";
74
92
 
75
- const source = `
76
- [Block]
77
- Hello World
78
- [end]
79
- `;
80
-
81
93
  const smark = new SomMark({
82
- src: source,
94
+ src: '[h1]Hello World[end]',
83
95
  format: "html"
84
96
  });
85
97
 
86
98
  console.log(await smark.transpile());
87
99
  ```
88
100
 
89
- ## Supported Languages
90
-
91
- * HTML
92
- * Markdown
93
- * MDX (Only ready components)
94
- * JSON
95
-
96
-
97
101
  # Documentation
98
102
 
99
- Detailed guides and API references are available in the `docs/` directory:
103
+ Read our detailed guides in the `docs/` folder:
100
104
 
101
- - **[Syntax Guide](docs/03.syntax.md)**: Master SomMark syntax (Blocks, Inline, At-Blocks).
102
- - **[Core API](docs/09.core.md)**: Programmatic usage of the library (`transpile`, `lex`, `parse`).
103
- - **[Mapper API](docs/13.mapper.md)**: Guide for creating custom mappers and rules.
104
- - **[CLI Reference](docs/11.cli.md)**: Command line options and configurations.
105
- - **[API Quick Reference](docs/api)**: Fast lookup for all classes and functions.
106
- - **[Configuration Reference](docs/12.config.md)**: Guide for creating custom configurations.
105
+ - **[Syntax Guide](docs/03.syntax.md)**: How to write SomMark (Blocks, Inline, At-Blocks).
106
+ - **[Plugin System](docs/19.plugin-system.md)**: How to create your own plugins.
107
+ - **[Built-in Plugins](docs/20.built-in-plugins.md)**: Guide to standard plugins.
108
+ - **[Core API](docs/09.core.md)**: How to use SomMark in your code.
109
+ - **[Mapper API](docs/13.mapper.md)**: How to create new output formats.
110
+ - **[CLI Reference](docs/11.cli.md)**: Terminal commands and flags.
111
+ - **[API Quick Reference](docs/api)**: Fast lookup for all functions.
@@ -0,0 +1,483 @@
1
+ # SomMark Specification
2
+
3
+ **SomMark** is a lightweight structured markup language designed to support hierarchical content, inline transformations, and raw text embedding.
4
+
5
+ SomMark provides three primary constructs:
6
+
7
+ 1. **Blocks** – hierarchical containers that support nesting
8
+ 2. **Inline Statements** – inline value transformations
9
+ 3. **AtBlocks** – raw text containers where parsing is disabled
10
+
11
+ Additionally, SomMark supports **comments** and **escape sequences**.
12
+
13
+ ---
14
+
15
+ # 1. Identifiers
16
+
17
+ Identifiers are used to name **Blocks**, **Inline Statements**, and **AtBlocks**.
18
+
19
+ ## Allowed Characters
20
+
21
+ Identifiers may contain:
22
+
23
+ * Letters (`a-z`, `A-Z`)
24
+ * Numbers (`0-9`)
25
+ * Dollar sign (`$`)
26
+ * Underscore (`_`)
27
+ * Hyphen (`-`)
28
+
29
+ Example valid identifiers:
30
+
31
+ ```
32
+ Block
33
+ section-1
34
+ user_profile
35
+ $template
36
+ note-2
37
+ ```
38
+
39
+ Example invalid identifiers:
40
+
41
+ ```
42
+ my block
43
+ test@
44
+ hello!
45
+ ```
46
+
47
+ Identifiers **must not contain spaces**.
48
+
49
+ ---
50
+
51
+ # 2. Blocks
52
+
53
+ > At the top level, only Blocks and comments are permitted.
54
+
55
+
56
+ Blocks are hierarchical containers that can contain other blocks, inline statements, or plain text.
57
+
58
+ Blocks are the primary structural element of SomMark.
59
+
60
+ ## Block Syntax
61
+
62
+ ### Block with Arguments
63
+
64
+ ```
65
+ [Identifier = arg1, arg2, key:value]
66
+ Block body content...
67
+ [end]
68
+ ```
69
+
70
+ Example:
71
+
72
+ ```
73
+ [Note = important, level:2]
74
+ This is a note block.
75
+ [end]
76
+ ```
77
+
78
+ ---
79
+
80
+ ### Block without Arguments
81
+
82
+ ```
83
+ [Identifier]
84
+ Block body content...
85
+ [end]
86
+ ```
87
+
88
+ Example:
89
+
90
+ ```
91
+ [Section]
92
+ This is a section.
93
+ [end]
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Block Behavior
99
+
100
+ * Blocks **support nesting**.
101
+ * Blocks can contain:
102
+
103
+ * plain text
104
+ * inline statements
105
+ * other blocks
106
+ * Arguments are optional.
107
+ * Arguments may be:
108
+
109
+ * **positional values**
110
+ * **key-value pairs**
111
+
112
+ Example:
113
+
114
+ ```
115
+ [Article = author:Adam]
116
+
117
+ Welcome to the article.
118
+
119
+ [Section = title:Intro]
120
+ This is the introduction.
121
+ [end]
122
+
123
+ [end]
124
+ ```
125
+
126
+ ---
127
+
128
+ # 3. Inline Statements
129
+
130
+ Inline statements transform or process a **value** within text.
131
+
132
+ Inline statements **do not allow nested SomMark syntax**.
133
+
134
+ ---
135
+
136
+ ## Inline Syntax
137
+
138
+ ### Inline with Arguments
139
+
140
+ ```
141
+ (Value)->(Identifier: arg1, arg2, arg3)
142
+ ```
143
+
144
+ Example:
145
+
146
+ ```
147
+ (hello world)->(uppercase)
148
+ ```
149
+
150
+ ---
151
+
152
+ ### Inline without Arguments
153
+
154
+ ```
155
+ (Value)->(Identifier)
156
+ ```
157
+
158
+ Example:
159
+
160
+ ```
161
+ (hello)->(bold)
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Inline Behavior
167
+
168
+ * `(Value)` is the **input value**.
169
+ * `(Identifier)` specifies the operation.
170
+ * Inline arguments **cannot use key:value syntax**.
171
+ * Inline statements **cannot contain nested syntax**.
172
+
173
+ Example:
174
+
175
+ ```
176
+ (This text)->(highlight: yellow)
177
+ ```
178
+
179
+ ---
180
+
181
+ # 4. AtBlocks (Raw Text Blocks)
182
+
183
+ AtBlocks are used when content must be treated as **plain text**.
184
+
185
+ No SomMark syntax inside an AtBlock is parsed.
186
+
187
+ ---
188
+
189
+ ## AtBlock Syntax
190
+
191
+ ### AtBlock with Arguments
192
+
193
+ ```
194
+ @_Identifier_@: arg1, arg2, key:value;
195
+ Raw content here.
196
+ Everything is treated as plain text.
197
+ @_end_@
198
+ ```
199
+
200
+ Example:
201
+
202
+ ```
203
+ @_Code_@: lang:js;
204
+
205
+ function hello(){
206
+ console.log("hello");
207
+ }
208
+
209
+ @_end_@
210
+ ```
211
+
212
+ ---
213
+
214
+ ### AtBlock without Arguments
215
+
216
+ ```
217
+ @_Identifier_@;
218
+ content...
219
+ @_end_@
220
+ ```
221
+
222
+ Example:
223
+
224
+ ```
225
+ @_Raw_@;
226
+ [This will not be parsed]
227
+ (Value)->(test)
228
+ @_end_@
229
+ ```
230
+
231
+ ---
232
+
233
+ ## AtBlock Behavior
234
+
235
+ * Content inside AtBlocks is **not parsed**.
236
+ * All characters inside are treated as **plain text**.
237
+ * Nested SomMark syntax is ignored.
238
+ * The AtBlock header **MUST end with a semicolon (`;`)**, even if no arguments are provided.
239
+
240
+ Example:
241
+
242
+ ```
243
+ @_Template_@: engine:handlebars;
244
+
245
+ {{ user.name }}
246
+
247
+ @_end_@
248
+ ```
249
+
250
+ ---
251
+
252
+ # 5. Arguments
253
+
254
+ Arguments are used in **Blocks** and **AtBlocks**.
255
+
256
+ ## Argument Types
257
+
258
+ ### Positional Arguments
259
+
260
+ ```
261
+ arg1, arg2, arg3
262
+ ```
263
+
264
+ Example:
265
+
266
+ ```
267
+ [Block = first, second]
268
+ ```
269
+
270
+ ---
271
+
272
+ ### Key-Value Arguments
273
+
274
+ ```
275
+ key:value
276
+ ```
277
+
278
+ Example:
279
+
280
+ ```
281
+ [Block = title:Intro, level:2]
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Argument Restrictions
287
+
288
+ Arguments may contain most characters including:
289
+
290
+ ```
291
+ [
292
+ ]
293
+ (
294
+ )
295
+ ```
296
+
297
+ However the following characters are restricted:
298
+
299
+ ### Colon (`:`)
300
+
301
+ Colon is used to separate **key-value pairs**.
302
+
303
+ Example:
304
+
305
+ ```
306
+ key:value
307
+ ```
308
+
309
+ If a colon must appear in a value, it must be escaped.
310
+
311
+ Example:
312
+
313
+ ```
314
+ x\:y
315
+ ```
316
+
317
+ Example block:
318
+
319
+ ```
320
+ [Block = path:x\:y]
321
+ content
322
+ [end]
323
+ ```
324
+
325
+ ---
326
+
327
+ ### Semicolon (`;`)
328
+
329
+ Semicolon is used **only in AtBlock arguments**.
330
+
331
+ It indicates the **end of the argument list**.
332
+
333
+ Example:
334
+
335
+ ```
336
+ @_Code_@: lang:js, theme:dark;
337
+ ```
338
+
339
+ Semicolons **have no special meaning** in Blocks or Inline Statements.
340
+
341
+ ---
342
+
343
+ # 6. Escape Character
344
+
345
+ SomMark uses the **backslash (`\`)** as the escape character.
346
+
347
+ Escaping works similarly to JavaScript string escaping.
348
+
349
+ Example:
350
+
351
+ ```
352
+ \[
353
+ ```
354
+
355
+ This prevents a block from being parsed.
356
+
357
+ Example:
358
+
359
+ ```
360
+ \[Not a block\]
361
+ ```
362
+
363
+ Escaping can also be used inside arguments.
364
+
365
+ Example:
366
+
367
+ ```
368
+ [Block = x\:y]
369
+ ```
370
+
371
+ ---
372
+
373
+ # 7. Comments
374
+
375
+ SomMark supports **single-line comments**.
376
+
377
+ ## Syntax
378
+
379
+ ```
380
+ # this is a comment
381
+ ```
382
+
383
+ Everything following `#` until the end of the line is ignored by the parser.
384
+
385
+ ---
386
+
387
+ ## Comment Rules
388
+
389
+ Comments may appear:
390
+
391
+ * on their own line
392
+ * between blocks
393
+ * after statements
394
+
395
+ Example:
396
+
397
+ ```
398
+ # Article metadata
399
+
400
+ [Article = author:Adam]
401
+
402
+ # introduction
403
+ [Section = title:Intro]
404
+ Welcome to SomMark.
405
+ [end]
406
+
407
+ [end]
408
+ ```
409
+
410
+ ---
411
+
412
+ ## Comments Inside AtBlocks
413
+
414
+ Inside AtBlocks, comments are treated as **plain text**.
415
+
416
+ Example:
417
+
418
+ ```
419
+ @_Code_@: lang:js;
420
+
421
+ # This line is not treated as a comment
422
+ console.log("Hello")
423
+
424
+ @_end_@
425
+ ```
426
+
427
+ ---
428
+
429
+ # 8. Non-Empty Content Rules
430
+
431
+ The following elements **must not be empty**:
432
+
433
+ * Block body
434
+ * AtBlock body
435
+ * Inline value
436
+
437
+ Invalid examples:
438
+
439
+ ```
440
+ ()->(Identifier)
441
+ ```
442
+
443
+ ---
444
+
445
+ # 9. Flexible Formatting
446
+
447
+ SomMark allows flexible formatting and whitespace.
448
+
449
+ The following are equivalent.
450
+
451
+ ## Compact Format
452
+
453
+ ```
454
+ [Block]Hello World[end]
455
+ ```
456
+
457
+ ## Expanded Format
458
+
459
+ ```
460
+ [
461
+ Block
462
+ ]
463
+
464
+ Hello World
465
+
466
+ [
467
+ end
468
+ ]
469
+ ```
470
+
471
+ Inline and AtBlocks follow similar whitespace flexibility.
472
+
473
+ ---
474
+
475
+ # 10. Construct Summary
476
+
477
+ | Construct | Nesting | Arguments | Key-Value Args | Parsing |
478
+ | ---------------- | ------- | --------- | -------------- | ---------- |
479
+ | Block | Yes | Optional | Yes | Parsed |
480
+ | Inline Statement | No | Optional | No | Parsed |
481
+ | AtBlock | No | Optional | Yes | Not parsed (Header ends with `;`) |
482
+ | Comment | No | No | No | Parsed but ignored by built-in "comment-remover" plugin during AST |
483
+
package/cli/cli.mjs CHANGED
@@ -1,12 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ import { enableColor } from "../helpers/colorize.js";
2
3
  import { getHelp } from "./commands/help.js";
3
4
  import { printVersion, printHeader } from "./commands/version.js";
4
5
  import { runBuild } from "./commands/build.js";
5
- import { printOutput } from "./commands/print.js";
6
+ import { printOutput, printLex, printParse } from "./commands/print.js";
6
7
  import { runInit } from "./commands/init.js";
7
8
  import { runShow } from "./commands/show.js";
9
+ import { runColor } from "./commands/color.js";
8
10
  import { extensions } from "./constants.js";
9
11
 
12
+ // ========================================================================== //
13
+ // Color Support //
14
+ // ========================================================================== //
15
+ import { isColorEnabled } from "./commands/color.js";
16
+
17
+ if (process.env.SOMMARK_COLOR === "true" || await isColorEnabled()) {
18
+ enableColor(true);
19
+ }
20
+
10
21
  // ========================================================================== //
11
22
  // Argument Parsing //
12
23
  // ========================================================================== //
@@ -47,7 +58,36 @@ async function main() {
47
58
  return;
48
59
  }
49
60
 
50
- // 6. Print to Console ( -p or --print )
61
+ // 5.5. Color
62
+ if (command === "color") {
63
+ runColor(args[1]);
64
+ return;
65
+ }
66
+
67
+ // 5.6. List
68
+ if (command === "list") {
69
+ const { runListPlugins, runListPipeline } = await import("./commands/list.js");
70
+ if (args[1] === "pipeline") {
71
+ await runListPipeline();
72
+ } else {
73
+ await runListPlugins(args.slice(1));
74
+ }
75
+ return;
76
+ }
77
+
78
+ // 6. Lex
79
+ if (command === "--lex") {
80
+ await printLex(args[1]);
81
+ return;
82
+ }
83
+
84
+ // 7. Parse
85
+ if (command === "--parse") {
86
+ await printParse(args[1]);
87
+ return;
88
+ }
89
+
90
+ // 9. Print to Console ( -p or --print )
51
91
 
52
92
  const format = command ? command.replace(/^--/, "") : "";
53
93
 
@@ -0,0 +1,36 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { getConfigDir } from "./init.js";
4
+
5
+ // ========================================================================== //
6
+ // Color Command //
7
+ // ========================================================================== //
8
+
9
+ const COLOR_FILE = "color.json";
10
+
11
+ function getColorFilePath() {
12
+ return path.join(getConfigDir(), COLOR_FILE);
13
+ }
14
+
15
+ export async function isColorEnabled() {
16
+ try {
17
+ const data = await fs.readFile(getColorFilePath(), "utf-8");
18
+ return JSON.parse(data).enabled === true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
24
+ export function runColor(action) {
25
+ if (action === "on") {
26
+ fs.mkdir(getConfigDir(), { recursive: true })
27
+ .then(() => fs.writeFile(getColorFilePath(), JSON.stringify({ enabled: true }), "utf-8"))
28
+ .then(() => console.log("Colors enabled."));
29
+ } else if (action === "off") {
30
+ fs.mkdir(getConfigDir(), { recursive: true })
31
+ .then(() => fs.writeFile(getColorFilePath(), JSON.stringify({ enabled: false }), "utf-8"))
32
+ .then(() => console.log("Colors disabled."));
33
+ } else {
34
+ console.log("Usage: sommark color <on|off>");
35
+ }
36
+ }