sommark 3.1.0 → 3.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/README.md +7 -0
- package/cli/commands/build.js +2 -1
- package/cli/commands/init.js +2 -6
- package/cli/commands/list.js +17 -12
- package/cli/commands/print.js +7 -2
- package/cli/helpers/transpile.js +2 -1
- package/core/errors.js +22 -9
- package/core/labels.js +3 -0
- package/core/lexer.js +207 -590
- package/core/parser.js +201 -65
- package/core/pluginManager.js +33 -23
- package/core/plugins/comment-remover.js +3 -3
- package/core/plugins/module-system.js +163 -124
- package/core/plugins/raw-content-plugin.js +15 -9
- package/core/plugins/rules-validation-plugin.js +2 -2
- package/core/plugins/sommark-format.js +92 -72
- package/core/tokenTypes.js +2 -1
- package/core/transpiler.js +70 -8
- package/coverage_test.js +21 -0
- package/helpers/utils.js +27 -0
- package/index.js +25 -16
- package/mappers/languages/html.js +5 -10
- package/package.json +1 -1
- package/v3-todo.smark +68 -70
- package/core/plugins/quote-escaper.js +0 -37
- package/format.js +0 -23
- package/unformatted.smark +0 -90
package/README.md
CHANGED
|
@@ -109,3 +109,10 @@ Read our detailed guides in the `docs/` folder:
|
|
|
109
109
|
- **[Mapper API](docs/13.mapper.md)**: How to create new output formats.
|
|
110
110
|
- **[CLI Reference](docs/11.cli.md)**: Terminal commands and flags.
|
|
111
111
|
- **[API Quick Reference](docs/api)**: Fast lookup for all functions.
|
|
112
|
+
|
|
113
|
+
# Editor Support
|
|
114
|
+
|
|
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).
|
|
117
|
+
|
|
118
|
+
Information for integration can be found in the [SomMark-LSP](https://github.com/Adam-Elmi/SomMark-LSP) project.
|
package/cli/commands/build.js
CHANGED
|
@@ -16,7 +16,8 @@ import { transpile } from "../helpers/transpile.js";
|
|
|
16
16
|
async function generateOutput(outputDir, outputFile, format, sourcePath, mappingFile) {
|
|
17
17
|
let source_code = await readContent(sourcePath);
|
|
18
18
|
source_code = source_code.toString();
|
|
19
|
-
const
|
|
19
|
+
const absolutePath = path.resolve(process.cwd(), sourcePath);
|
|
20
|
+
const output = await transpile({ src: source_code, format, filename: absolutePath, mappingFile });
|
|
20
21
|
const finalPath = path.join(outputDir, `${outputFile}.${extensions[format]}`);
|
|
21
22
|
await createFile(outputDir, `${outputFile}.${extensions[format]}`, output);
|
|
22
23
|
return finalPath;
|
package/cli/commands/init.js
CHANGED
|
@@ -20,15 +20,11 @@ export function getConfigDir() {
|
|
|
20
20
|
|
|
21
21
|
export async function runInit() {
|
|
22
22
|
try {
|
|
23
|
-
const configDir = getConfigDir();
|
|
24
|
-
const pluginsDir = path.join(configDir, "plugins");
|
|
25
|
-
const configFilePath = path.join(configDir, "smark.config.js");
|
|
26
|
-
|
|
27
23
|
// ======================================================
|
|
28
|
-
// Create
|
|
24
|
+
// Create configuration directory
|
|
29
25
|
// ======================================================
|
|
30
26
|
|
|
31
|
-
await fs.mkdir(
|
|
27
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
32
28
|
|
|
33
29
|
// ======================================================
|
|
34
30
|
// Default configuration content
|
package/cli/commands/list.js
CHANGED
|
@@ -10,7 +10,16 @@ import { formatMessage } from "../../core/errors.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export async function runListPlugins(args) {
|
|
12
12
|
const config = await loadConfig();
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
const sm = new SomMark({
|
|
15
|
+
src: "",
|
|
16
|
+
format: "html",
|
|
17
|
+
plugins: config.plugins,
|
|
18
|
+
excludePlugins: config.excludePlugins,
|
|
19
|
+
priority: config.priority
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const enabledPlugins = sm.plugins;
|
|
14
23
|
|
|
15
24
|
// Filter flags
|
|
16
25
|
const showInternal = args.includes("--internal") || args.includes("-i");
|
|
@@ -24,16 +33,14 @@ export async function runListPlugins(args) {
|
|
|
24
33
|
// 1. Internal Plugins
|
|
25
34
|
if (showInternal || showAll) {
|
|
26
35
|
const internal = enabledPlugins.filter(p => {
|
|
27
|
-
|
|
28
|
-
return BUILT_IN_PLUGINS.some(bp => bp.name === name);
|
|
36
|
+
return BUILT_IN_PLUGINS.some(bp => bp.name === p.name);
|
|
29
37
|
});
|
|
30
38
|
|
|
31
39
|
if (internal.length > 0) {
|
|
32
40
|
console.log(formatMessage(` <$magenta:Internal Plugins (Built-in):$>{N}`));
|
|
33
41
|
internal.forEach(p => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
printPluginInfo(name, pluginObj);
|
|
42
|
+
const pluginObj = BUILT_IN_PLUGINS.find(bp => bp.name === p.name);
|
|
43
|
+
printPluginInfo(p.name, pluginObj);
|
|
37
44
|
});
|
|
38
45
|
found = true;
|
|
39
46
|
}
|
|
@@ -42,15 +49,13 @@ export async function runListPlugins(args) {
|
|
|
42
49
|
// 2. External Plugins
|
|
43
50
|
if (showExternal || showAll) {
|
|
44
51
|
const external = enabledPlugins.filter(p => {
|
|
45
|
-
|
|
46
|
-
return !BUILT_IN_PLUGINS.some(bp => bp.name === name);
|
|
52
|
+
return !BUILT_IN_PLUGINS.some(bp => bp.name === p.name);
|
|
47
53
|
});
|
|
48
54
|
|
|
49
55
|
if (external.length > 0) {
|
|
50
56
|
console.log(formatMessage(`${found ? "{N}" : ""} <$magenta:External Plugins (User-defined):$>{N}`));
|
|
51
57
|
external.forEach(p => {
|
|
52
|
-
|
|
53
|
-
printPluginInfo(name, typeof p === "object" ? p : null);
|
|
58
|
+
printPluginInfo(p.name || "Unknown", p);
|
|
54
59
|
});
|
|
55
60
|
found = true;
|
|
56
61
|
}
|
|
@@ -101,7 +106,7 @@ export async function runListPipeline() {
|
|
|
101
106
|
console.log(formatMessage(` <$magenta:${phase.name}$>`));
|
|
102
107
|
if (matched.length > 0) {
|
|
103
108
|
matched.forEach(p => {
|
|
104
|
-
console.log(formatMessage(` <$green
|
|
109
|
+
console.log(formatMessage(` <$green:└── ${p.name}$> <$cyan:[${Array.isArray(p.type) ? p.type.join(", ") : p.type}]$>`));
|
|
105
110
|
});
|
|
106
111
|
} else {
|
|
107
112
|
console.log(formatMessage(` <$yellow: (None registered)$>`));
|
|
@@ -114,6 +119,6 @@ export async function runListPipeline() {
|
|
|
114
119
|
function printPluginInfo(name, pluginObj) {
|
|
115
120
|
const author = pluginObj?.author || "Unknown";
|
|
116
121
|
const desc = pluginObj?.description || "No description provided.";
|
|
117
|
-
console.log(formatMessage(` <$green
|
|
122
|
+
console.log(formatMessage(` <$green:└── ${name}$> - <$cyan:by ${author}$>`));
|
|
118
123
|
console.log(formatMessage(` <$yellow:${desc}$>`));
|
|
119
124
|
}
|
package/cli/commands/print.js
CHANGED
|
@@ -13,11 +13,12 @@ export async function printOutput(format, filePath) {
|
|
|
13
13
|
const fileName = path.basename(filePath);
|
|
14
14
|
console.log(formatMessage(`{line}<$blue: Printing output for$> <$yellow:'${fileName}'$>{line}`));
|
|
15
15
|
let source_code = await readContent(filePath);
|
|
16
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
16
17
|
if (format === "json") {
|
|
17
|
-
const output = await transpile({ src: source_code.toString(), format });
|
|
18
|
+
const output = await transpile({ src: source_code.toString(), format, filename: absolutePath });
|
|
18
19
|
console.log(JSON.stringify(JSON.parse(output, null, 2), null, 2));
|
|
19
20
|
} else {
|
|
20
|
-
console.log(await transpile({ src: source_code.toString(), format }));
|
|
21
|
+
console.log(await transpile({ src: source_code.toString(), format, filename: absolutePath }));
|
|
21
22
|
}
|
|
22
23
|
} else {
|
|
23
24
|
cliError([`{line}<$red:File$> <$blue:'${filePath}'$> <$red: is not found$>{line}`]);
|
|
@@ -34,9 +35,11 @@ export async function printLex(filePath) {
|
|
|
34
35
|
const source_code = await readContent(filePath);
|
|
35
36
|
const config = await loadConfig();
|
|
36
37
|
|
|
38
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
37
39
|
const smark = new SomMark({
|
|
38
40
|
src: source_code.toString(),
|
|
39
41
|
format: "text",
|
|
42
|
+
filename: absolutePath,
|
|
40
43
|
plugins: config.plugins,
|
|
41
44
|
priority: config.priority
|
|
42
45
|
});
|
|
@@ -58,9 +61,11 @@ export async function printParse(filePath) {
|
|
|
58
61
|
const source_code = await readContent(filePath);
|
|
59
62
|
const config = await loadConfig();
|
|
60
63
|
|
|
64
|
+
const absolutePath = path.resolve(process.cwd(), filePath);
|
|
61
65
|
const smark = new SomMark({
|
|
62
66
|
src: source_code.toString(),
|
|
63
67
|
format: "text",
|
|
68
|
+
filename: absolutePath,
|
|
64
69
|
plugins: config.plugins,
|
|
65
70
|
priority: config.priority
|
|
66
71
|
});
|
package/cli/helpers/transpile.js
CHANGED
|
@@ -15,7 +15,7 @@ const default_mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [m
|
|
|
15
15
|
// ========================================================================== //
|
|
16
16
|
// Transpile Function //
|
|
17
17
|
// ========================================================================== //
|
|
18
|
-
export async function transpile({ src, format, mappingFile = "" }) {
|
|
18
|
+
export async function transpile({ src, format, filename = null, mappingFile = "" }) {
|
|
19
19
|
const config = await loadConfig();
|
|
20
20
|
let finalMapper = mappingFile;
|
|
21
21
|
|
|
@@ -39,6 +39,7 @@ export async function transpile({ src, format, mappingFile = "" }) {
|
|
|
39
39
|
const smark = new SomMark({
|
|
40
40
|
src,
|
|
41
41
|
format,
|
|
42
|
+
filename,
|
|
42
43
|
mapperFile: finalMapper,
|
|
43
44
|
plugins: config.plugins,
|
|
44
45
|
priority: config.priority
|
package/core/errors.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import colorize from "../helpers/colorize.js";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* SomMark Errors
|
|
5
|
+
* Handles formatting and throwing errors with beautiful CLI coloring and pointers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ========================================================================== //
|
|
9
|
+
// Message Formatting //
|
|
10
|
+
// ========================================================================== //
|
|
11
|
+
|
|
3
12
|
function formatMessage(text) {
|
|
4
13
|
/*
|
|
5
|
-
Format:
|
|
6
|
-
{line} =
|
|
7
|
-
{N}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
[No Nest]
|
|
11
|
-
-----------------------------
|
|
12
|
-
Example: <$red: Expected token$> <$magenta: ']'$> {N} at line <$red: 1$> {N} column <$green: 2$> {line}
|
|
14
|
+
Format System:
|
|
15
|
+
{line} = Draws a horizontal line
|
|
16
|
+
{N} = Inserts a newline
|
|
17
|
+
<$color: Text$> = Colors the text (supports red, yellow, green, blue, magenta, cyan)
|
|
13
18
|
*/
|
|
14
19
|
const horizontal_rule = "\n----------------------------------------------------------------------------------------------\n";
|
|
15
|
-
const pattern = /<\$([^:]+):([
|
|
20
|
+
const pattern = /<\$([^:]+):([\s\S]*?)\$>/g;
|
|
16
21
|
|
|
17
22
|
if (Array.isArray(text)) {
|
|
18
23
|
text = text.join("");
|
|
@@ -33,6 +38,10 @@ function formatMessage(text) {
|
|
|
33
38
|
return text;
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
// ========================================================================== //
|
|
42
|
+
// Error Classes //
|
|
43
|
+
// ========================================================================== //
|
|
44
|
+
|
|
36
45
|
class CustomError extends Error {
|
|
37
46
|
constructor(message, name) {
|
|
38
47
|
super(message);
|
|
@@ -80,6 +89,10 @@ class SommarkError extends CustomError {
|
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
|
|
92
|
+
// ========================================================================== //
|
|
93
|
+
// Error Dispatcher (Helper) //
|
|
94
|
+
// ========================================================================== //
|
|
95
|
+
|
|
83
96
|
function getError(type) {
|
|
84
97
|
const validate_msg = msg => Array.isArray(msg) && msg.length > 0;
|
|
85
98
|
switch (type) {
|
package/core/labels.js
CHANGED
|
@@ -3,6 +3,8 @@ export const BLOCK = "Block",
|
|
|
3
3
|
INLINE = "Inline",
|
|
4
4
|
ATBLOCK = "AtBlock",
|
|
5
5
|
COMMENT = "Comment",
|
|
6
|
+
IMPORT = "Import",
|
|
7
|
+
USE_MODULE = "$use-module",
|
|
6
8
|
SEMICOLON = "Semicolon",
|
|
7
9
|
BLOCKCOMMA = "Block-comma",
|
|
8
10
|
ATBLOCKCOMMA = "Atblock-comma",
|
|
@@ -21,4 +23,5 @@ export const BLOCK = "Block",
|
|
|
21
23
|
at_value = "At Value",
|
|
22
24
|
at_id_2 = "At Identifier 2",
|
|
23
25
|
at_end = "Atblock End",
|
|
26
|
+
block_end_2 = "Block End 2",
|
|
24
27
|
end_keyword = "end";
|