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.
Files changed (62) hide show
  1. package/README.md +98 -82
  2. package/assets/logo.json +28 -0
  3. package/assets/smark.logo.png +0 -0
  4. package/assets/smark.logo.svg +21 -0
  5. package/cli/cli.mjs +7 -17
  6. package/cli/commands/build.js +26 -6
  7. package/cli/commands/color.js +22 -26
  8. package/cli/commands/help.js +10 -10
  9. package/cli/commands/init.js +20 -31
  10. package/cli/commands/print.js +18 -16
  11. package/cli/commands/show.js +4 -0
  12. package/cli/commands/version.js +6 -0
  13. package/cli/constants.js +9 -5
  14. package/cli/helpers/config.js +11 -0
  15. package/cli/helpers/file.js +17 -6
  16. package/cli/helpers/transpile.js +15 -17
  17. package/core/errors.js +49 -25
  18. package/core/formats.js +7 -3
  19. package/core/formatter.js +215 -0
  20. package/core/helpers/config-loader.js +40 -75
  21. package/core/labels.js +21 -9
  22. package/core/lexer.js +491 -212
  23. package/core/modules.js +164 -0
  24. package/core/parser.js +516 -389
  25. package/core/tokenTypes.js +36 -1
  26. package/core/transpiler.js +238 -154
  27. package/core/validator.js +79 -0
  28. package/formatter/mark.js +203 -43
  29. package/formatter/tag.js +202 -32
  30. package/grammar.ebnf +57 -50
  31. package/helpers/colorize.js +26 -13
  32. package/helpers/dedent.js +19 -0
  33. package/helpers/escapeHTML.js +13 -6
  34. package/helpers/kebabize.js +6 -0
  35. package/helpers/peek.js +9 -0
  36. package/helpers/removeChar.js +26 -13
  37. package/helpers/safeDataParser.js +114 -0
  38. package/helpers/utils.js +140 -158
  39. package/index.js +186 -188
  40. package/mappers/languages/html.js +105 -213
  41. package/mappers/languages/json.js +122 -171
  42. package/mappers/languages/markdown.js +355 -108
  43. package/mappers/languages/mdx.js +76 -120
  44. package/mappers/languages/xml.js +114 -0
  45. package/mappers/mapper.js +152 -123
  46. package/mappers/shared/index.js +22 -0
  47. package/package.json +26 -6
  48. package/SOMMARK-SPEC.md +0 -481
  49. package/cli/commands/list.js +0 -124
  50. package/constants/html_tags.js +0 -146
  51. package/core/pluginManager.js +0 -149
  52. package/core/plugins/comment-remover.js +0 -47
  53. package/core/plugins/module-system.js +0 -176
  54. package/core/plugins/raw-content-plugin.js +0 -78
  55. package/core/plugins/rules-validation-plugin.js +0 -231
  56. package/core/plugins/sommark-format.js +0 -244
  57. package/coverage_test.js +0 -21
  58. package/debug.js +0 -15
  59. package/helpers/camelize.js +0 -2
  60. package/helpers/defaultTheme.js +0 -3
  61. package/test_format_fix.js +0 -42
  62. package/v3-todo.smark +0 -73
package/index.js CHANGED
@@ -6,97 +6,58 @@ 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
8
  import Json from "./mappers/languages/json.js";
9
- import TagBuilder from "./formatter/tag.js";
10
- import MarkdownBuilder from "./formatter/mark.js";
9
+ import XML from "./mappers/languages/xml.js";
11
10
  import { runtimeError } from "./core/errors.js";
12
- import FORMATS, { textFormat, htmlFormat, markdownFormat, mdxFormat, jsonFormat } from "./core/formats.js";
11
+ import FORMATS, { textFormat, htmlFormat, markdownFormat, mdxFormat, jsonFormat, xmlFormat } from "./core/formats.js";
13
12
  import TOKEN_TYPES from "./core/tokenTypes.js";
14
13
  import * as labels from "./core/labels.js";
15
- import PluginManager from "./core/pluginManager.js";
16
- import ModuleSystem from "./core/plugins/module-system.js";
17
- import RawContentPlugin from "./core/plugins/raw-content-plugin.js";
18
- import CommentRemover from "./core/plugins/comment-remover.js";
19
- import RulesValidationPlugin from "./core/plugins/rules-validation-plugin.js";
20
- import SomMarkFormat from "./core/plugins/sommark-format.js";
14
+ import { resolveModules } from "./core/modules.js";
15
+ import { formatAST } from "./core/formatter.js";
16
+ import { validateAST } from "./core/validator.js";
21
17
  import { enableColor } from "./helpers/colorize.js";
22
- import { htmlTable, list, parseList, safeArg, todo } from "./helpers/utils.js";
18
+ import { safeArg } from "./helpers/utils.js";
23
19
 
24
20
 
25
- export const BUILT_IN_PLUGINS = [ModuleSystem, RawContentPlugin, CommentRemover, RulesValidationPlugin, SomMarkFormat];
26
-
21
+ /**
22
+ * The SomMark Core Engine.
23
+ * Processes SomMark code and turns it into different formats.
24
+ */
27
25
  class SomMark {
28
- constructor({ src, format, mapperFile = null, includeDocument = true, plugins = [], excludePlugins = [], priority = [], filename = "anonymous" }) {
26
+ static Mapper = Mapper;
27
+ /**
28
+ * Creates a new SomMark engine.
29
+ *
30
+ * @param {Object} options - Settings for the engine.
31
+ * @param {string} options.src - The SomMark code to process.
32
+ * @param {string} options.format - The final format you want (like 'html' or 'markdown').
33
+ * @param {Mapper|null} [options.mapperFile=null] - Custom rules for formatting.
34
+ * @param {string} [options.filename="anonymous"] - The name of the file, used for errors and settings.
35
+ * @param {boolean} [options.removeComments=true] - If true, comments will be removed from the final code.
36
+ * @param {Object} [options.placeholders={}] - Values to use for {placeholders}.
37
+ * @param {Array<string>} [options.customProps=[]] - Allowed custom HTML attributes.
38
+ * @param {Array<string>} [options.importStack=[]] - Tracking for circular dependencies.
39
+ */
40
+ constructor({ src, format, mapperFile = null, filename = "anonymous", removeComments = true, placeholders = {}, customProps = [], importStack = [] }) {
29
41
  this.src = src;
30
- this.format = format;
42
+ this.targetFormat = format;
31
43
  this.mapperFile = mapperFile;
32
- this.priority = priority;
33
44
  this.filename = filename;
45
+ this.removeComments = removeComments;
46
+ this.placeholders = placeholders;
47
+ this.customProps = customProps;
48
+ this.importStack = importStack;
34
49
  this.warnings = [];
35
50
  this._prepared = false;
36
51
 
37
- // 1. Identify which built-in plugins should be active by default
38
- const inactiveByDefault = ["raw-content", "sommark-format"];
39
- let activeBuiltIns = BUILT_IN_PLUGINS.filter(p =>
40
- !inactiveByDefault.includes(p.name) && !excludePlugins.includes(p.name)
41
- );
42
-
43
- // 2. Process 'plugins' array:
44
- // - If string, look up in BUILT_IN_PLUGINS
45
- // - If object with { name, options }, it's a built-in override
46
- // - If object with { plugin, options }, it's an external override
47
- // - If object without name/plugin but with other keys, it's a direct plugin object
48
- let processedPlugins = [];
49
- let manuallyActivatedNames = [];
50
-
51
- plugins.forEach(p => {
52
- if (typeof p === "string") {
53
- const builtIn = BUILT_IN_PLUGINS.find(bp => bp.name === p);
54
- if (builtIn) {
55
- processedPlugins.push({ ...builtIn }); // Clone to avoid mutation
56
- manuallyActivatedNames.push(p);
57
- }
58
- } else if (typeof p === "object" && p !== null) {
59
- if (p.name && p.options && !p.type) {
60
- // Built-in Override: { name: "raw-content", options: { ... } }
61
- const builtIn = BUILT_IN_PLUGINS.find(bp => bp.name === p.name);
62
- if (builtIn) {
63
- processedPlugins.push({
64
- ...builtIn,
65
- options: { ...builtIn.options, ...p.options }
66
- });
67
- manuallyActivatedNames.push(p.name);
68
- }
69
- } else if (p.plugin && p.options) {
70
- // External Override: { plugin: myPlugin, options: { ... } }
71
- processedPlugins.push({
72
- ...p.plugin,
73
- options: { ...p.plugin.options, ...p.options }
74
- });
75
- } else {
76
- // Direct Plugin Object
77
- processedPlugins.push(p);
78
- }
79
- }
80
- });
81
-
82
- // 3. Merge: Default active built-ins (minus ones manually re-added) + Processed Plugins
83
- const finalPlugins = [
84
- ...activeBuiltIns
85
- .filter(p => !manuallyActivatedNames.includes(p.name))
86
- .map(p => ({ ...p })), // Clone defaults for isolation
87
- ...processedPlugins
88
- ];
89
-
90
- this.plugins = finalPlugins;
91
- this.pluginManager = new PluginManager(this.plugins, this.priority);
52
+ // Create a random token to safely wrap data
53
+ this.moduleIdentityToken = `$_SM_MOD_${Math.random().toString(36).slice(2, 7)}_$`;
92
54
 
93
55
  this.Mapper = Mapper;
94
- this.includeDocument = includeDocument;
95
56
 
96
- const mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX, [jsonFormat]: Json, [textFormat]: new Mapper() };
57
+ const mapperFiles = { [htmlFormat]: HTML, [markdownFormat]: MARKDOWN, [mdxFormat]: MDX, [jsonFormat]: Json, [xmlFormat]: XML, [textFormat]: new Mapper() };
97
58
 
98
- if (!this.mapperFile && this.format) {
99
- const DefaultMapper = mapperFiles[this.format];
59
+ if (!this.mapperFile && this.targetFormat) {
60
+ const DefaultMapper = mapperFiles[this.targetFormat];
100
61
  if (DefaultMapper) {
101
62
  this.mapperFile = DefaultMapper.clone();
102
63
  }
@@ -104,17 +65,48 @@ class SomMark {
104
65
  this.mapperFile = this.mapperFile.clone();
105
66
  }
106
67
 
68
+ if (this.mapperFile) {
69
+ this.mapperFile.options.removeComments = this.removeComments;
70
+ this.mapperFile.options.moduleIdentityToken = this.moduleIdentityToken;
71
+ this.mapperFile.options.filename = this.filename;
72
+
73
+ // Initialize custom props whitelist
74
+ if (this.customProps && this.customProps.length > 0) {
75
+ const props = Array.isArray(this.customProps) ? this.customProps : [this.customProps];
76
+ props.forEach(prop => this.mapperFile.customProps.add(prop));
77
+ }
78
+ }
79
+
107
80
  this._initializeMappers();
108
81
  }
109
82
 
83
+
84
+ /**
85
+ * Adds a new rule or changes an existing one.
86
+ *
87
+ * @param {string} id - The name of the tag.
88
+ * @param {Function} render - The function that formats the tag.
89
+ * @param {Object} [options] - Extra settings for the tag.
90
+ */
110
91
  register = (id, render, options) => {
111
92
  this.mapperFile.register(id, render, options);
112
93
  };
113
94
 
95
+ /**
96
+ * Copies rules from other mappers.
97
+ *
98
+ * @param {...Mapper} mappers - The mappers to copy from.
99
+ */
114
100
  inherit = (...mappers) => {
115
101
  this.mapperFile.inherit(...mappers);
116
102
  };
117
103
 
104
+ /**
105
+ * Gets a rule by its name.
106
+ *
107
+ * @param {string} id - The tag name.
108
+ * @returns {Object|null}
109
+ */
118
110
  get = id => {
119
111
  return this.mapperFile.get(id);
120
112
  };
@@ -128,18 +120,12 @@ class SomMark {
128
120
  };
129
121
 
130
122
  _initializeMappers() {
131
- // 1. Check if a plugin provides a mapper for this format
132
- const pluginMapper = this.pluginManager.getFormatMapper(this.format);
133
- if (pluginMapper) {
134
- this.mapperFile = pluginMapper.clone();
135
- }
136
-
137
- if (!this.format) {
123
+ if (!this.targetFormat) {
138
124
  runtimeError(["{line}<$red:Undefined Format$>: <$yellow:Format argument is not defined.$>{line}"]);
139
125
  }
140
126
 
141
- if (!this.mapperFile && this.format) {
142
- runtimeError([`{line}<$red:Unknown Format$>: <$yellow:Mapper for format '${this.format}' not found.$>{line}`]);
127
+ if (!this.mapperFile && this.targetFormat) {
128
+ runtimeError([`{line}<$red:Unknown Format$>: <$yellow:Mapper for format '${this.targetFormat}' not found.$>{line}`]);
143
129
  }
144
130
  }
145
131
 
@@ -147,149 +133,149 @@ class SomMark {
147
133
  this.warnings.push(message);
148
134
  }
149
135
 
150
- async _applyScopedPreprocessors(src) {
151
- let processed = await this.pluginManager.runPreprocessor(src, "top-level", this);
152
-
153
- // Helper for async regex replacement
154
- const asyncReplace = async (str, regex, scope) => {
155
- if (typeof str !== "string") return str;
156
- const matches = [...str.matchAll(regex)];
157
- if (matches.length === 0) return str;
158
-
159
- // Process all matches in parallel for efficiency
160
- const replacements = await Promise.all(
161
- matches.map(async match => {
162
- // match[2] is the group for content inside quotes/brackets/whatever depending on the regex
163
- let contentToProcess;
164
- if (scope === "arguments") contentToProcess = match[2];
165
- if (scope === "content") contentToProcess = match[2];
166
-
167
- if (contentToProcess !== undefined) {
168
- const processedContent = await this.pluginManager.runPreprocessor(contentToProcess, scope, this);
169
- // Reconstruct the match with processed content
170
- if (scope === "arguments") return match[0].replace(match[2], processedContent);
171
- if (scope === "content") return match[0].replace(match[2], processedContent);
172
- }
173
- return match[0];
174
- })
175
- );
176
-
177
- // Reconstruct string by replacing matches in order
178
- let i = 0;
179
- return str.replace(regex, () => replacements[i++]);
180
- };
181
-
182
- // 1. Process Arguments Scope [...]
183
- const argRegex = /\[\s*([a-zA-Z0-9\-_$]+)\s*(?:=\s*((?:[^"\\\]]|\\[\s\S]|"[^"]*")*))?\s*\]/g;
184
- processed = await asyncReplace(processed, argRegex, "arguments");
185
-
186
- // 2. Process Content Scope
187
- const contentRegex = /(\]\s*)([\s\S]*?)(\s*\[\s*end\s*\])/g;
188
- processed = await asyncReplace(processed, contentRegex, "content");
189
-
190
- return processed;
191
- }
192
-
136
+
193
137
  _ensurePrepared() {
194
138
  if (this._prepared) return;
195
139
 
196
- // 1. Resolve Dynamic Formats from Plugins if built-in failed
197
- if (!this.mapperFile) {
198
- const PluginMapper = this.pluginManager.getFormatMapper(this.format);
199
- if (PluginMapper) {
200
- this.mapperFile = PluginMapper.clone ? PluginMapper.clone() : PluginMapper;
201
- }
202
- }
203
-
204
140
  // Final check
205
141
  if (!this.mapperFile) {
206
142
  runtimeError([
207
- `{line}<$red:Unknown Format$>: <$yellow:No mapper found for format:$> <$green:'${this.format}'$>`,
208
- `{N}<$yellow:Make sure you have registered a plugin that provides this format.$>{line}`
143
+ `{line}<$red:Unknown Format$>: <$yellow:No mapper found for format:$> <$green:'${this.targetFormat}'$>`,
144
+ `{N}<$yellow:Make sure you have registered format mapper correctly.$>{line}`
209
145
  ]);
210
146
  }
211
147
 
212
- // Run active registration hooks from plugins
213
- this.pluginManager.runRegisterHooks(this);
214
-
215
- // 2. Extend Mapper with static plugins definitions
216
- const extensions = this.pluginManager.getMapperExtensions();
217
- if (extensions.outputs.length > 0) {
218
- for (const out of extensions.outputs) {
219
- // Support both object {id, render, options} and array [id, render, options]
220
- if (Array.isArray(out)) {
221
- const [id, render, options = {}] = out;
222
- this.register(id, render, options);
223
- } else if (typeof out === "object" && out !== null) {
224
- const renderFn = out.register || out.render;
225
- if (typeof renderFn === "function") {
226
- this.register(out.id, renderFn, out.options || {});
227
- }
228
- }
229
- }
230
- }
231
-
232
- // Add recognized arguments if provided by plugins
233
- if (extensions.rules && extensions.rules.recognizedArguments) {
234
- if (Array.isArray(extensions.rules.recognizedArguments)) {
235
- extensions.rules.recognizedArguments.forEach(arg => this.mapperFile.extraProps.add(arg));
236
- }
237
- }
238
-
239
148
  this._prepared = true;
240
149
  }
241
150
 
151
+ /**
152
+ * Breaks the code into small pieces called tokens.
153
+ *
154
+ * @param {string} [src=this.src] - The code to break apart.
155
+ * @returns {Promise<Array<Object>>} - The list of tokens.
156
+ */
242
157
  async lex(src = this.src) {
243
158
  this._ensurePrepared();
244
159
  if (src !== this.src) this.src = src;
245
- const processedSrc = await this._applyScopedPreprocessors(this.src);
246
- let tokens = lexer(processedSrc, this.filename);
247
- tokens = await this.pluginManager.runAfterLex(tokens);
160
+ let tokens = lexer(this.src, this.filename);
248
161
  return tokens;
249
162
  }
250
163
 
164
+ /**
165
+ * Organizes the code into a tree structure.
166
+ * Also handles modules and checks for errors.
167
+ *
168
+ * @param {string} [src=this.src] - Optional source override.
169
+ * @returns {Promise<Array<Object>>} - The final code tree.
170
+ */
251
171
  async parse(src = this.src) {
252
172
  const tokens = await this.lex(src);
253
- let ast = parser(tokens, this.filename);
254
- ast = await this.pluginManager.runOnAst(ast, {
255
- mapperFile: this.mapperFile,
173
+ let ast = parser(tokens, this.filename, this.placeholders);
174
+
175
+ ast = await resolveModules(ast, {
176
+ mapperFile: this.mapperFile,
256
177
  filename: this.filename,
257
- format: this.format,
258
- instance: this
178
+ format: this.targetFormat,
179
+ instance: this,
180
+ importStack: this.importStack
259
181
  });
182
+
183
+ if (this.mapperFile) {
184
+ validateAST(ast, this.mapperFile, this);
185
+ }
186
+
187
+ return ast;
188
+ }
189
+
190
+ parseSync(src = this.src) {
191
+ this._ensurePrepared();
192
+ if (src !== this.src) this.src = src;
193
+ const tokens = lexer(this.src, this.filename);
194
+ let ast = parser(tokens, this.filename, this.placeholders);
195
+
196
+ if (this.mapperFile) {
197
+ validateAST(ast, this.mapperFile, this);
198
+ }
199
+
260
200
  return ast;
261
201
  }
262
202
 
203
+ /**
204
+ * Turns the SomMark code into the final format.
205
+ *
206
+ * @param {string} [src=this.src] - Optional source override.
207
+ * @returns {Promise<string>} - The finished code.
208
+ */
263
209
  async transpile(src = this.src) {
264
210
  if (src !== this.src) this.src = src;
265
211
  this._ensurePrepared();
266
212
 
267
213
  const ast = await this.parse(src);
214
+ let result = await transpiler({ ast, format: this.targetFormat, mapperFile: this.mapperFile });
215
+
216
+ return result;
217
+ }
268
218
 
269
- let result = await transpiler({ ast, format: this.format, mapperFile: this.mapperFile, includeDocument: this.includeDocument });
270
219
 
271
- // 3. Run Transformers
272
- return await this.pluginManager.runTransformers(result);
220
+ async format(options = {}) {
221
+ const tokens = await this.lex();
222
+ const ast = parser(tokens, this.filename);
223
+ return formatAST(ast, options);
224
+ }
225
+
226
+ formatSync(options = {}) {
227
+ const tokens = lexer(this.src, this.filename);
228
+ const ast = parser(tokens, this.filename);
229
+ return formatAST(ast, options);
273
230
  }
274
231
  }
275
232
 
276
- const lex = async (src, filename = "anonymous", plugins = [], excludePlugins = []) => {
277
- return await new SomMark({ src, filename, plugins, format: htmlFormat, excludePlugins }).lex();
233
+ /**
234
+ * A quick way to break code into tokens.
235
+ * Uses HTML settings by default.
236
+ *
237
+ * @param {string} src - The raw SomMark source.
238
+ * @param {string} [filename="anonymous"] - Filename for error context.
239
+ * @returns {Promise<Array<Object>>} - The list of tokens.
240
+ */
241
+ const lex = async (src, filename = "anonymous") => {
242
+ return await new SomMark({ src, filename, format: htmlFormat }).lex();
278
243
  };
279
244
 
280
- async function parse(src, filename = "anonymous", plugins = [], excludePlugins = []) {
245
+ /**
246
+ * A quick way to organize code into a tree.
247
+ * Uses HTML settings by default.
248
+ *
249
+ * @param {string} src - The raw SomMark source.
250
+ * @param {string} [filename="anonymous"] - Filename for error context.
251
+ * @returns {Promise<Array<Object>>} - The final code tree.
252
+ */
253
+ async function parse(src, filename = "anonymous") {
281
254
  if (!src) {
282
255
  runtimeError([`{line}<$red:Missing Source:$> <$yellow:The 'src' argument is required for parsing.$>{line}`]);
283
256
  }
284
- return await new SomMark({ src, filename, plugins, format: htmlFormat, excludePlugins }).parse();
257
+ return await new SomMark({ src, filename, format: htmlFormat }).parse();
285
258
  }
286
259
 
260
+ /**
261
+ * The easiest way to process SomMark code.
262
+ *
263
+ * @param {Object} options - Transpilation options.
264
+ * @param {string} options.src - Raw source code.
265
+ * @param {string} [options.format="html"] - Target format.
266
+ * @param {string} [options.filename="anonymous"] - Filename for context.
267
+ * @param {Mapper|null} [options.mapperFile=null] - Custom rules for formatting.
268
+ * @param {boolean} [options.removeComments=true] - Strip comments.
269
+ * @param {Object} [options.placeholders={}] - Global placeholders.
270
+ * @param {Array<string>} [options.customProps=[]] - Custom attribute whitelist.
271
+ * @returns {Promise<string>} - Transpiled output.
272
+ */
287
273
  async function transpile(options = {}) {
288
- const { src, format = htmlFormat, filename = "anonymous", mapperFile = null, includeDocument = true, plugins = [], excludePlugins = [], priority = [] } = options;
274
+ const { src, format = htmlFormat, filename = "anonymous", mapperFile = null, removeComments = true, placeholders = {}, customProps = [] } = options;
289
275
  if (typeof options !== "object" || options === null) {
290
276
  runtimeError([`{line}<$red:Invalid Options:$> <$yellow:The options argument must be a non-null object.$>{line}`]);
291
277
  }
292
- const knownProps = ["src", "format", "filename", "mapperFile", "includeDocument", "plugins", "excludePlugins", "priority"];
278
+ const knownProps = ["src", "format", "filename", "mapperFile", "removeComments", "placeholders", "customProps"];
293
279
  Object.keys(options).forEach(key => {
294
280
  if (!knownProps.includes(key)) {
295
281
  runtimeError([
@@ -301,13 +287,29 @@ async function transpile(options = {}) {
301
287
  runtimeError([`{line}<$red:Missing Source:$> <$yellow:The 'src' argument is required for transpilation.$>{line}`]);
302
288
  }
303
289
 
304
- const sm = new SomMark({ src, format, filename, mapperFile, includeDocument, plugins, excludePlugins, priority });
290
+ const sm = new SomMark({ src, format, filename, mapperFile, removeComments, placeholders, customProps });
305
291
  return await sm.transpile();
306
292
  }
307
293
 
294
+ /**
295
+ * A quick, synchronous way to get tokens.
296
+ *
297
+ * @param {string} src - Raw source code.
298
+ * @returns {Array<Object>} - The list of tokens.
299
+ */
308
300
  const lexSync = src => lexer(src);
309
301
 
310
- const parseSync = src => parser(lexer(src));
302
+ /**
303
+ * A quick, synchronous way to get the code tree.
304
+ *
305
+ * @param {string} src - Raw source code.
306
+ * @param {Object} [options={}] - Parsing options.
307
+ * @returns {Array<Object>} - The code tree.
308
+ */
309
+ const parseSync = (src, options = {}) => {
310
+ const { format = htmlFormat, filename = "anonymous", mapperFile = null, removeComments = true, placeholders = {}, customProps = [] } = options;
311
+ return new SomMark({ src, format, filename, mapperFile, removeComments, placeholders, customProps }).parseSync();
312
+ };
311
313
 
312
314
  import { findAndLoadConfig } from "./core/helpers/config-loader.js";
313
315
 
@@ -316,23 +318,19 @@ export {
316
318
  MARKDOWN,
317
319
  MDX,
318
320
  Json,
321
+ XML,
319
322
  Mapper,
320
- TagBuilder,
321
- MarkdownBuilder,
322
323
  FORMATS,
323
324
  lex,
324
325
  parse,
325
326
  transpile,
326
327
  lexSync,
327
328
  parseSync,
329
+ formatAST,
328
330
  TOKEN_TYPES,
329
331
  labels,
330
332
  enableColor,
331
- htmlTable,
332
- list,
333
- parseList,
334
333
  safeArg,
335
- todo,
336
334
  findAndLoadConfig
337
335
  };
338
336
  export default SomMark;