sommark 3.3.4 → 4.0.1
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 +98 -82
- package/assets/logo.json +28 -0
- package/assets/smark.logo.png +0 -0
- package/assets/smark.logo.svg +21 -0
- package/cli/cli.mjs +7 -17
- package/cli/commands/build.js +26 -6
- package/cli/commands/color.js +22 -26
- package/cli/commands/help.js +10 -10
- package/cli/commands/init.js +20 -31
- package/cli/commands/print.js +18 -16
- package/cli/commands/show.js +4 -0
- package/cli/commands/version.js +6 -0
- package/cli/constants.js +9 -5
- package/cli/helpers/config.js +11 -0
- package/cli/helpers/file.js +17 -6
- package/cli/helpers/transpile.js +15 -17
- package/core/errors.js +49 -25
- package/core/formats.js +7 -3
- package/core/formatter.js +215 -0
- package/core/helpers/config-loader.js +40 -75
- package/core/labels.js +21 -9
- package/core/lexer.js +491 -212
- package/core/modules.js +164 -0
- package/core/parser.js +516 -389
- package/core/tokenTypes.js +36 -1
- package/core/transpiler.js +238 -154
- package/core/validator.js +79 -0
- package/formatter/mark.js +203 -43
- package/formatter/tag.js +202 -32
- package/grammar.ebnf +57 -50
- package/helpers/colorize.js +26 -13
- package/helpers/dedent.js +19 -0
- package/helpers/escapeHTML.js +13 -6
- package/helpers/kebabize.js +6 -0
- package/helpers/peek.js +9 -0
- package/helpers/removeChar.js +26 -13
- package/helpers/safeDataParser.js +114 -0
- package/helpers/utils.js +140 -158
- package/index.js +186 -188
- package/mappers/languages/html.js +105 -213
- package/mappers/languages/json.js +122 -171
- package/mappers/languages/markdown.js +355 -108
- package/mappers/languages/mdx.js +76 -120
- package/mappers/languages/xml.js +114 -0
- package/mappers/mapper.js +152 -123
- package/mappers/shared/index.js +22 -0
- package/package.json +26 -6
- package/SOMMARK-SPEC.md +0 -481
- package/cli/commands/list.js +0 -124
- package/constants/html_tags.js +0 -146
- package/core/pluginManager.js +0 -149
- package/core/plugins/comment-remover.js +0 -47
- package/core/plugins/module-system.js +0 -176
- package/core/plugins/raw-content-plugin.js +0 -78
- package/core/plugins/rules-validation-plugin.js +0 -231
- package/core/plugins/sommark-format.js +0 -244
- package/coverage_test.js +0 -21
- package/debug.js +0 -15
- package/helpers/camelize.js +0 -2
- package/helpers/defaultTheme.js +0 -3
- package/test_format_fix.js +0 -42
- package/v3-todo.smark +0 -73
package/helpers/utils.js
CHANGED
|
@@ -1,188 +1,170 @@
|
|
|
1
1
|
import { sommarkError } from "../core/errors.js";
|
|
2
|
+
import * as labels from "../core/labels.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* Checks if a
|
|
5
|
-
* @param {
|
|
6
|
-
* @returns {boolean}
|
|
5
|
+
* Checks if a value is a plain object.
|
|
6
|
+
* @param {any} val - The value to check.
|
|
7
|
+
* @returns {boolean} - True if it's an object.
|
|
7
8
|
*/
|
|
8
|
-
export
|
|
9
|
-
return (status || "").trim() === "x" || (status || "").trim().toLowerCase() === "done";
|
|
10
|
-
}
|
|
9
|
+
export const isObject = (val) => typeof val === "object" && val !== null && !Array.isArray(val);
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
12
|
+
* Checks if a value is an array.
|
|
13
|
+
* @param {any} val - The value to check.
|
|
14
|
+
* @returns {boolean} - True if it's an array.
|
|
14
15
|
*/
|
|
15
|
-
export
|
|
16
|
-
let result;
|
|
17
|
-
for (const outputValue of outputs) {
|
|
18
|
-
if (typeof outputValue.id === "string") {
|
|
19
|
-
if (outputValue.id === targetId) {
|
|
20
|
-
result = outputValue;
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
} else if (Array.isArray(outputValue.id)) {
|
|
24
|
-
for (const id of outputValue.id) {
|
|
25
|
-
if (id === targetId) {
|
|
26
|
-
result = outputValue;
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
16
|
+
export const isArray = (val) => Array.isArray(val);
|
|
34
17
|
|
|
35
18
|
/**
|
|
36
|
-
*
|
|
19
|
+
* Checks if a value is a string.
|
|
20
|
+
* @param {any} val - The value to check.
|
|
21
|
+
* @returns {boolean} - True if it's a string.
|
|
37
22
|
*/
|
|
38
|
-
export
|
|
39
|
-
if (!Array.isArray(args)) {
|
|
40
|
-
sommarkError([`{line}<$red:TypeError:$> <$yellow:args must be an array$>{line}`]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (index === undefined && key === undefined) {
|
|
44
|
-
sommarkError([`{line}<$red:ReferenceError:> <$yellow:At least one of 'index' or 'key' must be provided$>{line}`]);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const validate = value => {
|
|
48
|
-
if (value === undefined) return false;
|
|
49
|
-
if (!type) return true;
|
|
50
|
-
const evaluated = setType ? setType(value) : value;
|
|
51
|
-
return typeof evaluated === type;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
if (index !== undefined && validate(args[index])) {
|
|
55
|
-
return args[index];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (key !== undefined && validate(args[key])) {
|
|
59
|
-
return args[key];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return fallBack;
|
|
63
|
-
}
|
|
23
|
+
export const isString = (val) => typeof val === "string";
|
|
64
24
|
|
|
65
25
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @param {
|
|
68
|
-
* @
|
|
69
|
-
* @returns {number}
|
|
26
|
+
* Checks if a value is a number and not NaN.
|
|
27
|
+
* @param {any} val - The value to check.
|
|
28
|
+
* @returns {boolean} - True if it's a valid number.
|
|
70
29
|
*/
|
|
71
|
-
export
|
|
72
|
-
const matrix = [];
|
|
73
|
-
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
|
|
74
|
-
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
|
75
|
-
|
|
76
|
-
for (let i = 1; i <= b.length; i++) {
|
|
77
|
-
for (let j = 1; j <= a.length; j++) {
|
|
78
|
-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
79
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
80
|
-
} else {
|
|
81
|
-
matrix[i][j] = Math.min(
|
|
82
|
-
matrix[i - 1][j - 1] + 1,
|
|
83
|
-
matrix[i][j - 1] + 1,
|
|
84
|
-
matrix[i - 1][j] + 1
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return matrix[b.length][a.length];
|
|
90
|
-
}
|
|
30
|
+
export const isNumber = (val) => typeof val === "number" && !isNaN(val);
|
|
91
31
|
|
|
92
32
|
/**
|
|
93
|
-
*
|
|
33
|
+
* Checks if a value is true or false.
|
|
34
|
+
* @param {any} val - The value to check.
|
|
35
|
+
* @returns {boolean} - True if it's a boolean.
|
|
94
36
|
*/
|
|
95
|
-
export
|
|
96
|
-
if (!data) return "";
|
|
97
|
-
|
|
98
|
-
if (typeof data === "string") {
|
|
99
|
-
data = data.split(/\r?\n/);
|
|
100
|
-
} else if (!Array.isArray(data) || data.length === 0) {
|
|
101
|
-
return "";
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let tableHTML = `<table class="sommark-table">\n<thead>\n<tr>`;
|
|
105
|
-
for (const header of headers) {
|
|
106
|
-
tableHTML += `<th>${escapeFn(header)}</th>`;
|
|
107
|
-
}
|
|
108
|
-
tableHTML += "</tr>\n</thead>\n<tbody>\n";
|
|
109
|
-
|
|
110
|
-
for (const row of data) {
|
|
111
|
-
const trimmedRow = row.trim();
|
|
112
|
-
if (!trimmedRow) continue;
|
|
113
|
-
|
|
114
|
-
const rowData = trimmedRow.split(/(?<!\\),/).map(cell => {
|
|
115
|
-
let text = cell.trim();
|
|
116
|
-
if (text.endsWith(";")) text = text.slice(0, -1);
|
|
117
|
-
return text.replace(/\\(.)/g, "$1");
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
tableHTML += "<tr>";
|
|
121
|
-
for (const cell of rowData) {
|
|
122
|
-
tableHTML += `<td>${escapeFn(cell.trim())}</td>`;
|
|
123
|
-
}
|
|
124
|
-
tableHTML += "</tr>\n";
|
|
125
|
-
}
|
|
37
|
+
export const isBool = (val) => typeof val === "boolean";
|
|
126
38
|
|
|
127
|
-
|
|
128
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Checks if a value is null.
|
|
41
|
+
* @param {any} val - The value to check.
|
|
42
|
+
* @returns {boolean} - True if it's null.
|
|
43
|
+
*/
|
|
44
|
+
export const isNull = (val) => val === null;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Checks if a value is missing (undefined).
|
|
48
|
+
* @param {any} val - The value to check.
|
|
49
|
+
* @returns {boolean} - True if it's undefined.
|
|
50
|
+
*/
|
|
51
|
+
export const isUndefined = (val) => val === undefined;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Finds a matching output definition for a tag ID from a list of registered outputs.
|
|
55
|
+
* Uses case-insensitive matching. Handles both string and array-based ID definitions.
|
|
56
|
+
*
|
|
57
|
+
* @param {Array<Object>} outputs - List of registered tag outputs.
|
|
58
|
+
* @param {string} targetId - The tag identifier to look for.
|
|
59
|
+
* @returns {Object|undefined} - The matched output entry or undefined.
|
|
60
|
+
*/
|
|
61
|
+
export function matchedValue(outputs, targetId) {
|
|
62
|
+
if (!outputs || !targetId) return undefined;
|
|
63
|
+
for (let i = outputs.length - 1; i >= 0; i--) {
|
|
64
|
+
const outputValue = outputs[i];
|
|
65
|
+
const lowerTarget = targetId.toLowerCase();
|
|
66
|
+
|
|
67
|
+
if (typeof outputValue.id === "string") {
|
|
68
|
+
if (outputValue.id.toLowerCase() === lowerTarget) {
|
|
69
|
+
return outputValue;
|
|
70
|
+
}
|
|
71
|
+
} else if (Array.isArray(outputValue.id)) {
|
|
72
|
+
if (outputValue.id.some(id => id.toLowerCase() === lowerTarget)) {
|
|
73
|
+
return outputValue;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
129
78
|
}
|
|
130
79
|
|
|
131
80
|
/**
|
|
132
|
-
*
|
|
81
|
+
* Safely retrieves an argument value, supporting both positional (number) and named (string) keys.
|
|
82
|
+
* Includes validation against a specific type and optional type casting.
|
|
83
|
+
*
|
|
84
|
+
* @param {Object} options - Resolution options.
|
|
85
|
+
* @param {Object} options.args - The argument object from an AST node.
|
|
86
|
+
* @param {number} [options.index] - The positional index (for V4 Global Indexing).
|
|
87
|
+
* @param {string} [options.key] - The named key.
|
|
88
|
+
* @param {string|null} [options.type=null] - Expected typeof result (e.g., 'string', 'boolean').
|
|
89
|
+
* @param {Function|null} [options.setType=null] - Optional function to cast the value before validation.
|
|
90
|
+
* @param {any} [options.fallBack=null] - Value to return if resolution or validation fails.
|
|
91
|
+
* @returns {any} - The resolved argument value or the fallback.
|
|
133
92
|
*/
|
|
134
|
-
export function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
93
|
+
export function safeArg({ args, index, key, type = null, setType = null, fallBack = null }) {
|
|
94
|
+
if (typeof args !== 'object' || args === null) {
|
|
95
|
+
sommarkError([`{line}<$red:TypeError:$> <$yellow:args must be an object$>{line}`]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (index === undefined && key === undefined) {
|
|
99
|
+
sommarkError([`{line}<$red:ReferenceError:> <$yellow:At least one of 'index' or 'key' must be provided$>{line}`]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const validate = value => {
|
|
103
|
+
if (value === undefined) return false;
|
|
104
|
+
|
|
105
|
+
// Handle explicit type check functions (e.g., isObject, isArray)
|
|
106
|
+
if (typeof type === 'function') {
|
|
107
|
+
return type(value);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!type) return true;
|
|
111
|
+
const evaluated = setType ? setType(value) : value;
|
|
112
|
+
return typeof evaluated === type;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
if (index !== undefined && validate(args[index])) {
|
|
116
|
+
return args[index];
|
|
155
117
|
}
|
|
156
118
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
119
|
+
if (key !== undefined && validate(args[key])) {
|
|
120
|
+
return args[key];
|
|
121
|
+
}
|
|
160
122
|
|
|
161
|
-
|
|
123
|
+
return fallBack;
|
|
162
124
|
}
|
|
163
125
|
|
|
164
126
|
/**
|
|
165
|
-
*
|
|
127
|
+
* Extracts and returns all positional arguments from the Object-based 'args' structure of V4.
|
|
128
|
+
*
|
|
129
|
+
* @param {Object} args - The AST node's argument object.
|
|
130
|
+
* @returns {Array<any>} - An ordered array of positional argument values.
|
|
166
131
|
*/
|
|
167
|
-
export function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
html += escapeFn(item.text);
|
|
178
|
-
if (item.children && item.children.length > 0) {
|
|
179
|
-
html += renderItems(item.children);
|
|
180
|
-
}
|
|
181
|
-
html += `</li>`;
|
|
182
|
-
}
|
|
183
|
-
html += `</${tag}>`;
|
|
184
|
-
return html;
|
|
185
|
-
};
|
|
132
|
+
export function getPositionalArgs(args) {
|
|
133
|
+
if (!args) return [];
|
|
134
|
+
const keys = Object.keys(args);
|
|
135
|
+
const result = keys
|
|
136
|
+
.filter(k => !isNaN(parseInt(k)))
|
|
137
|
+
.sort((a, b) => parseInt(a) - parseInt(b))
|
|
138
|
+
.map(k => args[k]);
|
|
139
|
+
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
186
142
|
|
|
187
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Calculates the Levenshtein distance between two strings.
|
|
145
|
+
* Used for "Did you mean?" suggestions and fuzzy matching in validation.
|
|
146
|
+
*
|
|
147
|
+
* @param {string} a - First string.
|
|
148
|
+
* @param {string} b - Second string.
|
|
149
|
+
* @returns {number} - The edit distance between the two strings.
|
|
150
|
+
*/
|
|
151
|
+
export function levenshtein(a, b) {
|
|
152
|
+
const matrix = [];
|
|
153
|
+
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
|
|
154
|
+
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
|
155
|
+
|
|
156
|
+
for (let i = 1; i <= b.length; i++) {
|
|
157
|
+
for (let j = 1; j <= a.length; j++) {
|
|
158
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
159
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
160
|
+
} else {
|
|
161
|
+
matrix[i][j] = Math.min(
|
|
162
|
+
matrix[i - 1][j - 1] + 1,
|
|
163
|
+
matrix[i][j - 1] + 1,
|
|
164
|
+
matrix[i - 1][j] + 1
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return matrix[b.length][a.length];
|
|
188
170
|
}
|