sommark 2.1.1 → 2.2.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 +14 -0
- package/README.md +3 -299
- package/cli/cli.mjs +15 -1
- package/cli/commands/help.js +2 -0
- package/cli/commands/init.js +64 -0
- package/cli/commands/show.js +46 -0
- package/cli/commands/version.js +1 -1
- package/cli/helpers/config.js +14 -5
- package/cli/helpers/transpile.js +7 -9
- package/core/formats.js +3 -2
- package/core/lexer.js +20 -13
- package/core/parser.js +18 -9
- package/core/transpiler.js +34 -20
- package/formatter/mark.js +3 -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 +55 -9
- package/package.json +2 -5
- package/lib/highlight.js +0 -11
package/core/lexer.js
CHANGED
|
@@ -67,7 +67,9 @@ function concatText(input, index, scope_state, extraConditions = []) {
|
|
|
67
67
|
text += char;
|
|
68
68
|
}
|
|
69
69
|
if (!text) {
|
|
70
|
-
sommarkError([
|
|
70
|
+
sommarkError([
|
|
71
|
+
`{line}From: <$magenta:concatText function:$>{N}<$red:Concatenation failed:$> string value is <$yellow:'${text}'$>{line}`
|
|
72
|
+
]);
|
|
71
73
|
}
|
|
72
74
|
return text;
|
|
73
75
|
} else {
|
|
@@ -117,7 +119,9 @@ function concatEscape(input, index) {
|
|
|
117
119
|
sommarkError(["{line}<$red:Next character is not found:$> <$yellow:There is no character after escape character!$>{line}"]);
|
|
118
120
|
}
|
|
119
121
|
if (!str) {
|
|
120
|
-
sommarkError([
|
|
122
|
+
sommarkError([
|
|
123
|
+
`{line}From: <$magenta:concatEscape function:$>{N}<$red:Concatenation failed:$> string value is <$yellow:'${str}'$>{line}`
|
|
124
|
+
]);
|
|
121
125
|
}
|
|
122
126
|
if (WHITESPACE_SET.has(str[1])) {
|
|
123
127
|
const matchedCharacter = Array.from(WHITESPACE_SET).find(ch => ch === str[1]);
|
|
@@ -158,7 +162,9 @@ function concatChar(input, index, stop_at_char) {
|
|
|
158
162
|
]);
|
|
159
163
|
}
|
|
160
164
|
if (!str) {
|
|
161
|
-
sommarkError([
|
|
165
|
+
sommarkError([
|
|
166
|
+
`{line}From: <$magenta:concatChar function:$>{N}<$red:Concatenation failed:$> string value is <$yellow:'${str}'$>{line}`
|
|
167
|
+
]);
|
|
162
168
|
}
|
|
163
169
|
return str;
|
|
164
170
|
} else {
|
|
@@ -185,10 +191,10 @@ function lexer(src) {
|
|
|
185
191
|
tokens.push({ type, value, line, start, end, depth: depth_stack.length });
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
const updateMetadata =
|
|
194
|
+
const updateMetadata = text => {
|
|
189
195
|
const newlines = updateNewLine(text) || 0;
|
|
190
196
|
if (newlines > 0) {
|
|
191
|
-
const lines = text.split(
|
|
197
|
+
const lines = text.split("\n");
|
|
192
198
|
const lastLineLength = lines[lines.length - 1].length;
|
|
193
199
|
start = end + 1;
|
|
194
200
|
end = lastLineLength;
|
|
@@ -431,7 +437,13 @@ function lexer(src) {
|
|
|
431
437
|
// ========================================================================== //
|
|
432
438
|
// Token: Block Value //
|
|
433
439
|
// ========================================================================== //
|
|
434
|
-
else if (
|
|
440
|
+
else if (
|
|
441
|
+
(previous_value === "=" ||
|
|
442
|
+
previous_value === BLOCKCOMMA ||
|
|
443
|
+
previous_value === BLOCKCOLON ||
|
|
444
|
+
previous_value === block_value) &&
|
|
445
|
+
!scope_state
|
|
446
|
+
) {
|
|
435
447
|
temp_str = concatChar(src, i, ["]", "\\", ",", ":"]);
|
|
436
448
|
i += temp_str.length - 1;
|
|
437
449
|
const nextToken = peek(src, i, 1);
|
|
@@ -484,12 +496,7 @@ function lexer(src) {
|
|
|
484
496
|
previous_value === inline_value) &&
|
|
485
497
|
!scope_state
|
|
486
498
|
) {
|
|
487
|
-
temp_str = concatChar(src, i, [
|
|
488
|
-
")",
|
|
489
|
-
"\\",
|
|
490
|
-
",",
|
|
491
|
-
previous_value === INLINECOLON ? ":" : null
|
|
492
|
-
]);
|
|
499
|
+
temp_str = concatChar(src, i, [")", "\\", ",", previous_value === INLINECOLON ? ":" : null]);
|
|
493
500
|
i += temp_str.length - 1;
|
|
494
501
|
// Update Metadata
|
|
495
502
|
updateMetadata(temp_str);
|
|
@@ -588,7 +595,7 @@ function lexer(src) {
|
|
|
588
595
|
return tokens;
|
|
589
596
|
} else {
|
|
590
597
|
lexerError([
|
|
591
|
-
`{line}<$red:Invalid SomMark syntax:$> <$yellow:Expected source input to be a string, got$> <$blue: '${typeof src}'
|
|
598
|
+
`{line}<$red:Invalid SomMark syntax:$> ${src === "" ? "<$yellow: Got empty string '' $>" : `<$yellow:Expected source input to be a string, got$> <$blue: '${typeof src}'$>`}{line}`
|
|
592
599
|
]);
|
|
593
600
|
}
|
|
594
601
|
}
|
package/core/parser.js
CHANGED
|
@@ -102,7 +102,6 @@ const updateData = (tokens, i) => {
|
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
|
|
106
105
|
const errorMessage = (tokens, i, expectedValue, behindValue, frontText) => {
|
|
107
106
|
const tokensUntilError = tokens.slice(0, i);
|
|
108
107
|
const contextText = tokensUntilError.map(t => t.value).join("");
|
|
@@ -123,7 +122,6 @@ const errorMessage = (tokens, i, expectedValue, behindValue, frontText) => {
|
|
|
123
122
|
// ========================================================================== //
|
|
124
123
|
function parseKey(tokens, i) {
|
|
125
124
|
let key = current_token(tokens, i).value.trim();
|
|
126
|
-
validateName(key);
|
|
127
125
|
// ========================================================================== //
|
|
128
126
|
// consume Key //
|
|
129
127
|
// ========================================================================== //
|
|
@@ -261,7 +259,12 @@ function parseBlock(tokens, i) {
|
|
|
261
259
|
let [key, keyIndex] = parseKey(tokens, i);
|
|
262
260
|
k = key;
|
|
263
261
|
i = keyIndex;
|
|
262
|
+
const prev = current_token(tokens, i);
|
|
264
263
|
i = parseColon(tokens, i, block_id);
|
|
264
|
+
if (current_token(tokens, i).type !== TOKEN_TYPES.VALUE && current_token(tokens, i).type !== TOKEN_TYPES.ESCAPE) {
|
|
265
|
+
parserError(errorMessage(tokens, i, block_value, ":"));
|
|
266
|
+
}
|
|
267
|
+
validateName(k);
|
|
265
268
|
continue;
|
|
266
269
|
} else if (
|
|
267
270
|
current_token(tokens, i) &&
|
|
@@ -403,6 +406,7 @@ function parseInline(tokens, i) {
|
|
|
403
406
|
parserError(errorMessage(tokens, i, inline_value, "("));
|
|
404
407
|
}
|
|
405
408
|
inlineNode.value = current_token(tokens, i).value;
|
|
409
|
+
inlineNode.depth = current_token(tokens, i).depth;
|
|
406
410
|
// ========================================================================== //
|
|
407
411
|
// consume Inline Value //
|
|
408
412
|
// ========================================================================== //
|
|
@@ -467,11 +471,12 @@ function parseInline(tokens, i) {
|
|
|
467
471
|
parserError(errorMessage(tokens, i, inline_value, ":"));
|
|
468
472
|
}
|
|
469
473
|
let v = "";
|
|
470
|
-
|
|
471
474
|
const pushArg = () => {
|
|
472
475
|
if (v !== "") {
|
|
473
476
|
inlineNode.args.push(v);
|
|
474
|
-
|
|
477
|
+
if (!Number.isInteger(Number(v))) {
|
|
478
|
+
inlineNode.args[v] = v;
|
|
479
|
+
}
|
|
475
480
|
v = "";
|
|
476
481
|
}
|
|
477
482
|
};
|
|
@@ -519,11 +524,11 @@ function parseInline(tokens, i) {
|
|
|
519
524
|
if (current_token(tokens, i) && current_token(tokens, i).type === TOKEN_TYPES.COMMA) {
|
|
520
525
|
parserError(errorMessage(tokens, i, ",", "", "Found extra"));
|
|
521
526
|
}
|
|
522
|
-
if (
|
|
523
|
-
current_token(tokens, i)
|
|
524
|
-
current_token(tokens, i)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
+
if (
|
|
528
|
+
!current_token(tokens, i) ||
|
|
529
|
+
(current_token(tokens, i) &&
|
|
530
|
+
current_token(tokens, i).type !== TOKEN_TYPES.VALUE &&
|
|
531
|
+
current_token(tokens, i).type !== TOKEN_TYPES.ESCAPE)
|
|
527
532
|
) {
|
|
528
533
|
parserError(errorMessage(tokens, i, inline_value, ","));
|
|
529
534
|
}
|
|
@@ -649,6 +654,10 @@ function parseAtBlock(tokens, i) {
|
|
|
649
654
|
k = key;
|
|
650
655
|
i = keyIndex;
|
|
651
656
|
i = parseColon(tokens, i, at_id);
|
|
657
|
+
if (current_token(tokens, i).type !== TOKEN_TYPES.VALUE && current_token(tokens, i).type !== TOKEN_TYPES.ESCAPE) {
|
|
658
|
+
parserError(errorMessage(tokens, i, at_value, ":"));
|
|
659
|
+
}
|
|
660
|
+
validateName(k);
|
|
652
661
|
continue;
|
|
653
662
|
} else if (current_token(tokens, i) && current_token(tokens, i).type === TOKEN_TYPES.ESCAPE) {
|
|
654
663
|
let [escape_character, escapeIndex] = parseEscape(tokens, i);
|
package/core/transpiler.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BLOCK, TEXT, INLINE, ATBLOCK, COMMENT } from "./labels.js";
|
|
2
2
|
import escapeHTML from "../helpers/escapeHTML.js";
|
|
3
3
|
import { transpilerError } from "./errors.js";
|
|
4
|
-
import { textFormat, htmlFormat, markdownFormat, mdxFormat } from "./formats.js";
|
|
4
|
+
import { textFormat, htmlFormat, markdownFormat, mdxFormat, jsonFormat } from "./formats.js";
|
|
5
|
+
|
|
6
|
+
const expose_for_fmts = [jsonFormat];
|
|
5
7
|
|
|
6
8
|
// ========================================================================== //
|
|
7
9
|
// Extracting target identifier //
|
|
@@ -26,7 +28,7 @@ function matchedValue(outputs, targetId) {
|
|
|
26
28
|
return result;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
function validateRules(target, args, content) {
|
|
31
|
+
function validateRules(target, args, content, type = null) {
|
|
30
32
|
if (!target || !target.options || !target.options.rules) {
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
@@ -96,6 +98,15 @@ function validateRules(target, args, content) {
|
|
|
96
98
|
]);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
101
|
+
// Validate element type
|
|
102
|
+
if (id && rules.type && type) {
|
|
103
|
+
if (rules.type !== type) {
|
|
104
|
+
transpilerError([
|
|
105
|
+
"{line}<$red:Validation Error:$> ",
|
|
106
|
+
`<$yellow:Identifier$> <$blue:'${Array.isArray(id) ? id.join(" | ") : id}'$> <$yellow:is expected to be type$> <$green:'${rules.type}'$>{N}<$cyan:Received type: $> <$magenta:'${type}'$>{line}`
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
99
110
|
}
|
|
100
111
|
// ========================================================================== //
|
|
101
112
|
// +++++++++++++++++++++++++++++ //
|
|
@@ -104,14 +115,16 @@ async function generateOutput(ast, i, format, mapper_file) {
|
|
|
104
115
|
const node = Array.isArray(ast) ? ast[i] : ast;
|
|
105
116
|
let result = "";
|
|
106
117
|
let context = "";
|
|
107
|
-
let target = mapper_file ? matchedValue(mapper_file.outputs, node.id) :
|
|
118
|
+
let target = mapper_file ? matchedValue(mapper_file.outputs, node.id) : null;
|
|
119
|
+
const block_formats = [htmlFormat, mdxFormat, jsonFormat];
|
|
108
120
|
if (target) {
|
|
109
|
-
validateRules(target, node.args, "");
|
|
110
|
-
result +=
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for (
|
|
121
|
+
validateRules(target, node.args, "", node.type);
|
|
122
|
+
result += block_formats.includes(format)
|
|
123
|
+
? `${target.render({ args: node.args, content: "<%smark>", ast: expose_for_fmts.includes(format) ? ast[i] : null })}`
|
|
124
|
+
: target.render({ args: node.args, content: "" });
|
|
125
|
+
// Body nodes
|
|
126
|
+
for (let j = 0; j < node.body.length; j++) {
|
|
127
|
+
const body_node = node.body[j];
|
|
115
128
|
switch (body_node.type) {
|
|
116
129
|
// ========================================================================== //
|
|
117
130
|
// Text //
|
|
@@ -119,8 +132,7 @@ async function generateOutput(ast, i, format, mapper_file) {
|
|
|
119
132
|
case TEXT:
|
|
120
133
|
validateRules(target, body_node.args, body_node.text);
|
|
121
134
|
const shouldEscape = target && target.options && target.options.escape === false ? false : true;
|
|
122
|
-
context +=
|
|
123
|
-
(format === htmlFormat || format === mdxFormat) && shouldEscape ? escapeHTML(body_node.text) : body_node.text;
|
|
135
|
+
context += [htmlFormat, mdxFormat].includes(format) && shouldEscape ? escapeHTML(body_node.text) : body_node.text;
|
|
124
136
|
break;
|
|
125
137
|
// ========================================================================== //
|
|
126
138
|
// Inline //
|
|
@@ -128,13 +140,11 @@ async function generateOutput(ast, i, format, mapper_file) {
|
|
|
128
140
|
case INLINE:
|
|
129
141
|
target = matchedValue(mapper_file.outputs, body_node.id);
|
|
130
142
|
if (target) {
|
|
131
|
-
validateRules(target, body_node.args, body_node.value);
|
|
132
|
-
context +=
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
content: format === htmlFormat || format === mdxFormat ? escapeHTML(body_node.value) : body_node.value
|
|
137
|
-
});
|
|
143
|
+
validateRules(target, body_node.args, body_node.value, body_node.type);
|
|
144
|
+
context += target.render({
|
|
145
|
+
args: body_node.args.length > 0 ? body_node.args : [],
|
|
146
|
+
content: format === htmlFormat || format === mdxFormat ? escapeHTML(body_node.value) : body_node.value
|
|
147
|
+
});
|
|
138
148
|
}
|
|
139
149
|
break;
|
|
140
150
|
// ========================================================================== //
|
|
@@ -143,7 +153,7 @@ async function generateOutput(ast, i, format, mapper_file) {
|
|
|
143
153
|
case ATBLOCK:
|
|
144
154
|
target = matchedValue(mapper_file.outputs, body_node.id);
|
|
145
155
|
if (target) {
|
|
146
|
-
validateRules(target, body_node.args, body_node.content);
|
|
156
|
+
validateRules(target, body_node.args, body_node.content, body_node.type);
|
|
147
157
|
// Escape logic: fallback to options.escape, default true
|
|
148
158
|
const shouldEscape = target.options?.escape ?? true;
|
|
149
159
|
if (shouldEscape) {
|
|
@@ -171,7 +181,8 @@ async function generateOutput(ast, i, format, mapper_file) {
|
|
|
171
181
|
break;
|
|
172
182
|
}
|
|
173
183
|
}
|
|
174
|
-
|
|
184
|
+
|
|
185
|
+
if (format === htmlFormat || format === mdxFormat || format === jsonFormat) {
|
|
175
186
|
result = result.replace("<%smark>", context);
|
|
176
187
|
} else {
|
|
177
188
|
result += context;
|
|
@@ -245,6 +256,9 @@ async function transpiler({ ast, format, mapperFile, includeDocument = true }) {
|
|
|
245
256
|
const document = `<!DOCTYPE html>\n<html>\n${finalHeader}\n<body>\n${output}\n</body>\n</html>\n`;
|
|
246
257
|
return document;
|
|
247
258
|
}
|
|
259
|
+
if (format === jsonFormat) {
|
|
260
|
+
output = JSON.parse(JSON.stringify(output));
|
|
261
|
+
}
|
|
248
262
|
return output;
|
|
249
263
|
}
|
|
250
264
|
|
package/formatter/mark.js
CHANGED
|
@@ -18,7 +18,7 @@ class MarkdownBuilder {
|
|
|
18
18
|
} else if (level < min) {
|
|
19
19
|
level = min;
|
|
20
20
|
}
|
|
21
|
-
return
|
|
21
|
+
return `\n${"#".repeat(level)} ${text}\n`;
|
|
22
22
|
}
|
|
23
23
|
return text;
|
|
24
24
|
}
|
|
@@ -29,7 +29,7 @@ class MarkdownBuilder {
|
|
|
29
29
|
if (!text && !url) {
|
|
30
30
|
return "";
|
|
31
31
|
}
|
|
32
|
-
return ` ${type === "image" ? "!" : ""}[${text}](${url + (title ? " " : "")}${title}) `;
|
|
32
|
+
return ` ${type === "image" ? "!" : ""}[${text}](${url + (title ? " " : "")}${title ? JSON.stringify(title) : ""}) `;
|
|
33
33
|
}
|
|
34
34
|
// ========================================================================== //
|
|
35
35
|
// Bold //
|
|
@@ -91,10 +91,7 @@ class MarkdownBuilder {
|
|
|
91
91
|
// Horizontal rule //
|
|
92
92
|
// ========================================================================== //
|
|
93
93
|
horizontal(format = "*") {
|
|
94
|
-
|
|
95
|
-
return "\n***\n";
|
|
96
|
-
}
|
|
97
|
-
return format === "*" ? "\n***\n" : format === "_" ? "___" : format === "*" ? "***" : "";
|
|
94
|
+
return `\n${format.repeat(3)}\n`;
|
|
98
95
|
}
|
|
99
96
|
// ========================================================================== //
|
|
100
97
|
// Escape //
|
package/grammar.ebnf
CHANGED
|
@@ -12,7 +12,6 @@ EscapeChar = "\";
|
|
|
12
12
|
(* 1. Identifiers can be only letters and numbers. *)
|
|
13
13
|
(* 2. Semi-colon is only recognized in Atblock arguments. *)
|
|
14
14
|
(* 3. Colon is a separator in Block and Atblock arguments; must be escaped if part of value. *)
|
|
15
|
-
(* 4. Bodies and Values cannot be empty. *)
|
|
16
15
|
|
|
17
16
|
(* Comments *)
|
|
18
17
|
Comment = "#", { ? any character except "\n" ? }, "\n";
|
package/index.js
CHANGED
|
@@ -5,10 +5,11 @@ import Mapper from "./mappers/mapper.js";
|
|
|
5
5
|
import HTML from "./mappers/languages/html.js";
|
|
6
6
|
import MARKDOWN from "./mappers/languages/markdown.js";
|
|
7
7
|
import MDX from "./mappers/languages/mdx.js";
|
|
8
|
+
import Json from "./mappers/languages/json.js";
|
|
8
9
|
import TagBuilder from "./formatter/tag.js";
|
|
9
10
|
import MarkdownBuilder from "./formatter/mark.js";
|
|
10
11
|
import { runtimeError } from "./core/errors.js";
|
|
11
|
-
import FORMATS, { textFormat, htmlFormat, markdownFormat, mdxFormat } from "./core/formats.js";
|
|
12
|
+
import FORMATS, { textFormat, htmlFormat, markdownFormat, mdxFormat, jsonFormat } from "./core/formats.js";
|
|
12
13
|
import TOKEN_TYPES from "./core/tokenTypes.js";
|
|
13
14
|
import * as labels from "./core/labels.js";
|
|
14
15
|
class SomMark {
|
|
@@ -19,7 +20,7 @@ class SomMark {
|
|
|
19
20
|
|
|
20
21
|
this.Mapper = Mapper;
|
|
21
22
|
this.includeDocument = includeDocument;
|
|
22
|
-
const accepted_formats = [textFormat, htmlFormat, markdownFormat, mdxFormat];
|
|
23
|
+
const accepted_formats = [textFormat, htmlFormat, markdownFormat, mdxFormat, jsonFormat];
|
|
23
24
|
if (!this.format) {
|
|
24
25
|
runtimeError(["{line}<$red:Undefined Format$>: <$yellow:Format argument is not defined.$>{line}"]);
|
|
25
26
|
}
|
|
@@ -29,7 +30,7 @@ class SomMark {
|
|
|
29
30
|
`{N}<$yellow:Accepted formats are:$> [<$cyan: ${accepted_formats.join(", ")}$>]{line}`
|
|
30
31
|
]);
|
|
31
32
|
}
|
|
32
|
-
const mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX };
|
|
33
|
+
const mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX, [jsonFormat]: Json};
|
|
33
34
|
if (!this.mapperFile && this.format) {
|
|
34
35
|
this.mapperFile = mapperFiles[this.format];
|
|
35
36
|
}
|
|
@@ -95,7 +96,8 @@ async function transpile(options = {}) {
|
|
|
95
96
|
export {
|
|
96
97
|
HTML,
|
|
97
98
|
MARKDOWN,
|
|
98
|
-
|
|
99
|
+
MDX,
|
|
100
|
+
Json,
|
|
99
101
|
Mapper,
|
|
100
102
|
TagBuilder,
|
|
101
103
|
MarkdownBuilder,
|
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
import Mapper from "../mapper.js";
|
|
2
2
|
const HTML = new Mapper();
|
|
3
|
-
const { tag, code, list } = HTML;
|
|
3
|
+
const { tag, code, list, safeArg } = HTML;
|
|
4
|
+
|
|
5
|
+
HTML.register(
|
|
6
|
+
["Html", "html"],
|
|
7
|
+
({ args }) => {
|
|
8
|
+
HTML.pageProps.pageTitle = safeArg(args, undefined, "title", null, null, HTML.pageProps.pageTitle);
|
|
9
|
+
HTML.pageProps.charset = safeArg(args, undefined, "charset", null, null, HTML.pageProps.charset);
|
|
10
|
+
HTML.pageProps.tabIcon.src = safeArg(args, undefined, "iconSrc", null, null, HTML.pageProps.tabIcon.src);
|
|
11
|
+
HTML.pageProps.tabIcon.type = safeArg(args, undefined, "iconType", null, null, HTML.pageProps.tabIcon.type);
|
|
12
|
+
HTML.pageProps.httpEquiv["X-UA-Compatible"] = safeArg(
|
|
13
|
+
args,
|
|
14
|
+
undefined,
|
|
15
|
+
"httpEquiv",
|
|
16
|
+
null,
|
|
17
|
+
null,
|
|
18
|
+
HTML.pageProps.httpEquiv["X-UA-Compatible"]
|
|
19
|
+
);
|
|
20
|
+
HTML.pageProps.viewport = safeArg(args, undefined, "viewport", null, null, HTML.pageProps.viewport);
|
|
21
|
+
return "";
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
rules: {
|
|
25
|
+
type: "Block"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
4
29
|
|
|
5
30
|
// Block
|
|
6
|
-
HTML.register(
|
|
7
|
-
|
|
8
|
-
})
|
|
31
|
+
HTML.register(
|
|
32
|
+
["Block", "block"],
|
|
33
|
+
({ content }) => {
|
|
34
|
+
return content;
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
rules: {
|
|
38
|
+
type: "Block"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
);
|
|
9
42
|
// Section
|
|
10
|
-
HTML.register(
|
|
11
|
-
|
|
12
|
-
})
|
|
43
|
+
HTML.register(
|
|
44
|
+
["Section", "section"],
|
|
45
|
+
({ content }) => {
|
|
46
|
+
return tag("section").body(content);
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
rules: {
|
|
50
|
+
type: "Block"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
13
54
|
// Headings
|
|
14
55
|
["h1", "h2", "h3", "h4", "h5", "h6"].forEach(heading => {
|
|
15
56
|
HTML.register(heading, ({ content }) => {
|
|
@@ -17,44 +58,44 @@ HTML.register("Section", ({ content }) => {
|
|
|
17
58
|
});
|
|
18
59
|
});
|
|
19
60
|
// Bold
|
|
20
|
-
HTML.register(["bold", "b"], ({ content }) => {
|
|
61
|
+
HTML.register(["bold", "Bold", "b"], ({ content }) => {
|
|
21
62
|
return tag("strong").body(content);
|
|
22
63
|
});
|
|
23
64
|
// Italic
|
|
24
65
|
HTML.register(["italic", "i"], ({ content }) => {
|
|
25
66
|
return tag("i").body(content);
|
|
26
67
|
});
|
|
27
|
-
//
|
|
68
|
+
// Emphasis
|
|
28
69
|
HTML.register(["emphasis", "e"], ({ content }) => {
|
|
29
70
|
return tag("span").attributes({ style: "font-weight:bold; font-style: italic;" }).body(content);
|
|
30
71
|
});
|
|
31
72
|
// Colored Text
|
|
32
|
-
HTML.register("color", ({ args, content }) => {
|
|
73
|
+
HTML.register(["color", "Color"], ({ args, content }) => {
|
|
74
|
+
const color = safeArg(args, 0, undefined, null, null, "none");
|
|
33
75
|
return tag("span")
|
|
34
|
-
.attributes({ style: `color:${
|
|
76
|
+
.attributes({ style: `color:${color}` })
|
|
35
77
|
.body(content);
|
|
36
78
|
});
|
|
37
79
|
// Link
|
|
38
|
-
HTML.register("link", ({ args, content }) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
80
|
+
HTML.register(["link", "Link"], ({ args, content }) => {
|
|
81
|
+
const url = safeArg(args, 0, "url", null, null, "");
|
|
82
|
+
const title = safeArg(args, 1, "title", null, null, "");
|
|
83
|
+
return tag("a").attributes({ href: url.trim(), title: title.trim(), target: "_blank" }).body(content);
|
|
42
84
|
});
|
|
43
85
|
// Image
|
|
44
86
|
HTML.register(
|
|
45
87
|
["image", "Image"],
|
|
46
88
|
({ args }) => {
|
|
47
|
-
const src = args
|
|
48
|
-
const alt = args
|
|
49
|
-
const width = args
|
|
50
|
-
|
|
89
|
+
const src = safeArg(args, undefined, "src", null, null, "");
|
|
90
|
+
const alt = safeArg(args, undefined, "alt", null, null, "");
|
|
91
|
+
const width = safeArg(args, undefined, "width", null, null, "");
|
|
92
|
+
const height = safeArg(args, undefined, "height", null, null, "");
|
|
51
93
|
return tag("img").attributes({ src, alt, width, height }).selfClose();
|
|
52
94
|
},
|
|
53
95
|
{
|
|
54
96
|
rules: {
|
|
55
|
-
is_Self_closing: true,
|
|
56
97
|
args: {
|
|
57
|
-
|
|
98
|
+
required: ["src"]
|
|
58
99
|
}
|
|
59
100
|
}
|
|
60
101
|
}
|
|
@@ -65,7 +106,7 @@ HTML.register(
|
|
|
65
106
|
({ args, content }) => {
|
|
66
107
|
return code(args, content);
|
|
67
108
|
},
|
|
68
|
-
{ escape: false }
|
|
109
|
+
{ escape: false, rules: { type: "AtBlock" } }
|
|
69
110
|
);
|
|
70
111
|
// List
|
|
71
112
|
HTML.register(
|
|
@@ -81,7 +122,12 @@ HTML.register(
|
|
|
81
122
|
({ content, args }) => {
|
|
82
123
|
return HTML.htmlTable(content.split(/\n/), args);
|
|
83
124
|
},
|
|
84
|
-
{
|
|
125
|
+
{
|
|
126
|
+
escape: false,
|
|
127
|
+
rules: {
|
|
128
|
+
type: "AtBlock"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
85
131
|
);
|
|
86
132
|
// Horizontal Rule
|
|
87
133
|
HTML.register(
|
|
@@ -98,9 +144,8 @@ HTML.register(
|
|
|
98
144
|
// Todo
|
|
99
145
|
HTML.register("todo", ({ args, content }) => {
|
|
100
146
|
const checked = HTML.todo(content);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
147
|
+
const task = safeArg(args, 0, undefined, null, null, "");
|
|
148
|
+
return tag("div").body(tag("input").attributes({ type: "checkbox", disabled: true, checked }).selfClose() + task);
|
|
104
149
|
});
|
|
105
150
|
|
|
106
151
|
export default HTML;
|