sommark 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Adam Elmi Eid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+
2
+ <img width="2000" height="491" alt="SomMark Cover" src="https://raw.githubusercontent.com/Adam-Elmi/SomMark/master/assets/smark_bg.png" />
3
+
4
+
5
+
6
+ <p align="center">
7
+ SomMark is a lightweight, custom documentation markup language designed to be simple, readable, and easy to process.
8
+ </p>
9
+
10
+ <p align="center">
11
+ <span>Website (Coming Soon)</span>
12
+ ·
13
+ <span>Docs (Coming Soon)</span>
14
+ ·
15
+ <span>Community (Coming Soon)</span>
16
+ </p>
17
+
18
+
19
+ <p align="center">
20
+ <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" />
21
+ <img src="https://img.shields.io/badge/version-v1.0.0-blue?style=flat-square" />
22
+ <img src="https://img.shields.io/badge/type-markup%20language-purple?style=flat-square" />
23
+ <img src="https://img.shields.io/badge/html-supported-orange?style=flat-square" />
24
+ <img src="https://img.shields.io/badge/markdown-supported-lightyellow?style=flat-square" />
25
+ <img src="https://img.shields.io/badge/mdx-supported-lightblue?style=flat-square" />
26
+
27
+ </p>
28
+
29
+ ---
30
+
31
+ # SomMark v1
32
+
33
+ SomMark is a simple and extensible markup language designed for writing documentation and structured content. It is easy to read, easy to parse, and easy to convert into formats like HTML, Markdown, and MDX.
34
+
35
+ SomMark is built around **clear syntax**, **explicit structure**, and a **mapping-based output system**.
36
+
37
+ ---
38
+
39
+ ## Core Syntax
40
+
41
+ SomMark has **three main syntax types**.
42
+
43
+ ---
44
+
45
+ ## 1. Block
46
+
47
+ A **Block** is a container.
48
+ It holds arguments and child content.
49
+
50
+ ```ini
51
+ [Block = arg1, arg2, arg3]
52
+ This is the body.
53
+ These texts are considered as children.
54
+ [end]
55
+ ```
56
+
57
+ * `Block` is the block name
58
+ * Arguments are optional
59
+ * Everything inside is treated as block content
60
+
61
+ ---
62
+
63
+ ## 2. Inline Statement
64
+
65
+ An **Inline Statement** is used inside text to apply formatting or behavior such as color, links, or styles.
66
+
67
+ ```ini
68
+ [Block]
69
+ This is the (text)->(color:red).
70
+ These words are (important)->(bold).
71
+ [end]
72
+ ```
73
+
74
+ Inline statements modify specific parts of text without breaking the flow.
75
+
76
+ ---
77
+
78
+ ## 3. At Block
79
+
80
+ Sometimes inline statements are not enough.
81
+ **At Blocks** are used for complex structures like tables, lists, code blocks, and custom content.
82
+
83
+ ```ini
84
+ [Block]
85
+ @_table_@: month, revenue, expenses
86
+ - January, 1200, 400
87
+ - February, 1400, 600
88
+ - March, 2000, 800
89
+ @_end_@
90
+
91
+ @_code_@: lua
92
+ function add(a, b)
93
+ return a + b
94
+ end
95
+ @_end_@
96
+ [end]
97
+ ```
98
+
99
+ At Blocks give you full control over how structured data is handled.
100
+
101
+ ---
102
+
103
+ ## Modes
104
+
105
+ SomMark has **two modes**:
106
+
107
+ ### Default Mode
108
+
109
+ * Comes with predefined identifiers such as `table`, `code`, `list`, and more
110
+ * Can be directly transpiled to HTML or Markdown
111
+ * Ideal for documentation
112
+
113
+ ### Custom Mode
114
+
115
+ * You define your own identifiers
116
+ * Full control over behavior and output
117
+ * Useful for custom formats or tools
118
+
119
+ ---
120
+
121
+ ## Mapping Concept
122
+
123
+ SomMark uses a **mapping system**.
124
+
125
+ * You define how each block, inline statement, or at-block should be converted
126
+ * Output is not fixed
127
+ * The same SomMark file can generate different results (HTML, MD, MDX, etc.)
128
+
129
+ This makes SomMark highly extensible and future-proof.
130
+
131
+ ---
132
+
133
+ ## Escape Character
134
+
135
+ To prevent SomMark from parsing syntax, use the escape character (`` ` ``):
136
+
137
+ ```ini
138
+ [Block]
139
+ This is a text `[Hello]` not a block.
140
+ Also this `(world)` is not inline syntax.
141
+ [end]
142
+ ```
143
+
144
+ Escaped content is treated as plain text.
145
+
146
+ ---
147
+
148
+ ## Purpose
149
+
150
+ SomMark is designed for:
151
+
152
+ * Documentation
153
+ * Structured writing
154
+ * Tooling and transpilation
155
+ * Extensible content systems
package/cli/cli.mjs ADDED
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ import projectJson from "../package.json" with { type: "json" };
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import { cliError, formatMessage } from "../core/validator.js";
7
+ import lexer from "../core/lexer.js";
8
+ import parser from "../core/parser.js";
9
+ import transpiler from "../core/transpiler.js";
10
+ import html from "../mappers/default_mode/smark.html.js";
11
+ import md from "../mappers/default_mode/smark.md.js";
12
+ import mdx from "../mappers/default_mode/smark.mdx.js";
13
+
14
+ const options = ["-v", "--version", "-h", "--help", "--html", "--md", "--mdx"];
15
+
16
+ function getHelp(unknown_option = true) {
17
+ const msg = [
18
+ `${unknown_option && process.argv[2] ? `<$red:Unrecognized option$> <$blue: '${process.argv[2]}'$>` : "<$cyan:[Help]$>"}`,
19
+ "{N}<$yellow:Usage:$> <$blue:smark [options] [targetFile] [option] [outputFile] [outputDir]$>",
20
+ "{N}<$yellow:Available options are:$>",
21
+ "{N} <$green:-h or --help$> <$cyan: show help message$>",
22
+ "{N} <$green:-v or --version$> <$cyan: show version information$>",
23
+ "{N} <$green:--html$> <$cyan: transpile to html$>",
24
+ "{N} <$green:--md$> <$cyan: transpile to markdown$>",
25
+ "{N} <$green:--mdx> <$cyan: transpile to mdx>"
26
+ ].join("");
27
+ const help_msg = formatMessage(msg);
28
+ if (!options.includes(process.argv[2]) && unknown_option) {
29
+ console.log(help_msg);
30
+ process.exit(0);
31
+ } else if (process.argv[2] === "-h" || process.argv[2] === "--help") {
32
+ console.log(help_msg);
33
+ process.exit(0);
34
+ }
35
+ }
36
+
37
+ if (process.argv[2] && (process.argv[2] === "-h" || process.argv[2] === "--help")) {
38
+ getHelp(false);
39
+ } else {
40
+ getHelp();
41
+ }
42
+
43
+ if (process.argv.length <= 2) {
44
+ console.log(
45
+ [
46
+ projectJson.version && typeof parseFloat(projectJson.version) === "number" ? projectJson.version : "",
47
+ "SomMark is a structural markup language for writing structured documents.",
48
+ "Copyright (C) Adam Elmi",
49
+ "Github: https://github.com/Adam-Elmi/SomMark"
50
+ ]
51
+ .filter(value => value !== "")
52
+ .join("\n")
53
+ );
54
+ }
55
+
56
+ if (projectJson && projectJson.version !== undefined && (process.argv[2] === "-v" || process.argv[2] === "--version")) {
57
+ console.log(projectJson.version);
58
+ }
59
+
60
+ const isExist = async path => {
61
+ try {
62
+ if (path) {
63
+ await fs.access(path);
64
+ return true;
65
+ } else {
66
+ throw new Error("Path is not found");
67
+ }
68
+ } catch (_) {
69
+ return false;
70
+ }
71
+ };
72
+
73
+ async function createFile(folder, file, content) {
74
+ if (!(await isExist(folder))) {
75
+ await fs.mkdir(folder, { recursive: true });
76
+ }
77
+ await fs.writeFile(path.join(folder, file), content);
78
+ }
79
+
80
+ async function readContent(path) {
81
+ const content = await fs.readFile(path);
82
+ return content;
83
+ }
84
+
85
+ const CONFIG_FILE_NAME = "smark.config.js";
86
+ const currentDir = process.cwd();
87
+ const configPath = path.join(currentDir, CONFIG_FILE_NAME);
88
+
89
+ let config = {
90
+ outputFile: "output",
91
+ outputDir: "",
92
+ mode: "default",
93
+ mappingFile: ""
94
+ };
95
+
96
+ async function loadConfig() {
97
+ if (isExist(configPath)) {
98
+ try {
99
+ const configURL = pathToFileURL(configPath).href;
100
+ const loadedModule = await import(configURL);
101
+ config = loadedModule.default;
102
+ } catch (error) {
103
+ console.error(`Error loading configuration file ${CONFIG_FILE_NAME}:`, error.message);
104
+ }
105
+ } else {
106
+ console.log(`${CONFIG_FILE_NAME} not found. Using default configuration.`);
107
+ }
108
+
109
+ if (!config.outputDir) {
110
+ config.outputDir = process.cwd();
111
+ }
112
+ return config;
113
+ }
114
+
115
+ async function transpile({ src, format, mappingFile = "" }) {
116
+ if ((await loadConfig()).mode === "default") {
117
+ return transpiler({ ast: parser(lexer(src)), format, mapperFile: format === "html" ? html : format === "md" ? md : mdx });
118
+ } else if (mappingFile && isExist(mappingFile)) {
119
+ return transpiler({ ast: parser(lexer(src)), format, mappingFile });
120
+ } else {
121
+ cliError([`{line}<$red:File$> <$blue:'${mappingFile}'$> <$red: is not found$>{line}`]);
122
+ }
123
+ }
124
+
125
+ async function generateOutput(outputDir, outputFile, format) {
126
+ let source_code = await readContent(process.argv[3]);
127
+ source_code = source_code.toString();
128
+ const output = await transpile({ src: source_code, format, mappingFile: config.mappingFile });
129
+ await createFile(outputDir, `${outputFile}.${format}`, output);
130
+ }
131
+ async function generateFile() {
132
+ try {
133
+ const format_option = process.argv[2] ?? "";
134
+ const format = format_option.replaceAll("-", "") ?? "";
135
+ if (format && ["html", "md", "mdx"].includes(format)) {
136
+ if (Array.isArray(process.argv) && process.argv.length > 0) {
137
+ const targetFile = process.argv[3] ? path.parse(process.argv[3]) : "";
138
+ if (await isExist(process.argv[3])) {
139
+ const file = path.parse(process.argv[3]);
140
+ if (file.ext === ".smark") {
141
+ const config = await loadConfig();
142
+ const success_msg = (outputDir, outputFile) => {
143
+ return formatMessage(
144
+ [
145
+ `{line}[<$yellow: STATUS$> : <$green: SUCCESS$>]{line}<$blue: File$> <$yellow:'${outputFile}.${format}'$> <$blue: is successfully created`,
146
+ ` in directory$> <$yellow: '${outputDir}'$>{line}`
147
+ ].join("")
148
+ );
149
+ };
150
+ if (process.argv[4] === undefined) {
151
+ if (config.mode === "default") {
152
+ config.mappingFile = format === "html" ? html : format === "md" ? md : format === "mdx" ? mdx : null;
153
+ }
154
+ await generateOutput(config.outputDir, config.outputFile, format);
155
+ console.log(success_msg(config.outputDir, config.outputFile));
156
+ } else if (process.argv[4] === "-o") {
157
+ if (process.argv[5] !== undefined) {
158
+ config.outputFile = path.parse(process.argv[5]).name;
159
+ config.outputDir = process.argv[6] !== undefined ? process.argv[6] : config.outputDir;
160
+ generateOutput(config.outputDir, config.outputFile, format);
161
+ console.log(success_msg(config.outputDir, config.outputFile));
162
+ }
163
+ }
164
+ } else {
165
+ cliError([
166
+ `{line}<$red:Unrecognized file extension$> <$blue: '${file.ext}'$> , <$red: only files with file extension$> <$green:'.smark'$> <$red: are accepted.$>{line}`
167
+ ]);
168
+ }
169
+ } else {
170
+ cliError([
171
+ `{line}<$magenta:File$> <$blue:'${process.argv[3] ? targetFile.name + targetFile.ext : "Unknown"}'$> <$magenta: is not found$>${(await isExist(targetFile.dir)) ? ` <$magenta: in directory$> <$yellow:${targetFile.dir}$>` : "."}`,
172
+ `${process.argv[3] ? "" : "{N}<$magenta:<Unknown>$> -> <$yellow:means you did not define the file path.$>"}{line}`
173
+ ]);
174
+ }
175
+ }
176
+ }
177
+ } catch (err) {
178
+ console.error(err);
179
+ }
180
+ }
181
+ generateFile();
package/core/ids.js ADDED
@@ -0,0 +1,2 @@
1
+ const PREDEFINED_IDS = ["link", "image", "color"];
2
+ export default PREDEFINED_IDS;
package/core/lexer.js ADDED
@@ -0,0 +1,293 @@
1
+ import TOKEN_TYPES from "./tokenTypes.js";
2
+ import peek from "../helpers/peek.js";
3
+ import { block_value, block_id, inline_id, inline_value, at_id, at_value, end_keyword } from "./names.js";
4
+ import { lexerError } from "./validator.js";
5
+
6
+ function concat(input, index, stop_at_char = [], scope_state, include_then_break = false, escapeChar = "") {
7
+ let str = "";
8
+ for (let char_index = index; char_index < input.length; char_index++) {
9
+ let char = input[char_index];
10
+ if (stop_at_char === null) {
11
+ if (char === "\n") {
12
+ break;
13
+ } else if (char === "[" && !scope_state) {
14
+ break;
15
+ } else if (char === "=" && !scope_state) {
16
+ break;
17
+ } else if (char === "]" && !scope_state) {
18
+ break;
19
+ } else if (char === "(" && !scope_state) {
20
+ break;
21
+ } else if (char === "-" && peek(input, char_index, 1) === ">" && !scope_state) {
22
+ break;
23
+ } else if (char === "@" && peek(input, char_index, 1) === "_" && !scope_state) {
24
+ break;
25
+ } else if (char === "_" && peek(input, char_index, 1) === "@" && !scope_state) {
26
+ break;
27
+ } else if (char === "#" && !scope_state) {
28
+ break;
29
+ } else if (char === "`" && !scope_state) {
30
+ break;
31
+ }
32
+ str += char;
33
+ } else {
34
+ if (char === escapeChar && peek(input, char_index, 1) === "`") {
35
+ str += char + peek(input, char_index, 1);
36
+ break;
37
+ } else if (char === escapeChar && peek(input, char_index, 1) !== "`") {
38
+ break;
39
+ } else if (char !== escapeChar && Array.isArray(stop_at_char) && stop_at_char.includes(char)) {
40
+ include_then_break ? (str += char) : null;
41
+ break;
42
+ }
43
+ str += char;
44
+ }
45
+ }
46
+
47
+ return str;
48
+ }
49
+
50
+ function lexer(src) {
51
+ if (src && typeof src === "string") {
52
+ const tokens = [];
53
+ let scope_state = false;
54
+ let line = 1;
55
+ let start;
56
+ let end;
57
+ let depth_stack = [];
58
+ let context = "",
59
+ temp_str = "",
60
+ previous_value = "";
61
+
62
+ function addToken(type, value) {
63
+ tokens.push({ type, value, line, start, end, depth: depth_stack.length });
64
+ }
65
+
66
+ for (let i = 0; i < src.length; i++) {
67
+ let current_char = src[i];
68
+ // Token: Open Bracket
69
+ if (current_char === "[" && !scope_state) {
70
+ if (i === 0) {
71
+ // Update Column
72
+ start = 1;
73
+ end = start;
74
+ } else {
75
+ // Update Column
76
+ start = end !== undefined ? end : 1;
77
+ end = start;
78
+ }
79
+ // Push to depth if next token is not end_keyword
80
+ temp_str = concat(src, i + 1, ["]"], scope_state);
81
+ if (temp_str && temp_str.length > 0) {
82
+ if (temp_str.trim() !== end_keyword) {
83
+ depth_stack.push("Block");
84
+ }
85
+ }
86
+ addToken(TOKEN_TYPES.OPEN_BRACKET, current_char);
87
+ previous_value = current_char;
88
+ }
89
+ // Token: Equal Sign
90
+ else if (current_char === "=" && !scope_state) {
91
+ // Update Column
92
+ start = end !== undefined ? end : 1;
93
+ end = start;
94
+ addToken(TOKEN_TYPES.EQUAL, current_char);
95
+ previous_value = current_char;
96
+ }
97
+ // Token: Close Bracket
98
+ else if (current_char === "]" && !scope_state) {
99
+ // Update Column
100
+ start = end !== undefined ? end : 1;
101
+ end = start;
102
+ addToken(TOKEN_TYPES.CLOSE_BRACKET, current_char);
103
+ if (previous_value === end_keyword) {
104
+ depth_stack.pop();
105
+ }
106
+ previous_value = current_char;
107
+ }
108
+ // Token: Open Parenthesis
109
+ else if (current_char === "(" && !scope_state) {
110
+ // Update Column
111
+ start = previous_value === "\n" ? end : end !== undefined ? end + 1 : 1;
112
+ end = start;
113
+ addToken(TOKEN_TYPES.OPEN_PAREN, current_char);
114
+ if (previous_value !== "->") {
115
+ previous_value = current_char;
116
+ }
117
+ }
118
+ // Token: Thin Arrow
119
+ else if (current_char === "-" && peek(src, i, 1) === ">") {
120
+ temp_str = current_char + peek(src, i, 1);
121
+ i += temp_str.length - 1;
122
+ // Update Column
123
+ start = end !== undefined ? end : 1;
124
+ end = start + temp_str.length;
125
+ addToken(TOKEN_TYPES.THIN_ARROW, temp_str);
126
+ previous_value = temp_str;
127
+ }
128
+ // Token: Close Parenthesis
129
+ else if (current_char === ")" && !scope_state) {
130
+ // Update Column
131
+ start = end !== undefined ? end : 1;
132
+ end = start;
133
+ addToken(TOKEN_TYPES.CLOSE_PAREN, current_char);
134
+ previous_value = current_char;
135
+ }
136
+ // Token: Open At (@_)
137
+ else if (current_char === "@" && peek(src, i, 1) === "_") {
138
+ temp_str = current_char + peek(src, i, 1);
139
+ i += temp_str.length - 1;
140
+ // Update Column
141
+ start = end !== undefined ? end : 1;
142
+ end = start + temp_str.length;
143
+ scope_state = true;
144
+ addToken(TOKEN_TYPES.OPEN_AT, temp_str);
145
+ previous_value = temp_str;
146
+ }
147
+ // Token: Close At (_@)
148
+ else if (current_char === "_" && peek(src, i, 1) === "@") {
149
+ temp_str = current_char + peek(src, i, 1);
150
+ i += temp_str.length - 1;
151
+ // Update Column
152
+ start = end !== undefined ? end + 1 : 1;
153
+ end = start + temp_str.length;
154
+ addToken(TOKEN_TYPES.CLOSE_AT, temp_str);
155
+ previous_value = temp_str;
156
+ }
157
+ // Token: Colon
158
+ else if (current_char === ":" && previous_value === "_@") {
159
+ // Update Column
160
+ start = end !== undefined ? end : 1;
161
+ end = start;
162
+ addToken(TOKEN_TYPES.COLON, current_char);
163
+ previous_value = current_char;
164
+ }
165
+ // Token: Newline
166
+ else if (current_char === "\n") {
167
+ line++;
168
+ start = 0;
169
+ end = 0;
170
+ previous_value = current_char;
171
+ addToken(TOKEN_TYPES.NEWLINE, current_char);
172
+ }
173
+ // Escape character
174
+ else if (current_char === "`" && !scope_state) {
175
+ temp_str = current_char + concat(src, i + 1, ["`"], scope_state, true);
176
+ if (temp_str && temp_str.length > 0) {
177
+ i += temp_str.length - 1;
178
+ if (previous_value === "(") {
179
+ addToken(TOKEN_TYPES.VALUE, temp_str);
180
+ } else {
181
+ addToken(TOKEN_TYPES.TEXT, temp_str);
182
+ }
183
+ }
184
+ }
185
+ // Token: Block Identifier OR Token: Block Value OR Token: End Keyword
186
+ else {
187
+ if (previous_value === "[" || (previous_value === "=" && !scope_state)) {
188
+ temp_str = concat(src, i, ["=", "]", "\n"], scope_state);
189
+ i += temp_str.length - 1;
190
+ // Update Column
191
+ start = end !== undefined ? end : 1;
192
+ end = start + temp_str.length;
193
+ if (temp_str.trim()) {
194
+ if (previous_value === "[") {
195
+ // Token: End Keyword
196
+ if (temp_str.trim() === end_keyword) {
197
+ addToken(TOKEN_TYPES.END_KEYWORD, temp_str);
198
+ previous_value = temp_str.trim();
199
+ scope_state = false;
200
+ }
201
+ // Token: Block Identifier
202
+ else {
203
+ addToken(TOKEN_TYPES.IDENTIFIER, temp_str);
204
+ previous_value = block_id;
205
+ }
206
+ }
207
+ // Token: Block Value
208
+ else if (previous_value === "=") {
209
+ addToken(TOKEN_TYPES.VALUE, temp_str);
210
+ previous_value = block_value;
211
+ }
212
+ }
213
+ }
214
+ // Token: Inline Value OR Token: Inline Identifier
215
+ else if (previous_value === "(" || (previous_value === "->" && !scope_state)) {
216
+ temp_str = concat(src, i, [")", "["], scope_state, true, ")");
217
+ i += temp_str.length - 1;
218
+ // Update Column
219
+ start = end !== undefined ? end : 1;
220
+ end = start + temp_str.length;
221
+ if (temp_str.trim()) {
222
+ if (previous_value === "(") {
223
+ // Token: Inline Value
224
+ addToken(TOKEN_TYPES.VALUE, temp_str);
225
+ previous_value = inline_value;
226
+ } else if (previous_value === "->") {
227
+ // Token: Inline Identifier
228
+ addToken(TOKEN_TYPES.IDENTIFIER, temp_str);
229
+ previous_value = inline_id;
230
+ }
231
+ }
232
+ }
233
+ // Token: At Identifier OR Token: At Value OR Token: End Keyword
234
+ else if (previous_value === "@_" || previous_value === ":") {
235
+ temp_str = concat(src, i, ["_", "\n"], scope_state);
236
+ i += temp_str.length - 1;
237
+ if (temp_str.trim()) {
238
+ // Update Column
239
+ start = end !== undefined ? end + 1 : 1;
240
+ end = start + temp_str.length;
241
+ if (previous_value === "@_") {
242
+ // Token: End Keyword
243
+ if (temp_str.trim() === end_keyword) {
244
+ addToken(TOKEN_TYPES.END_KEYWORD, temp_str);
245
+ previous_value = temp_str.trim();
246
+ scope_state = false;
247
+ }
248
+ // Token: At Identifier
249
+ else {
250
+ addToken(TOKEN_TYPES.IDENTIFIER, temp_str);
251
+ previous_value = at_id;
252
+ }
253
+ }
254
+ // Token: At Value
255
+ else if (previous_value === ":") {
256
+ addToken(TOKEN_TYPES.VALUE, temp_str);
257
+ previous_value = at_value;
258
+ }
259
+ }
260
+ }
261
+ // Token: Comment
262
+ else if (current_char === "#") {
263
+ temp_str = concat(src, i, ["\n"], scope_state);
264
+ // Update Column
265
+ start = previous_value === "\n" ? end : end !== undefined ? end + 1 : 1;
266
+ end = start + temp_str.length;
267
+ if (temp_str.trim()) {
268
+ i += temp_str.length - 1;
269
+ addToken(TOKEN_TYPES.COMMENT, temp_str);
270
+ }
271
+ }
272
+ // Token: Text
273
+ else {
274
+ context = concat(src, i, null, scope_state);
275
+ i += context.length - 1;
276
+ // Update Column
277
+ start = previous_value === "\n" ? end : end !== undefined ? end + 1 : 1;
278
+ end = start + context.length;
279
+ if (context.trim()) {
280
+ addToken(TOKEN_TYPES.TEXT, context);
281
+ }
282
+ }
283
+ }
284
+ context = "";
285
+ temp_str = "";
286
+ }
287
+ return tokens;
288
+ } else {
289
+ lexerError(["{line}<$red:Invalid Source Code:$> <$yellow:Source code is not a string or is empty.$>{line}"]);
290
+ }
291
+ }
292
+
293
+ export default lexer;
package/core/names.js ADDED
@@ -0,0 +1,13 @@
1
+ export const BLOCK = "Block",
2
+ TEXT = "Text",
3
+ INLINE = "Inline",
4
+ ATBLOCK = "AtBlock",
5
+ NEWLINE = "Newline",
6
+ COMMENT = "Comment",
7
+ block_id = "Block Identifier",
8
+ block_value = "Block Value",
9
+ inline_id = "Inline Identifier",
10
+ inline_value = "Inline Value",
11
+ at_id = "At Identifier",
12
+ at_value = "At Value",
13
+ end_keyword = "end";