sommark 3.3.4 → 4.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 (61) hide show
  1. package/README.md +98 -82
  2. package/assets/logo.json +28 -0
  3. package/assets/smark.logo.png +0 -0
  4. package/assets/smark.logo.svg +21 -0
  5. package/cli/cli.mjs +7 -17
  6. package/cli/commands/build.js +24 -4
  7. package/cli/commands/color.js +22 -26
  8. package/cli/commands/help.js +10 -10
  9. package/cli/commands/init.js +20 -31
  10. package/cli/commands/print.js +18 -16
  11. package/cli/commands/show.js +4 -0
  12. package/cli/commands/version.js +6 -0
  13. package/cli/constants.js +9 -5
  14. package/cli/helpers/config.js +11 -0
  15. package/cli/helpers/file.js +17 -6
  16. package/cli/helpers/transpile.js +7 -12
  17. package/core/errors.js +49 -25
  18. package/core/formats.js +7 -3
  19. package/core/formatter.js +215 -0
  20. package/core/helpers/config-loader.js +29 -74
  21. package/core/labels.js +21 -9
  22. package/core/lexer.js +491 -212
  23. package/core/modules.js +164 -0
  24. package/core/parser.js +516 -389
  25. package/core/tokenTypes.js +36 -1
  26. package/core/transpiler.js +237 -154
  27. package/core/validator.js +79 -0
  28. package/formatter/mark.js +203 -43
  29. package/formatter/tag.js +202 -32
  30. package/grammar.ebnf +57 -50
  31. package/helpers/colorize.js +26 -13
  32. package/helpers/escapeHTML.js +13 -6
  33. package/helpers/kebabize.js +6 -0
  34. package/helpers/peek.js +9 -0
  35. package/helpers/removeChar.js +26 -13
  36. package/helpers/safeDataParser.js +114 -0
  37. package/helpers/utils.js +140 -158
  38. package/index.js +198 -188
  39. package/mappers/languages/html.js +105 -213
  40. package/mappers/languages/json.js +122 -171
  41. package/mappers/languages/markdown.js +355 -108
  42. package/mappers/languages/mdx.js +76 -120
  43. package/mappers/languages/xml.js +114 -0
  44. package/mappers/mapper.js +152 -123
  45. package/mappers/shared/index.js +22 -0
  46. package/package.json +26 -6
  47. package/SOMMARK-SPEC.md +0 -481
  48. package/cli/commands/list.js +0 -124
  49. package/constants/html_tags.js +0 -146
  50. package/core/pluginManager.js +0 -149
  51. package/core/plugins/comment-remover.js +0 -47
  52. package/core/plugins/module-system.js +0 -176
  53. package/core/plugins/raw-content-plugin.js +0 -78
  54. package/core/plugins/rules-validation-plugin.js +0 -231
  55. package/core/plugins/sommark-format.js +0 -244
  56. package/coverage_test.js +0 -21
  57. package/debug.js +0 -15
  58. package/helpers/camelize.js +0 -2
  59. package/helpers/defaultTheme.js +0 -3
  60. package/test_format_fix.js +0 -42
  61. package/v3-todo.smark +0 -73
package/README.md CHANGED
@@ -1,118 +1,134 @@
1
- <img width="2000" height="491" alt="SomMark Cover" src="https://raw.githubusercontent.com/Adam-Elmi/SomMark/master/assets/smark_bg.png" />
1
+ # SomMark v4 <img src="assets/smark.logo.png" width="80" align="right">
2
2
 
3
- <p align="center">
4
- SomMark v3 is a simple, flexible markup language for structured content.
5
- </p>
3
+ [![npm version](https://img.shields.io/npm/v/sommark.svg)](https://www.npmjs.com/package/sommark)
4
+ [![license](https://img.shields.io/npm/l/sommark.svg)](https://github.com/Adam-Elmi/SomMark/blob/master/LICENSE)
6
5
 
7
- <p align="center">
8
- <!--License-->
9
- <a href="https://www.npmjs.com/package/sommark" target="_blank">
10
- <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" />
11
- </a>
6
+ 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.
12
7
 
13
- <!--Npm Version-->
14
- <a href="https://www.npmjs.com/package/sommark" target="_blank">
15
- <img src="https://img.shields.io/npm/v/sommark?style=flat-square" />
16
- </a>
8
+ SomMark uses explicit structural boundaries to ensure your document remains stable and predictable. It enables infinite nesting and provides total control over your contents.
17
9
 
18
- <!--Language Type-->
19
- <img src="https://img.shields.io/badge/type-markup%20language-orange?style=flat-square" />
10
+ ---
20
11
 
21
- <!--SomMark Playground-->
22
- <a href="https://adam-elmi.github.io/SomMark-Playground" target="_blank">
23
- <img
24
- src="https://img.shields.io/badge/SomMark-Playground-blue?style=flat-square"
25
- alt="SomMark Playground Badge" />
26
- </a>
27
- </p>
12
+ ## Simple Showcase
28
13
 
29
- ----
14
+ SomMark uses blocks for structure. A block starts with `[identifier]` and must end with `[end]`.
30
15
 
31
- ## Try SomMark Playground
16
+ ### HTML
17
+ ```ini
18
+ [h1]Welcome to SomMark[end]
19
+
20
+ [div = class: "main"]
21
+ This is content inside a container block.
22
+ [p]
23
+ Blocks are the most important part of SomMark.
24
+ (This is a span-like inline statement)->(css: "color: green")
25
+ [end]
26
+ [end]
27
+ ```
32
28
 
33
- Test SomMark live in your browser:
34
- [https://adam-elmi.github.io/SomMark-Playground/](https://adam-elmi.github.io/SomMark-Playground/)
29
+ ### JSON
30
+ SomMark can represent complex data structures through its specialized mappers.
31
+ ```ini
32
+ [object]
33
+ [string = key: "name"]Adam Elmi[end]
34
+ [number = key: "age"]25[end]
35
+ [array = key: "skills"]
36
+ [string]JavaScript[end]
37
+ [string]SomMark[end]
38
+ [end]
39
+ [end]
40
+ ```
35
41
 
36
- ----
42
+ ### XML
43
+ SomMark produces clean, structured XML ideal for configuration and data manifests.
44
+ ```ini
45
+ [xml = version: "1.0"][end]
46
+ [project = name: "SomMark-App"]
47
+ [metadata]
48
+ [author]Adam Elmi[end]
49
+ [version]4.0.0[end]
50
+ [end]
51
+ [settings]
52
+ [database = type: "postgres"]
53
+ [host]localhost[end]
54
+ [port]5432[end]
55
+ [end]
56
+ [end]
57
+ [end]
58
+ ```
37
59
 
38
- # What's new in v3?
60
+ ### MDX
61
+ Use the JavaScript data layer to pass native data to your components.
62
+ ```ini
63
+ [h1]MDX Portfolio[end]
39
64
 
40
- SomMark v3 is faster, more powerful, and easier to extend.
65
+ [Gallery =
66
+ images: js{["nature.jpg", "tech.jpg"]},
67
+ active: js{true}
68
+ ]
69
+ This block uses native JS arrays and booleans.
70
+ [end]
71
+ ```
41
72
 
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.
73
+ ### Markdown
74
+ Use placeholders to inject dynamic text into your templates.
75
+ ```ini
76
+ [h1]Hello p{username}[end]
50
77
 
51
- # Installation
78
+ [quote]
79
+ You are reading documentation on p{siteName}.
80
+ SomMark is an extensible language.
81
+ [end]
52
82
 
53
- ```bash
54
- npm install -g sommark
83
+ [hr][end]
55
84
  ```
56
85
 
57
- # Usage
86
+ ---
58
87
 
59
- ## v3 Syntax Example
88
+ ## How It Works
60
89
 
61
- SomMark is designed to be readable and clear.
90
+ SomMark is an extensible language that processes content through a four-stage pipeline:
62
91
 
63
- ```ini
64
- # Html
65
- [h1]Welcome to SomMark v3[end]
92
+ 1. **Lexing**: The engine scans the source and converts it into a stream of tokens.
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.
66
96
 
67
- [section = class: "hero", id: "main"]
68
- [a = href: "https://sommark.org"]Visit Website[end]
69
- [end]
97
+ The **Module System** enables a "Declare-then-Inject" pattern, allowing you to import mappers and create scalable projects with full recursive support.
70
98
 
71
- # Markdown
72
- [quote]
73
- SomMark is simple and powerful.
74
- [end]
99
+ ---
75
100
 
76
- [bold]Check out our syntax guide![end]
101
+ ## Installation
77
102
 
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]
103
+ Install the SomMark CLI globally:
104
+
105
+ ```bash
106
+ npm install -g sommark
86
107
  ```
87
108
 
88
- ## Using in JavaScript
109
+ ---
110
+
111
+ ## Usage in Node.js
89
112
 
90
113
  ```javascript
91
114
  import SomMark from "sommark";
92
115
 
93
- const smark = new SomMark({
94
- src: '[h1]Hello World[end]',
95
- format: "html"
116
+ const sm = new SomMark({
117
+ src: "[h1]Hello World[end]",
118
+ format: "html"
96
119
  });
97
120
 
98
- console.log(await smark.transpile());
121
+ const output = await sm.transpile();
122
+ // <h1>Hello World</h1>
99
123
  ```
100
124
 
101
- # Documentation
102
-
103
- Read our detailed guides in the `docs/` folder:
104
-
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.
125
+ ---
112
126
 
113
- # Editor Support
127
+ ## Documentation
114
128
 
115
- ### Editor Support
116
- High-quality syntax highlighting and diagnostics are provided via **LSP Semantic Tokens**. This ensures perfect coloring in any editor that supports the Language Server Protocol (e.g., VS Code, Neovim, CoC).
129
+ Read the full guides in the `docs/` folder:
117
130
 
118
- Information for integration can be found in the [SomMark-LSP](https://github.com/Adam-Elmi/SomMark-LSP) project.
131
+ * **[Syntax Guide](docs/syntax/syntax.md)**: Rules for writing Blocks, At-Blocks, and Inlines.
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.
@@ -0,0 +1,28 @@
1
+ {
2
+ "letter": {
3
+ "font": "jaro",
4
+ "color": "#FFFFFF",
5
+ "stroke-color": "#110B52",
6
+ "stroke-transparent": "13%"
7
+ },
8
+ "background": {
9
+ "colors": {
10
+ "color-1": {
11
+ "color": "#F80753",
12
+ "gradient-stop-position": "0%",
13
+ "transparent": "100%"
14
+ },
15
+ "color-2": {
16
+ "color": "#920431",
17
+ "gradient-stop-position": "100%",
18
+ "transparent": "100%"
19
+ }
20
+ }
21
+ },
22
+ "arrow": {
23
+ "font": "Karantina",
24
+ "color": "#FFFFFF",
25
+ "stroke-color": "#585394",
26
+ "stroke-transparent": "26%"
27
+ }
28
+ }
Binary file
@@ -0,0 +1,21 @@
1
+ <svg width="60" height="66" viewBox="0 0 60 66" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect y="1" width="60" height="60" rx="5" fill="url(#paint0_linear_103_13)"/>
3
+ <mask id="path-2-outside-1_103_13" maskUnits="userSpaceOnUse" x="8" y="15" width="17" height="34" fill="black">
4
+ <rect fill="white" x="8" y="15" width="17" height="34"/>
5
+ <path d="M9.76 48C9.36 48 9.16 47.8 9.16 47.4V42.888C9.16 42.68 9.168 42.512 9.184 42.384C9.216 42.256 9.312 42.152 9.472 42.072L15.76 39.192V34.92L9.568 31.08C9.296 30.92 9.16 30.68 9.16 30.36V21.552C9.16 21.296 9.176 21.112 9.208 21C9.24 20.872 9.36 20.736 9.568 20.592L15.88 16.32C16.04 16.224 16.184 16.152 16.312 16.104C16.456 16.04 16.632 16.008 16.84 16.008H23.32C23.72 16.008 23.92 16.208 23.92 16.608V20.688C23.92 21.04 23.8 21.28 23.56 21.408L17.272 24V28.44L23.56 32.04C23.8 32.152 23.92 32.408 23.92 32.808V43.248C23.92 43.376 23.896 43.512 23.848 43.656C23.816 43.8 23.736 43.904 23.608 43.968L16.072 47.712C15.976 47.76 15.856 47.824 15.712 47.904C15.584 47.968 15.456 48 15.328 48H9.76Z"/>
6
+ </mask>
7
+ <path d="M9.76 48C9.36 48 9.16 47.8 9.16 47.4V42.888C9.16 42.68 9.168 42.512 9.184 42.384C9.216 42.256 9.312 42.152 9.472 42.072L15.76 39.192V34.92L9.568 31.08C9.296 30.92 9.16 30.68 9.16 30.36V21.552C9.16 21.296 9.176 21.112 9.208 21C9.24 20.872 9.36 20.736 9.568 20.592L15.88 16.32C16.04 16.224 16.184 16.152 16.312 16.104C16.456 16.04 16.632 16.008 16.84 16.008H23.32C23.72 16.008 23.92 16.208 23.92 16.608V20.688C23.92 21.04 23.8 21.28 23.56 21.408L17.272 24V28.44L23.56 32.04C23.8 32.152 23.92 32.408 23.92 32.808V43.248C23.92 43.376 23.896 43.512 23.848 43.656C23.816 43.8 23.736 43.904 23.608 43.968L16.072 47.712C15.976 47.76 15.856 47.824 15.712 47.904C15.584 47.968 15.456 48 15.328 48H9.76Z" fill="#F5F5F5"/>
8
+ <path d="M9.184 42.384L8.21386 42.1415L8.19921 42.2L8.19172 42.26L9.184 42.384ZM9.472 42.072L9.05558 41.1628L9.04006 41.1699L9.02479 41.1776L9.472 42.072ZM15.76 39.192L16.1764 40.1012L16.76 39.8339V39.192H15.76ZM15.76 34.92H16.76V34.3635L16.287 34.0702L15.76 34.92ZM9.568 31.08L10.095 30.2302L10.0851 30.224L10.075 30.2181L9.568 31.08ZM9.208 21L10.1695 21.2747L10.1741 21.2587L10.1781 21.2425L9.208 21ZM9.568 20.592L9.00747 19.7638L8.99879 19.7698L9.568 20.592ZM15.88 16.32L15.3655 15.4625L15.3421 15.4765L15.3195 15.4918L15.88 16.32ZM16.312 16.104L16.6631 17.0403L16.691 17.0299L16.7181 17.0178L16.312 16.104ZM23.56 21.408L23.9411 22.3325L23.9869 22.3137L24.0306 22.2904L23.56 21.408ZM17.272 24L16.8909 23.0755L16.272 23.3306V24H17.272ZM17.272 28.44H16.272V29.0198L16.7751 29.3078L17.272 28.44ZM23.56 32.04L23.0631 32.9078L23.0993 32.9286L23.1371 32.9462L23.56 32.04ZM23.848 43.656L22.8993 43.3398L22.883 43.3887L22.8718 43.4391L23.848 43.656ZM23.608 43.968L24.0529 44.8636L24.0552 44.8624L23.608 43.968ZM16.072 47.712L15.6271 46.8164L15.6248 46.8176L16.072 47.712ZM15.712 47.904L16.1592 48.7984L16.1786 48.7887L16.1976 48.7782L15.712 47.904ZM9.76 48V47C9.71414 47 9.86343 46.9892 10.0171 47.1429C10.1708 47.2966 10.16 47.4459 10.16 47.4H9.16H8.16C8.16 47.7541 8.24921 48.2034 8.60289 48.5571C8.95657 48.9108 9.40586 49 9.76 49V48ZM9.16 47.4H10.16V42.888H9.16H8.16V47.4H9.16ZM9.16 42.888H10.16C10.16 42.6997 10.1676 42.5778 10.1763 42.508L9.184 42.384L8.19172 42.26C8.16844 42.4462 8.16 42.6603 8.16 42.888H9.16ZM9.184 42.384L10.1541 42.6265C10.1265 42.737 10.072 42.8263 10.0148 42.8883C9.96234 42.9451 9.92001 42.966 9.91921 42.9664L9.472 42.072L9.02479 41.1776C8.70151 41.3392 8.33947 41.639 8.21386 42.1415L9.184 42.384ZM9.472 42.072L9.88842 42.9812L16.1764 40.1012L15.76 39.192L15.3436 38.2828L9.05558 41.1628L9.472 42.072ZM15.76 39.192H16.76V34.92H15.76H14.76V39.192H15.76ZM15.76 34.92L16.287 34.0702L10.095 30.2302L9.568 31.08L9.04097 31.9298L15.233 35.7698L15.76 34.92ZM9.568 31.08L10.075 30.2181C10.0699 30.2151 10.0768 30.2184 10.0896 30.2309C10.1029 30.244 10.1184 30.2629 10.132 30.287C10.162 30.3399 10.16 30.3751 10.16 30.36H9.16H8.16C8.16 31.0282 8.47828 31.5992 9.06098 31.9419L9.568 31.08ZM9.16 30.36H10.16V21.552H9.16H8.16V30.36H9.16ZM9.16 21.552H10.16C10.16 21.4428 10.1635 21.3632 10.1682 21.3086C10.1735 21.248 10.1782 21.2444 10.1695 21.2747L9.208 21L8.24648 20.7253C8.1732 20.9817 8.16 21.2868 8.16 21.552H9.16ZM9.208 21L10.1781 21.2425C10.1435 21.381 10.0801 21.4542 10.0718 21.4636C10.062 21.4748 10.0757 21.4568 10.1372 21.4142L9.568 20.592L8.99879 19.7698C8.75056 19.9417 8.36299 20.2569 8.23786 20.7575L9.208 21ZM9.568 20.592L10.1285 21.4202L16.4405 17.1482L15.88 16.32L15.3195 15.4918L9.0075 19.7638L9.568 20.592ZM15.88 16.32L16.3945 17.1775C16.5199 17.1022 16.6081 17.061 16.6631 17.0403L16.312 16.104L15.9609 15.1677C15.7599 15.243 15.5601 15.3458 15.3655 15.4625L15.88 16.32ZM16.312 16.104L16.7181 17.0178C16.7004 17.0257 16.7293 17.008 16.84 17.008V16.008V15.008C16.5347 15.008 16.2116 15.0543 15.9059 15.1902L16.312 16.104ZM16.84 16.008V17.008H23.32V16.008V15.008H16.84V16.008ZM23.32 16.008V17.008C23.3659 17.008 23.2166 17.0188 23.0629 16.8651C22.9092 16.7114 22.92 16.5621 22.92 16.608H23.92H24.92C24.92 16.2539 24.8308 15.8046 24.4771 15.4509C24.1234 15.0972 23.6741 15.008 23.32 15.008V16.008ZM23.92 16.608H22.92V20.688H23.92H24.92V16.608H23.92ZM23.92 20.688H22.92C22.92 20.7553 22.908 20.74 22.9356 20.6848C22.95 20.6559 22.972 20.623 23.0027 20.5917C23.0332 20.5605 23.0642 20.5391 23.0894 20.5256L23.56 21.408L24.0306 22.2904C24.6949 21.936 24.92 21.2824 24.92 20.688H23.92ZM23.56 21.408L23.1789 20.4835L16.8909 23.0755L17.272 24L17.6531 24.9245L23.9411 22.3325L23.56 21.408ZM17.272 24H16.272V28.44H17.272H18.272V24H17.272ZM17.272 28.44L16.7751 29.3078L23.0631 32.9078L23.56 32.04L24.0569 31.1722L17.7689 27.5722L17.272 28.44ZM23.56 32.04L23.1371 32.9462C23.0914 32.9248 23.0442 32.8927 23.0027 32.8503C22.9618 32.8085 22.9375 32.7681 22.9245 32.7404C22.902 32.6924 22.92 32.698 22.92 32.808H23.92H24.92C24.92 32.243 24.7403 31.4873 23.9829 31.1338L23.56 32.04ZM23.92 32.808H22.92V43.248H23.92H24.92V32.808H23.92ZM23.92 43.248H22.92C22.92 43.2507 22.9195 43.2793 22.8993 43.3398L23.848 43.656L24.7967 43.9722C24.8725 43.7447 24.92 43.5013 24.92 43.248H23.92ZM23.848 43.656L22.8718 43.4391C22.8836 43.3861 22.9117 43.3099 22.9714 43.2323C23.0316 43.1539 23.1021 43.1029 23.1608 43.0736L23.608 43.968L24.0552 44.8624C24.462 44.659 24.7292 44.3004 24.8242 43.8729L23.848 43.656ZM23.608 43.968L23.1631 43.0724L15.6271 46.8164L16.072 47.712L16.5169 48.6076L24.0529 44.8636L23.608 43.968ZM16.072 47.712L15.6248 46.8176C15.5109 46.8745 15.3771 46.9461 15.2264 47.0298L15.712 47.904L16.1976 48.7782C16.3349 48.7019 16.4411 48.6455 16.5192 48.6064L16.072 47.712ZM15.712 47.904L15.2648 47.0096C15.2606 47.0117 15.265 47.009 15.2775 47.0059C15.2903 47.0026 15.3078 47 15.328 47V48V49C15.6288 49 15.9089 48.9236 16.1592 48.7984L15.712 47.904ZM15.328 48V47H9.76V48V49H15.328V48Z" fill="#110B52" fill-opacity="0.13" mask="url(#path-2-outside-1_103_13)"/>
9
+ <mask id="path-4-outside-2_103_13" maskUnits="userSpaceOnUse" x="30" y="25" width="26" height="23" fill="black">
10
+ <rect fill="white" x="30" y="25" width="26" height="23"/>
11
+ <path d="M40.048 42.944L43.312 39.68H31.28V33.728H43.248L40.048 30.528L43.76 26.88L53.616 36.736L43.76 46.592L40.048 42.944Z"/>
12
+ </mask>
13
+ <path d="M40.048 42.944L43.312 39.68H31.28V33.728H43.248L40.048 30.528L43.76 26.88L53.616 36.736L43.76 46.592L40.048 42.944Z" fill="#F5F5F5"/>
14
+ <path d="M40.048 42.944L39.3409 42.2369L38.6276 42.9502L39.3471 43.6572L40.048 42.944ZM43.312 39.68L44.0191 40.3871L45.7262 38.68H43.312V39.68ZM31.28 39.68H30.28V40.68H31.28V39.68ZM31.28 33.728V32.728H30.28V33.728H31.28ZM43.248 33.728V34.728H45.6622L43.9551 33.0209L43.248 33.728ZM40.048 30.528L39.3471 29.8148L38.6276 30.5218L39.3409 31.2351L40.048 30.528ZM43.76 26.88L44.4671 26.1729L43.7661 25.4719L43.0591 26.1668L43.76 26.88ZM53.616 36.736L54.3231 37.4431L55.0302 36.736L54.3231 36.0289L53.616 36.736ZM43.76 46.592L43.0591 47.3052L43.7661 48.0001L44.4671 47.2991L43.76 46.592ZM40.048 42.944L40.7551 43.6511L44.0191 40.3871L43.312 39.68L42.6049 38.9729L39.3409 42.2369L40.048 42.944ZM43.312 39.68V38.68H31.28V39.68V40.68H43.312V39.68ZM31.28 39.68H32.28V33.728H31.28H30.28V39.68H31.28ZM31.28 33.728V34.728H43.248V33.728V32.728H31.28V33.728ZM43.248 33.728L43.9551 33.0209L40.7551 29.8209L40.048 30.528L39.3409 31.2351L42.5409 34.4351L43.248 33.728ZM40.048 30.528L40.7489 31.2412L44.4609 27.5932L43.76 26.88L43.0591 26.1668L39.3471 29.8148L40.048 30.528ZM43.76 26.88L43.0529 27.5871L52.9089 37.4431L53.616 36.736L54.3231 36.0289L44.4671 26.1729L43.76 26.88ZM53.616 36.736L52.9089 36.0289L43.0529 45.8849L43.76 46.592L44.4671 47.2991L54.3231 37.4431L53.616 36.736ZM43.76 46.592L44.4609 45.8788L40.7489 42.2308L40.048 42.944L39.3471 43.6572L43.0591 47.3052L43.76 46.592Z" fill="#585394" fill-opacity="0.26" mask="url(#path-4-outside-2_103_13)"/>
15
+ <defs>
16
+ <linearGradient id="paint0_linear_103_13" x1="30" y1="1" x2="30" y2="61" gradientUnits="userSpaceOnUse">
17
+ <stop stop-color="#F80753"/>
18
+ <stop offset="1" stop-color="#920431"/>
19
+ </linearGradient>
20
+ </defs>
21
+ </svg>
package/cli/cli.mjs CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * SomMark CLI Entry Point
4
+ * Reads your command-line arguments and runs the right tool.
5
+ */
2
6
  import { enableColor } from "../helpers/colorize.js";
3
7
 
4
8
  import { getHelp } from "./commands/help.js";
@@ -47,13 +51,14 @@ async function main() {
47
51
  return;
48
52
  }
49
53
 
50
- // 4. Init
54
+ // 4. Init (Always Local)
51
55
  if (command === "init") {
52
- await runInit(args[1] === "--local" || args[1] === "-l");
56
+ await runInit();
53
57
  return;
54
58
  }
55
59
 
56
60
 
61
+
57
62
  // 5. Show
58
63
  if (command === "show") {
59
64
  await runShow(args[1]);
@@ -66,16 +71,6 @@ async function main() {
66
71
  return;
67
72
  }
68
73
 
69
- // 5.6. List
70
- if (command === "list") {
71
- const { runListPlugins, runListPipeline } = await import("./commands/list.js");
72
- if (args[1] === "pipeline") {
73
- await runListPipeline();
74
- } else {
75
- await runListPlugins(args.slice(1));
76
- }
77
- return;
78
- }
79
74
 
80
75
  // 6. Lex
81
76
  if (command === "--lex") {
@@ -96,14 +91,9 @@ async function main() {
96
91
  if (extensions[format]) {
97
92
  // Build or Print
98
93
  if (args[1] === "-p" || args[1] === "--print") {
99
- // smark --format -p file
100
- // args[0]=--format, args[1]=-p, args[2]=file
101
94
  await printOutput(format, args[2]);
102
95
  process.exit(0);
103
96
  } else {
104
- // smark --format file [options]
105
- // args[0]=--format, args[1]=file, args[2]=-o, args[3]=output...
106
-
107
97
  await runBuild(
108
98
  command, // format_option (--markdown)
109
99
  args[1], // sourcePath
@@ -5,6 +5,7 @@ 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 XML from "../../mappers/languages/xml.js";
8
9
  import { extensions } from "../constants.js";
9
10
  import { isExist, readContent, createFile } from "../helpers/file.js";
10
11
  import { loadConfig } from "../helpers/config.js";
@@ -13,11 +14,20 @@ import { transpile } from "../helpers/transpile.js";
13
14
  // ========================================================================== //
14
15
  // Generate Output File //
15
16
  // ========================================================================== //
16
- async function generateOutput(outputDir, outputFile, format, sourcePath, mappingFile) {
17
+ /**
18
+ * Helper to generate and save the created code.
19
+ * @param {string} outputDir - Directory to save the file.
20
+ * @param {string} outputFile - Output filename (without extension).
21
+ * @param {string} format - Target format (html, markdown, etc.).
22
+ * @param {string} sourcePath - Path to the source .smark file.
23
+ * @param {Mapper|null} mappingFile - Custom mapped rules.
24
+ * @returns {Promise<string>} - The full path to the created file.
25
+ */
26
+ async function generateOutput(outputDir, outputFile, format, sourcePath, mappingFile, config) {
17
27
  let source_code = await readContent(sourcePath);
18
28
  source_code = source_code.toString();
19
29
  const absolutePath = path.resolve(process.cwd(), sourcePath);
20
- const output = await transpile({ src: source_code, format, filename: absolutePath, mappingFile });
30
+ const output = await transpile({ src: source_code, format, filename: absolutePath, mappingFile, config });
21
31
  const finalPath = path.join(outputDir, `${outputFile}.${extensions[format]}`);
22
32
  await createFile(outputDir, `${outputFile}.${extensions[format]}`, output);
23
33
  return finalPath;
@@ -26,6 +36,16 @@ async function generateOutput(outputDir, outputFile, format, sourcePath, mapping
26
36
  // ========================================================================== //
27
37
  // Run Build Process //
28
38
  // ========================================================================== //
39
+ /**
40
+ * The starting point for the build process.
41
+ * Checks the file type, loads settings, and creates the output code.
42
+ *
43
+ * @param {string} format_option - The file format to output (like '--html').
44
+ * @param {string} sourcePath - The path to the file you want to build.
45
+ * @param {string} outputFlag - The '-o' flag.
46
+ * @param {string} outputFileArg - The custom filename.
47
+ * @param {string} outputDirArg - The custom directory.
48
+ */
29
49
  export async function runBuild(format_option, sourcePath, outputFlag, outputFileArg, outputDirArg) {
30
50
  try {
31
51
  const format = format_option.replaceAll("-", "") ?? "";
@@ -58,7 +78,7 @@ export async function runBuild(format_option, sourcePath, outputFlag, outputFile
58
78
  let mappingFile = config.mappingFile;
59
79
 
60
80
  if (!mappingFile) {
61
- mappingFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : format === "json" ? Json : null;
81
+ mappingFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : format === "json" ? Json : format === "xml" ? XML : null;
62
82
  }
63
83
 
64
84
  // CLI Overrides
@@ -69,7 +89,7 @@ export async function runBuild(format_option, sourcePath, outputFlag, outputFile
69
89
  }
70
90
  }
71
91
 
72
- const createdFilePath = await generateOutput(finalOutputDir, finalOutputFile, format, sourcePath, mappingFile);
92
+ const createdFilePath = await generateOutput(finalOutputDir, finalOutputFile, format, sourcePath, mappingFile, config);
73
93
  const stats = await fs.stat(createdFilePath);
74
94
  const date = new Date().toLocaleString();
75
95
 
@@ -1,36 +1,32 @@
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
- }
1
+ import { formatMessage } from "../../core/errors.js";
14
2
 
3
+ /**
4
+ * Checks if colors are turned on in your settings.
5
+ * @returns {Promise<boolean>}
6
+ */
15
7
  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
- }
8
+ return process.env.SOMMARK_COLOR === "true";
22
9
  }
23
10
 
11
+ /**
12
+ * Shows the user how to turn colors on or off.
13
+ * @param {string} action - 'on' or 'off'.
14
+ */
24
15
  export function runColor(action) {
25
16
  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."));
17
+ console.log(formatMessage([
18
+ `{line}<$yellow:SomMark uses Environment Variables for colors:$>{line}`,
19
+ `<$blue:Set this in your current shell:$>`,
20
+ ` <$cyan:export SOMMARK_COLOR=true$>{line}`,
21
+ `<$blue:Add it to your .bashrc or .zshrc for permanent effect.$>{line}`
22
+ ].join("")));
29
23
  } 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."));
24
+ console.log(formatMessage([
25
+ `{line}<$yellow:To disable colors, run:$>{line}`,
26
+ ` <$cyan:export SOMMARK_COLOR=false$>{line}`,
27
+ `<$blue:(Or remove the SOMMARK_COLOR variable from your shell config)$>{line}`
28
+ ].join("")));
33
29
  } else {
34
- console.log("Usage: sommark color <on|off>");
30
+ console.log(formatMessage(`Usage: <$blue:sommark color on|off$>`));
35
31
  }
36
32
  }
@@ -5,6 +5,11 @@ import { options } from "../constants.js";
5
5
  // Help Command //
6
6
  // ========================================================================== //
7
7
 
8
+ /**
9
+ * Displays the CLI help message.
10
+ * @param {boolean} [unknown_option=true] - Whether to show the "Unrecognized option" prefix if an invalid flag is passed.
11
+ * @returns {string} - The formatted help message.
12
+ */
8
13
  export function getHelp(unknown_option = true) {
9
14
  const msg = [
10
15
  `${unknown_option && process.argv[2] ? `<$red:Unrecognized option$> <$blue: '${process.argv[2]}'$>` : ""}`,
@@ -13,32 +18,27 @@ export function getHelp(unknown_option = true) {
13
18
  "{N}{N}<$yellow:Global Options:$>",
14
19
  "{N} <$green:-h, --help$> <$cyan: Show help message$>",
15
20
  "{N} <$green:-v, --version$> <$cyan: Show version information$>",
16
- "{N} <$green:init$> <$cyan: Initialize global SomMark configuration directory$>",
21
+ "{N} <$green:init$> <$cyan: Initialize local SomMark configuration file (smark.config.js)$>",
17
22
  "{N} <$green:show config$> <$cyan: Display the absolute paths to the active SomMark configuration files$>",
18
- "{N} <$green:color on|off$> <$cyan: Enable or disable colored output$>",
19
- "{N} <$green:list plugins$> <$cyan: List all enabled plugins with author and description$>",
20
- "{N} <$green:list -i plugins$> <$cyan: List only internal (built-in) plugins$>",
21
- "{N} <$green:list -e plugins$> <$cyan: List only external (user-defined) plugins$>",
22
- "{N} <$green:list pipeline$> <$cyan: Show the execution order of all active plugin phases$>",
23
+ "{N} <$green:color on|off$> <$cyan: Help on enabling colors via Environment Variables$>",
23
24
 
24
25
  "{N}{N}<$yellow:Transpilation Options:$>",
25
26
  "{N}<$yellow:Usage:$> <$blue:sommark [option] [targetFile] [option] [outputFile] [outputDir]$>",
26
27
  "{N} <$green:--html$> <$cyan: Transpile to HTML$>",
27
28
  "{N} <$green:--markdown$> <$cyan: Transpile to Markdown$>",
28
29
  "{N} <$green:--mdx$> <$cyan: Transpile to MDX$>",
29
- "{N} <$green:--json$> <$cyan: Transpile to json$>",
30
+ "{N} <$green:--json$> <$cyan: Transpile to JSON$>",
30
31
  "{N} <$green:--text$> <$cyan: Transpile to plain text$>",
31
32
  "{N} <$green:--lex$> <$cyan: Print lexer tokens to console$>",
32
33
  "{N} <$green:--parse$> <$cyan: Print parser AST to console$>",
33
34
 
34
- "{N}{N}<$yellow:Output Options:$>",
35
+ "{N}{N}<$yellow:Output & Config Overrides:$>",
35
36
  "{N} <$green:-p, --print$> <$cyan: Print output to console (stdout)$>",
36
37
  "{N} <$green:-o$> <$cyan: Specify output filename (and optionally directory)$>",
37
38
 
38
39
  "{N}{N}<$yellow:Examples:$>",
39
40
  "{N} <$magenta:1. Basic usage:$> <$blue:sommark --html input.smark$>",
40
- "{N} <$magenta:2. Print to console:$> <$blue:sommark --html -p input.smark$>",
41
- "{N} <$magenta:3. Custom output:$> <$blue:sommark --html input.smark -o myOutput ./dist/$>"
41
+ "{N} <$magenta:2. Custom output:$> <$blue:sommark --html input.smark -o myOutput ./dist/$>"
42
42
  ].join("");
43
43
  const help_msg = formatMessage(msg);
44
44
 
@@ -1,47 +1,37 @@
1
- import fs from "node:fs/promises";
2
1
  import path from "node:path";
3
- import os from "node:os";
4
2
  import { cliError, formatMessage } from "../../core/errors.js";
3
+ import { isExist, createFile } from "../helpers/file.js";
5
4
 
6
5
  // ========================================================================== //
7
6
  // Init Command //
8
7
  // ========================================================================== //
9
8
 
10
- export function getConfigDir() {
11
- const homeDir = os.homedir();
12
- if (process.platform === "win32") {
13
- return path.join(process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"), "sommark");
14
- } else if (process.platform === "darwin") {
15
- return path.join(homeDir, "Library", "Application Support", "sommark");
16
- } else {
17
- return path.join(process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"), "sommark");
18
- }
19
- }
20
-
21
- export async function runInit(isLocal = false) {
9
+ /**
10
+ * Initializes a new SomMark configuration file (smark.config.js) in the current directory.
11
+ */
12
+ export async function runInit() {
22
13
  try {
23
- const configDir = isLocal ? process.cwd() : getConfigDir();
14
+ const configDir = process.cwd();
24
15
  const configFilePath = path.join(configDir, "smark.config.js");
25
16
 
26
- if (!isLocal) {
27
- await fs.mkdir(configDir, { recursive: true });
28
- }
29
-
30
- const defaultConfigContent = `export default {
31
- outputDir: "./",
32
- outputFile: "output",
33
- mappingFile: null,
34
- plugins: [],
35
- priority: [],
36
- excludePlugins: [],
17
+ const defaultConfigContent = `/**
18
+ * SomMark Configuration File
19
+ * Generated by 'smark init'
20
+ */
21
+ export default {
22
+ format: "html", // Target output format (html, markdown, mdx, json, xml)
23
+ removeComments: true, // Strip SomMark comments from the final output
24
+ customProps: [], // Whitelisted HTML attributes (prevents CSS hijacking)
25
+ placeholders: {}, // Global p{key} variables for content injection
26
+ outputDir: "./", // Where to save the transpiled files
27
+ outputFile: "output", // Default output filename
37
28
  };
38
29
  `;
39
30
 
40
- try {
41
- await fs.access(configFilePath);
31
+ if (await isExist(configFilePath)) {
42
32
  console.log(formatMessage(`<$yellow:Configuration already exists at:$> <$cyan:${configFilePath}$>`));
43
- } catch {
44
- await fs.writeFile(configFilePath, defaultConfigContent, "utf-8");
33
+ } else {
34
+ await createFile(configDir, "smark.config.js", defaultConfigContent);
45
35
  console.log(formatMessage(`<$green:Initialized SomMark configuration at:$> <$cyan:${configFilePath}$>`));
46
36
  }
47
37
  } catch (error) {
@@ -50,4 +40,3 @@ export async function runInit(isLocal = false) {
50
40
  ]);
51
41
  }
52
42
  }
53
-