sommark 2.1.2 → 2.3.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/CHANGELOG.md +30 -0
- package/README.md +41 -308
- package/cli/cli.mjs +15 -1
- package/cli/commands/build.js +2 -1
- package/cli/commands/help.js +32 -29
- package/cli/commands/init.js +64 -0
- package/cli/commands/show.js +46 -0
- package/cli/commands/version.js +1 -1
- package/cli/constants.js +6 -5
- package/cli/helpers/config.js +14 -5
- package/core/formats.js +3 -2
- package/core/lexer.js +25 -16
- package/core/parser.js +18 -9
- package/core/transpiler.js +34 -18
- package/formatter/mark.js +27 -45
- package/formatter/tag.js +6 -6
- package/grammar.ebnf +0 -1
- package/index.js +6 -4
- package/mappers/languages/html.js +71 -26
- package/mappers/languages/json.js +172 -0
- package/mappers/languages/markdown.js +79 -31
- package/mappers/mapper.js +104 -10
- package/package.json +2 -5
- package/lib/highlight.js +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## v2.3.0 (2026-02-23)
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
* Added missing JSON support in the CLI.
|
|
9
|
+
* Added two new methods: makeFrontmatter and raw_js_imports.
|
|
10
|
+
* Added new documentation.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
* Fixed MDX format output error caused by extra whitespaces.
|
|
15
|
+
* Fixed colon issue in atblock body.
|
|
16
|
+
|
|
17
|
+
### Improved
|
|
18
|
+
|
|
19
|
+
* Improved several internal methods.
|
|
20
|
+
* Updated and enhanced tests.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## v2.2.0 (2026-02-23)
|
|
24
|
+
## Features
|
|
25
|
+
- Added JSON support
|
|
26
|
+
- Added type rules to validate element type
|
|
27
|
+
- Improved documentation
|
|
28
|
+
- Improved mapper files
|
|
29
|
+
- Removed **highlight.js** dependency
|
|
30
|
+
- Added new CLI feature: automatic configuration file creation
|
|
31
|
+
|
|
32
|
+
|
|
3
33
|
## v2.1.2 (2026-02-09)
|
|
4
34
|
### Fixes
|
|
5
35
|
- Fixed cli print functionality
|
package/README.md
CHANGED
|
@@ -1,135 +1,47 @@
|
|
|
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
|
-
|
|
4
|
+
SomMark is a declarative, extensible markup language for structured content that can be converted to HTML, Markdown, MDX, JSON, and more.
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
+
<!--License-->
|
|
9
|
+
<a href="https://www.npmjs.com/package/sommark" target="_blank">
|
|
8
10
|
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" />
|
|
9
|
-
|
|
10
|
-
<img src="https://img.shields.io/badge/type-markup%20language-purple?style=flat-square" />
|
|
11
|
-
<img src="https://img.shields.io/badge/html-supported-orange?style=flat-square" />
|
|
12
|
-
<img src="https://img.shields.io/badge/markdown-supported-lightyellow?style=flat-square" />
|
|
13
|
-
<img src="https://img.shields.io/badge/mdx-supported-lightblue?style=flat-square" />
|
|
14
|
-
</p>
|
|
15
|
-
|
|
16
|
-
# SomMark v2
|
|
17
|
-
|
|
18
|
-
> [!WARNING]
|
|
19
|
-
> Old version(v1) is no longer supported.
|
|
20
|
-
|
|
21
|
-
SomMark provides a way to write structured content that can be converted into other formats like HTML or Markdown. It is different from standard Markdown because it uses explicit syntax for blocks and elements, which makes it easier to process and customize.
|
|
22
|
-
|
|
23
|
-
# Features
|
|
24
|
-
|
|
25
|
-
* **Explicit Syntax**: Every element has a clear start and end, which reduces parsing errors.
|
|
26
|
-
* **Customizable Mappers**: You can convert SomMark content into any format (HTML, Markdown, JSON, etc.) by using Mappers.
|
|
27
|
-
* **Validation**: You can define rules to check your content, such as limiting the number of arguments or requiring specific keys.
|
|
28
|
-
* **MDX Support**: SomMark can map to existing React components ("Only Ready Components").
|
|
29
|
-
> [!NOTE]
|
|
30
|
-
> SomMark does not parse raw JSX. It only maps to ready components.
|
|
31
|
-
|
|
32
|
-
# Syntax
|
|
33
|
-
|
|
34
|
-
SomMark uses three main types of elements: Blocks, Inline Statements, and At-Blocks.
|
|
11
|
+
</a>
|
|
35
12
|
|
|
36
|
-
|
|
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>
|
|
37
17
|
|
|
38
|
-
|
|
18
|
+
<!--Language Type-->
|
|
19
|
+
<img src="https://img.shields.io/badge/type-markup%20language-white?style=flat-square" />
|
|
39
20
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
> [!NOTE]
|
|
49
|
-
> The colon `:` separates keys and values.
|
|
50
|
-
> Keys are optional.
|
|
51
|
-
|
|
52
|
-
**Without Arguments**
|
|
53
|
-
```ini
|
|
54
|
-
[Note]
|
|
55
|
-
This is a simple block.
|
|
56
|
-
[end]
|
|
57
|
-
```
|
|
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>
|
|
58
28
|
|
|
59
|
-
## 2. Inline Statement
|
|
60
29
|
|
|
61
|
-
|
|
30
|
+
----
|
|
62
31
|
|
|
63
|
-
|
|
64
|
-
```ini
|
|
65
|
-
This text is (bold)->(bold) and this is (red)->(color: red).
|
|
66
|
-
```
|
|
67
|
-
> [!NOTE]
|
|
68
|
-
> Inline arguments are values only. Keys are not supported.
|
|
32
|
+
## Try SomMark Playground
|
|
69
33
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
(Click here)->(Button)
|
|
73
|
-
```
|
|
34
|
+
Test SomMark features live here:
|
|
35
|
+
[https://adam-elmi.github.io/SomMark-Playground/](https://adam-elmi.github.io/SomMark-Playground/)
|
|
74
36
|
|
|
75
|
-
|
|
37
|
+
----
|
|
76
38
|
|
|
77
|
-
|
|
39
|
+
# SomMark v2
|
|
78
40
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@_Code_@: javascript;
|
|
82
|
-
console.log("This is raw code.");
|
|
83
|
-
@_end_@
|
|
84
|
-
```
|
|
85
|
-
> [!NOTE]
|
|
86
|
-
> You must use a semi-colon `;` to end the argument list.
|
|
87
|
-
|
|
88
|
-
**Without Arguments**
|
|
89
|
-
```ini
|
|
90
|
-
@_Raw_@
|
|
91
|
-
Raw content here.
|
|
92
|
-
@_end_@
|
|
93
|
-
```
|
|
41
|
+
> [!WARNING]
|
|
42
|
+
> Old version(v1) is no longer supported.
|
|
94
43
|
|
|
95
|
-
|
|
96
|
-
* SomMark Top-Level Rules:
|
|
97
|
-
- Only Blocks and comments are allowed at the top level.
|
|
98
|
-
- Inline Statements, Atblocks, and text cannot appear at the top level. They must be inside a Block, or it is invalid.
|
|
99
|
-
**Invalid Top-Level:**
|
|
100
|
-
```ini
|
|
101
|
-
Hello world ❌ (Text cannot be at top level)
|
|
102
|
-
|
|
103
|
-
Welcome to (SomMark)->(Bold) ❌ (Inline statement cannot be at top level)
|
|
104
|
-
|
|
105
|
-
@_Code_@: js;
|
|
106
|
-
function add(a, b) {
|
|
107
|
-
return a + b;
|
|
108
|
-
}
|
|
109
|
-
@_end_@ ❌ (Atblock cannot be at top level)
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Valid Top-Level:**
|
|
113
|
-
```ini
|
|
114
|
-
[Block]
|
|
115
|
-
Hello world
|
|
116
|
-
Welcome to (SomMark)->(Bold) # Inline statement inside block is valid
|
|
117
|
-
|
|
118
|
-
@_Code_@: js;
|
|
119
|
-
function add(a, b) {
|
|
120
|
-
return a + b; # Treated as plain text
|
|
121
|
-
}
|
|
122
|
-
@_end_@
|
|
123
|
-
|
|
124
|
-
[end]
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
* **Identifiers**: Names can only contain letters and numbers.
|
|
129
|
-
* **Escape Character**: Use the backslash `\` to escape special characters (like colons or commas) inside arguments.
|
|
130
|
-
* **Colons**: inside Block and At-Block arguments, the colon (`:`) separates names from values.
|
|
131
|
-
* **Semi-Colons**: The semi-colon (`;`) is only used in At-Blocks to assert the end of the argument list.
|
|
132
|
-
* **Whitespace**: SomMark ignores extra spaces and newlines, so you can format your code however you like.
|
|
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.
|
|
133
45
|
|
|
134
46
|
# Installation
|
|
135
47
|
|
|
@@ -167,207 +79,28 @@ Hello World
|
|
|
167
79
|
`;
|
|
168
80
|
|
|
169
81
|
const smark = new SomMark({
|
|
170
|
-
|
|
171
|
-
|
|
82
|
+
src: source,
|
|
83
|
+
format: "html"
|
|
172
84
|
});
|
|
173
85
|
|
|
174
86
|
console.log(await smark.transpile());
|
|
175
87
|
```
|
|
176
88
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
Detailed guides and API references are available in the `docs/` directory:
|
|
180
|
-
|
|
181
|
-
* **[Syntax Guide](docs/syntax.md)**: Master SomMark syntax (Blocks, Inline, At-Blocks).
|
|
182
|
-
* **[Core API](docs/core.md)**: Programmatic usage of the library (`transpile`, `lex`, `parse`).
|
|
183
|
-
* **[Mapper API](docs/mapper.md)**: Guide for creating custom mappers and rules.
|
|
184
|
-
* **[CLI Reference](docs/cli.md)**: Command line options and configurations.
|
|
185
|
-
* **[API Quick Reference](docs/api)**: Fast lookup for all classes and functions.
|
|
186
|
-
* **[Configuration Reference](docs/config.md)**: Guide for creating custom configurations.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
# Configuration (Only for CLI)
|
|
191
|
-
|
|
192
|
-
You can create a `smark.config.js` file to configure the CLI.
|
|
193
|
-
|
|
194
|
-
```javascript
|
|
195
|
-
/* smark.config.js */
|
|
196
|
-
import myMapper from "./my-mapper.js";
|
|
197
|
-
|
|
198
|
-
export default {
|
|
199
|
-
outputFile: "output", // Default output filename
|
|
200
|
-
outputDir: "./dist", // Where to save files
|
|
201
|
-
mappingFile: myMapper // Use a custom mapper by default
|
|
202
|
-
};
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
# Creating Custom Mappers
|
|
206
|
-
|
|
207
|
-
Mappers tell SomMark how to convert your content. You can define rules, options, and how arguments are handled.
|
|
208
|
-
|
|
209
|
-
## Basic Structure
|
|
210
|
-
|
|
211
|
-
```javascript
|
|
212
|
-
import { Mapper } from "sommark";
|
|
213
|
-
const myMapper = new Mapper();
|
|
214
|
-
const { tag } = myMapper;
|
|
215
|
-
|
|
216
|
-
// Define a Block
|
|
217
|
-
myMapper.register("Alert", ({ args, content }) => {
|
|
218
|
-
// Access arguments by index or name
|
|
219
|
-
const type = args[0] || args.type || "info";
|
|
220
|
-
|
|
221
|
-
// Use TagBuilder to create HTML elements safely
|
|
222
|
-
return myMapper.tag("div")
|
|
223
|
-
.attributes({ class: `alert ${type}` })
|
|
224
|
-
.body(content);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
export default myMapper;
|
|
228
|
-
```
|
|
229
|
-
> [!WARNING]
|
|
230
|
-
> The `.body()` and `.selfClose()` methods return the final HTML string. You must treat them as the end of the builder chain. If you forget to call them, you will return a builder object instead of a string.
|
|
231
|
-
|
|
232
|
-
You also skip tag builder and use raw HTML.
|
|
233
|
-
|
|
234
|
-
```javascript
|
|
235
|
-
import { Mapper } from "sommark";
|
|
236
|
-
const myMapper = new Mapper();
|
|
237
|
-
|
|
238
|
-
myMapper.register("Alert", ({ args, content }) => {
|
|
239
|
-
// Access arguments by index or name
|
|
240
|
-
const type = args[0] || args.type || "info";
|
|
241
|
-
|
|
242
|
-
// Use raw HTML
|
|
243
|
-
return `<div class="alert ${type}">${content}</div>`;
|
|
244
|
-
});
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Mapping Multiple Identifiers
|
|
248
|
-
|
|
249
|
-
You can use an array of strings to map multiple names to the same output function.
|
|
250
|
-
|
|
251
|
-
```javascript
|
|
252
|
-
import { Mapper } from "sommark";
|
|
253
|
-
const myMapper = new Mapper();
|
|
254
|
-
const { tag } = myMapper;
|
|
255
|
-
|
|
256
|
-
// Both [code] and [Code] will use this mapper
|
|
257
|
-
myMapper.register(["code", "Code"], ({ content }) => {
|
|
258
|
-
return tag("pre").body(tag("code").body(content));
|
|
259
|
-
});
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
## Reusing Existing Mappers
|
|
263
|
-
|
|
264
|
-
You can borrow rules from default mappers to avoid rewriting them.
|
|
265
|
-
|
|
266
|
-
```javascript
|
|
267
|
-
import { Mapper, HTML } from "sommark";
|
|
268
|
-
const myMapper = new Mapper();
|
|
269
|
-
|
|
270
|
-
// Reuse the "Code" block from the default HTML mapper
|
|
271
|
-
const codeOutput = HTML.get("Code");
|
|
272
|
-
if (codeOutput) {
|
|
273
|
-
myMapper.register(codeOutput.id, codeOutput.render, codeOutput.options);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Add your own custom blocks...
|
|
277
|
-
myMapper.register("MyBlock", ({ content }) => {
|
|
278
|
-
return content;
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
export default myMapper;
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
## Using Rules (Validation)
|
|
285
|
-
|
|
286
|
-
You can force strict rules on your content. If a rule is broken, SomMark will stop and show an error.
|
|
287
|
-
|
|
288
|
-
### Argument Validation (`args`)
|
|
289
|
-
|
|
290
|
-
Validates the arguments passed to the tag.
|
|
291
|
-
|
|
292
|
-
```javascript
|
|
293
|
-
myMapper.register("User", ({ args }) => {
|
|
294
|
-
return tag("div").body(`User: ${args[0]}`);
|
|
295
|
-
}, {
|
|
296
|
-
rules: {
|
|
297
|
-
args: {
|
|
298
|
-
min: 1, // Must have at least 1 argument
|
|
299
|
-
max: 3, // Cannot have more than 3 arguments
|
|
300
|
-
required: ["id"], // The "id" named key is required
|
|
301
|
-
includes: ["id", "role", "age"] // Only these keys are allowed
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
- **`min`**: Minimum number of arguments required.
|
|
308
|
-
- **`max`**: Maximum number of arguments allowed.
|
|
309
|
-
- **`required`**: Array of keys that MUST be present in the arguments.
|
|
310
|
-
- **`includes`**: Whitelist of allowed argument keys. Any key not in this list will trigger an error.
|
|
311
|
-
|
|
312
|
-
### Content Validation (`content`)
|
|
313
|
-
|
|
314
|
-
Validates the inner content (body) of the block.
|
|
315
|
-
|
|
316
|
-
```javascript
|
|
317
|
-
myMapper.register("Summary", ({ content }) => {
|
|
318
|
-
return tag("p").body(content);
|
|
319
|
-
}, {
|
|
320
|
-
rules: {
|
|
321
|
-
content: {
|
|
322
|
-
maxLength: 100 // Content must be 100 characters or less
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
- **`maxLength`**: Maximum length of the content string.
|
|
89
|
+
## Supported Languages
|
|
329
90
|
|
|
330
|
-
|
|
91
|
+
* HTML
|
|
92
|
+
* Markdown
|
|
93
|
+
* MDX (Only ready components)
|
|
94
|
+
* JSON
|
|
331
95
|
|
|
332
|
-
Ensures a tag is used without content or children.
|
|
333
96
|
|
|
334
|
-
|
|
335
|
-
myMapper.register("Separator", () => {
|
|
336
|
-
return tag("hr").selfClose();
|
|
337
|
-
}, {
|
|
338
|
-
rules: {
|
|
339
|
-
is_Self_closing: true
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
- **`is_Self_closing`**: If `true`, SomMark will throw an error if the tag contains any content.
|
|
345
|
-
|
|
346
|
-
*Example input that passes:* `[Image = src: image.png, alt: Image][end]`
|
|
347
|
-
|
|
348
|
-
## Using Options
|
|
349
|
-
|
|
350
|
-
Options change how SomMark processes the content inside the block.
|
|
351
|
-
|
|
352
|
-
```javascript
|
|
353
|
-
import { Mapper } from "sommark";
|
|
354
|
-
const myMapper = new Mapper();
|
|
355
|
-
const { tag } = myMapper;
|
|
356
|
-
|
|
357
|
-
myMapper.register("Code", ({ content }) => {
|
|
358
|
-
return tag("pre").body(content);
|
|
359
|
-
}, {
|
|
360
|
-
escape: false,
|
|
361
|
-
rules: {
|
|
362
|
-
args: {
|
|
363
|
-
min: 1,
|
|
364
|
-
required: ["id"]
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}); // options
|
|
368
|
-
```
|
|
369
|
-
---
|
|
97
|
+
# Documentation
|
|
370
98
|
|
|
371
|
-
|
|
99
|
+
Detailed guides and API references are available in the `docs/` directory:
|
|
372
100
|
|
|
373
|
-
|
|
101
|
+
- **[Syntax Guide](docs/syntax.md)**: Master SomMark syntax (Blocks, Inline, At-Blocks).
|
|
102
|
+
- **[Core API](docs/core.md)**: Programmatic usage of the library (`transpile`, `lex`, `parse`).
|
|
103
|
+
- **[Mapper API](docs/mapper.md)**: Guide for creating custom mappers and rules.
|
|
104
|
+
- **[CLI Reference](docs/cli.md)**: Command line options and configurations.
|
|
105
|
+
- **[API Quick Reference](docs/api)**: Fast lookup for all classes and functions.
|
|
106
|
+
- **[Configuration Reference](docs/config.md)**: Guide for creating custom configurations.
|
package/cli/cli.mjs
CHANGED
|
@@ -3,6 +3,8 @@ import { getHelp } from "./commands/help.js";
|
|
|
3
3
|
import { printVersion, printHeader } from "./commands/version.js";
|
|
4
4
|
import { runBuild } from "./commands/build.js";
|
|
5
5
|
import { printOutput } from "./commands/print.js";
|
|
6
|
+
import { runInit } from "./commands/init.js";
|
|
7
|
+
import { runShow } from "./commands/show.js";
|
|
6
8
|
import { extensions } from "./constants.js";
|
|
7
9
|
|
|
8
10
|
// ========================================================================== //
|
|
@@ -33,7 +35,19 @@ async function main() {
|
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
// 4.
|
|
38
|
+
// 4. Init
|
|
39
|
+
if (command === "init") {
|
|
40
|
+
await runInit();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 5. Show
|
|
45
|
+
if (command === "show") {
|
|
46
|
+
await runShow(args[1]);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 6. Print to Console ( -p or --print )
|
|
37
51
|
|
|
38
52
|
const format = command ? command.replace(/^--/, "") : "";
|
|
39
53
|
|
package/cli/commands/build.js
CHANGED
|
@@ -4,6 +4,7 @@ import { cliError, formatMessage } from "../../core/errors.js";
|
|
|
4
4
|
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
|
+
import Json from "../../mappers/languages/json.js";
|
|
7
8
|
import { extensions } from "../constants.js";
|
|
8
9
|
import { isExist, readContent, createFile } from "../helpers/file.js";
|
|
9
10
|
import { loadConfig } from "../helpers/config.js";
|
|
@@ -56,7 +57,7 @@ export async function runBuild(format_option, sourcePath, outputFlag, outputFile
|
|
|
56
57
|
let mappingFile = config.mappingFile;
|
|
57
58
|
|
|
58
59
|
if (!mappingFile) {
|
|
59
|
-
mappingFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : null;
|
|
60
|
+
mappingFile = format === "html" ? HTML : format === "markdown" ? MARKDOWN : format === "mdx" ? MDX : format === "json" ? Json : null;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
// CLI Overrides
|
package/cli/commands/help.js
CHANGED
|
@@ -6,38 +6,41 @@ import { options } from "../constants.js";
|
|
|
6
6
|
// ========================================================================== //
|
|
7
7
|
|
|
8
8
|
export function getHelp(unknown_option = true) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const msg = [
|
|
10
|
+
`${unknown_option && process.argv[2] ? `<$red:Unrecognized option$> <$blue: '${process.argv[2]}'$>` : ""}`,
|
|
11
|
+
"{N}<$yellow:Usage:$> <$blue:sommark [option]$>",
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"{N}{N}<$yellow:Global Options:$>",
|
|
14
|
+
"{N} <$green:-h, --help$> <$cyan: Show help message$>",
|
|
15
|
+
"{N} <$green:-v, --version$> <$cyan: Show version information$>",
|
|
16
|
+
"{N} <$green:init$> <$cyan: Initialize global SomMark configuration directory$>",
|
|
17
|
+
"{N} <$green:show config$> <$cyan: Display the absolute paths to the active SomMark configuration files$>",
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
"{N}{N}<$yellow:Transpilation Options:$>",
|
|
20
|
+
"{N}<$yellow:Usage:$> <$blue:sommark [option] [targetFile] [option] [outputFile] [outputDir]$>",
|
|
21
|
+
"{N} <$green:--html$> <$cyan: Transpile to HTML$>",
|
|
22
|
+
"{N} <$green:--markdown$> <$cyan: Transpile to Markdown$>",
|
|
23
|
+
"{N} <$green:--mdx$> <$cyan: Transpile to MDX$>",
|
|
24
|
+
"{N} <$green:--json$> <$cyan: Transpile to json$>",
|
|
25
|
+
"{N} <$green:--text$> <$cyan: Transpile to plain text$>",
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
"{N}{N}<$yellow:Output Options:$>",
|
|
28
|
+
"{N} <$green:-p, --print$> <$cyan: Print output to console (stdout)$>",
|
|
29
|
+
"{N} <$green:-o$> <$cyan: Specify output filename (and optionally directory)$>",
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
"{N}{N}<$yellow:Examples:$>",
|
|
32
|
+
"{N} <$magenta:1. Basic usage:$> <$blue:sommark --html input.smark$>",
|
|
33
|
+
"{N} <$magenta:2. Print to console:$> <$blue:sommark --html -p input.smark$>",
|
|
34
|
+
"{N} <$magenta:3. Custom output:$> <$blue:sommark --html input.smark -o myOutput ./dist/$>"
|
|
35
|
+
].join("");
|
|
36
|
+
const help_msg = formatMessage(msg);
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
if (!options.includes(process.argv[2]) && unknown_option) {
|
|
39
|
+
console.log(help_msg);
|
|
40
|
+
process.exit(0);
|
|
41
|
+
} else if (process.argv[2] === "-h" || process.argv[2] === "--help") {
|
|
42
|
+
console.log(help_msg);
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
return help_msg;
|
|
43
46
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import { cliError, formatMessage } from "../../core/errors.js";
|
|
5
|
+
|
|
6
|
+
// ========================================================================== //
|
|
7
|
+
// Init Command //
|
|
8
|
+
// ========================================================================== //
|
|
9
|
+
|
|
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() {
|
|
22
|
+
try {
|
|
23
|
+
const configDir = getConfigDir();
|
|
24
|
+
const pluginsDir = path.join(configDir, "plugins");
|
|
25
|
+
const configFilePath = path.join(configDir, "smark.config.js");
|
|
26
|
+
|
|
27
|
+
// ======================================================
|
|
28
|
+
// Create directories
|
|
29
|
+
// ======================================================
|
|
30
|
+
|
|
31
|
+
await fs.mkdir(pluginsDir, { recursive: true });
|
|
32
|
+
|
|
33
|
+
// ======================================================
|
|
34
|
+
// Default configuration content
|
|
35
|
+
// ======================================================
|
|
36
|
+
|
|
37
|
+
const defaultConfigContent = `export default {
|
|
38
|
+
outputDir: "",
|
|
39
|
+
outputFile: "output",
|
|
40
|
+
mappingFile: "",
|
|
41
|
+
};
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
// ======================================================
|
|
45
|
+
// Check if config file already exists
|
|
46
|
+
// ======================================================
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await fs.access(configFilePath);
|
|
50
|
+
console.log(formatMessage(`<$yellow:Configuration already exists at:$> <$cyan:${configFilePath}$>`));
|
|
51
|
+
} catch {
|
|
52
|
+
// ======================================================
|
|
53
|
+
// Create default config file if it doesn't exist
|
|
54
|
+
// ======================================================
|
|
55
|
+
|
|
56
|
+
await fs.writeFile(configFilePath, defaultConfigContent, "utf-8");
|
|
57
|
+
console.log(formatMessage(`<$green:Initialized SomMark configuration at:$> <$cyan:${configFilePath}$>`));
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
cliError([
|
|
61
|
+
`{line}<$red:Failed to initialize SomMark configuration:$> <$magenta:${error.message}$>{line}`
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { cliError, formatMessage } from "../../core/errors.js";
|
|
4
|
+
import { getConfigDir } from "./init.js";
|
|
5
|
+
|
|
6
|
+
// ========================================================================== //
|
|
7
|
+
// Show Command //
|
|
8
|
+
// ========================================================================== //
|
|
9
|
+
|
|
10
|
+
export async function runShow(target) {
|
|
11
|
+
if (target === "config") {
|
|
12
|
+
try {
|
|
13
|
+
const configDir = getConfigDir();
|
|
14
|
+
const configFilePath = path.join(configDir, "smark.config.js");
|
|
15
|
+
const pluginsDir = path.join(configDir, "plugins");
|
|
16
|
+
//========================================================================== //
|
|
17
|
+
// Helper to check existence and format message //
|
|
18
|
+
//========================================================================== //
|
|
19
|
+
const checkPath = async (itemPath, isDir = false) => {
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(itemPath);
|
|
22
|
+
return `<$green:${itemPath}$> <$cyan:(Exists)$>`;
|
|
23
|
+
} catch {
|
|
24
|
+
return `<$red:${itemPath}$> <$yellow:(Not Found)$>`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const configStatus = await checkPath(configFilePath);
|
|
29
|
+
const pluginsStatus = await checkPath(pluginsDir, true);
|
|
30
|
+
|
|
31
|
+
console.log(formatMessage(`{N}<$yellow:SomMark Configuration Files:$>{N}`));
|
|
32
|
+
console.log(formatMessage(` <$magenta:Config File:$> ${configStatus}`));
|
|
33
|
+
console.log(formatMessage(` <$magenta:Plugins Dir:$> ${pluginsStatus}{N}`));
|
|
34
|
+
|
|
35
|
+
} catch (error) {
|
|
36
|
+
cliError([
|
|
37
|
+
`{line}<$red:Failed to retrieve configuration paths:$> <$magenta:${error.message}$>{line}`
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
cliError([
|
|
42
|
+
`{line}<$red:Invalid target for 'show' command:$> <$blue:'${target || ""}'$> `,
|
|
43
|
+
`<$yellow:Usage:$> <$cyan:sommark show config$>{line}`
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
}
|
package/cli/commands/version.js
CHANGED
|
@@ -14,7 +14,7 @@ export function printHeader() {
|
|
|
14
14
|
console.log(
|
|
15
15
|
[
|
|
16
16
|
`SomMark-${projectJson.version}`,
|
|
17
|
-
"SomMark is a structural markup language for writing structured
|
|
17
|
+
"SomMark is a structural markup language for writing structured content.",
|
|
18
18
|
"Copyright (C) Adam Elmi",
|
|
19
19
|
"Github: https://github.com/Adam-Elmi/SomMark"
|
|
20
20
|
]
|
package/cli/constants.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// CLI Constants //
|
|
3
3
|
// ========================================================================== //
|
|
4
4
|
|
|
5
|
-
export const options = ["-v", "--version", "-h", "--help", "--html", "--markdown", "--mdx", "--text", "--print", "-p"];
|
|
5
|
+
export const options = ["-v", "--version", "-h", "--help", "--html", "--markdown", "--mdx", "json", "--text", "--print", "-p"];
|
|
6
6
|
|
|
7
7
|
export const extensions = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
text: "txt",
|
|
9
|
+
html: "html",
|
|
10
|
+
markdown: "md",
|
|
11
|
+
mdx: "mdx",
|
|
12
|
+
json: "json"
|
|
12
13
|
};
|