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
@@ -1,51 +1,20 @@
1
1
  import path from "node:path";
2
- import os from "node:os";
3
2
  import fs from "node:fs/promises";
4
- import { pathToFileURL, fileURLToPath } from "node:url";
3
+ import { pathToFileURL } from "node:url";
5
4
 
6
5
  const CONFIG_FILE_NAME = "smark.config.js";
7
6
 
8
7
  /**
9
- * Gets the global configuration directory based on the OS.
10
- */
11
- export function getConfigDir() {
12
- const homeDir = os.homedir();
13
- if (process.platform === "win32") {
14
- return path.join(process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"), "sommark");
15
- } else if (process.platform === "darwin") {
16
- return path.join(homeDir, "Library", "Application Support", "sommark");
17
- } else {
18
- return path.join(process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"), "sommark");
19
- }
20
- }
21
-
22
- /**
23
- * Recursively searches for smark.config.js up the directory tree starting from startDir.
24
- */
25
- async function findConfig(startDir) {
26
- let currentDir = path.resolve(startDir);
27
- const root = path.parse(currentDir).root;
28
-
29
- while (true) {
30
- const configPath = path.join(currentDir, CONFIG_FILE_NAME);
31
- try {
32
- await fs.access(configPath);
33
- return configPath;
34
- } catch {
35
- if (currentDir === root) break;
36
- currentDir = path.dirname(currentDir);
37
- }
38
- }
39
- return null;
40
- }
41
-
42
- /**
43
- * Loads the configuration from a file.
8
+ * Loads a configuration object from a Javascript file.
9
+ * We add the current time to the file path. This makes Node.js read
10
+ * the file again instead of using an old copy from its memory.
11
+ *
12
+ * @param {string} configPath - The absolute path to the config file.
13
+ * @returns {Promise<Object|null>} - The configuration object or null on error.
44
14
  */
45
15
  async function loadConfigFile(configPath) {
46
16
  if (!configPath) return null;
47
17
  try {
48
- // Use a timestamp to bypass cache for dynamic updates in LSP
49
18
  const configURL = `${pathToFileURL(configPath).href}?t=${Date.now()}`;
50
19
  const loadedModule = await import(configURL);
51
20
  return loadedModule.default || loadedModule;
@@ -55,73 +24,69 @@ async function loadConfigFile(configPath) {
55
24
  }
56
25
 
57
26
  /**
58
- * Finds and loads the configuration starting from targetPath.
59
- * Checks local directory, parent directories, and finally the global config directory.
27
+ * Finds and loads the SomMark configuration file.
28
+ * It looks in the current folder or a specific path if provided.
29
+ *
30
+ * @param {string|null} targetPath - A specific file or folder to look in.
31
+ * @returns {Promise<Object>} - The final configuration merged with defaults.
60
32
  */
61
33
  export async function findAndLoadConfig(targetPath) {
62
- let startDir;
34
+ let startDir = process.cwd();
35
+ let configPath = null;
36
+
37
+ // 1. Check if targetPath is an explicit config file path
63
38
  if (targetPath) {
64
39
  try {
65
40
  const stats = await fs.stat(targetPath);
66
- startDir = stats.isDirectory() ? targetPath : path.dirname(targetPath);
67
- } catch {
68
- startDir = process.cwd();
69
- }
70
- } else {
71
- startDir = process.cwd();
72
- }
73
-
74
- let configPath = await findConfig(startDir);
75
-
76
- if (!configPath) {
77
- // As a fallback, check the current working directory of the process
78
- // This helps LSP find the project config when running in the project root
79
- const localConfigPath = path.join(process.cwd(), CONFIG_FILE_NAME);
80
- try {
81
- await fs.access(localConfigPath);
82
- configPath = localConfigPath;
41
+ if (stats.isFile() && targetPath.endsWith(".js")) {
42
+ configPath = path.resolve(targetPath);
43
+ } else {
44
+ startDir = stats.isDirectory() ? targetPath : path.dirname(targetPath);
45
+ }
83
46
  } catch {
84
- // Not in CWD
47
+ // Path doesn't exist
85
48
  }
86
49
  }
87
50
 
51
+ // 2. Check the current folder
88
52
  if (!configPath) {
89
- const globalConfigPath = path.join(getConfigDir(), CONFIG_FILE_NAME);
53
+ const localConfig = path.join(startDir, CONFIG_FILE_NAME);
90
54
  try {
91
- await fs.access(globalConfigPath);
92
- configPath = globalConfigPath;
55
+ await fs.access(localConfig);
56
+ configPath = localConfig;
93
57
  } catch {
94
- // No config found
58
+ // No local config found
95
59
  }
96
60
  }
97
-
61
+
98
62
  const defaultConfig = {
99
63
  outputFile: "output",
100
64
  outputDir: startDir,
101
- mappingFile: null,
102
- plugins: [],
103
- priority: [],
104
- excludePlugins: [],
105
- includeDocument: true
65
+ mapperFile: null,
66
+ removeComments: true,
67
+ placeholders: {},
68
+ customProps: [],
106
69
  };
107
70
 
108
71
  if (configPath) {
109
72
  const loadedConfig = await loadConfigFile(configPath);
110
73
  if (loadedConfig) {
111
- const finalConfig = { ...defaultConfig, ...loadedConfig, resolvedConfigPath: configPath };
74
+ // Support both mapperFile and mappingFile (backwards compatibility)
75
+ const finalMapper = loadedConfig.mapperFile || loadedConfig.mappingFile || defaultConfig.mapperFile;
112
76
 
113
- // Ensure outputDir is resolved if it's relative in the config
77
+ const finalConfig = {
78
+ ...defaultConfig,
79
+ ...loadedConfig,
80
+ mapperFile: finalMapper,
81
+ resolvedConfigPath: configPath
82
+ };
114
83
  if (loadedConfig.outputDir) {
115
84
  const configDir = path.dirname(configPath);
116
85
  finalConfig.outputDir = path.resolve(configDir, loadedConfig.outputDir);
117
86
  }
118
-
119
87
  return finalConfig;
120
88
  }
121
89
  }
122
90
 
123
91
  return { ...defaultConfig, resolvedConfigPath: null };
124
92
  }
125
-
126
-
127
-
package/core/labels.js CHANGED
@@ -1,27 +1,39 @@
1
+ /**
2
+ * These labels identify different parts of the code (like blocks or text)
3
+ * so the system knows how to handle them.
4
+ */
1
5
  export const BLOCK = "Block",
2
6
  TEXT = "Text",
3
7
  INLINE = "Inline",
4
8
  ATBLOCK = "AtBlock",
5
9
  COMMENT = "Comment",
6
10
  IMPORT = "Import",
7
- USE_MODULE = "$use-module",
8
- SEMICOLON = "Semicolon",
11
+ USE_MODULE = "$use-module";
12
+
13
+ /**
14
+ * Names for symbols used to separate parts of the code (like commas and colons).
15
+ */
16
+ export const SEMICOLON = "Semicolon",
9
17
  BLOCKCOMMA = "Block-comma",
10
18
  ATBLOCKCOMMA = "Atblock-comma",
11
19
  INLINECOMMA = "Inline-comma",
12
20
  BLOCKCOLON = "Block-colon",
13
21
  ATBLOCKCOLON = "Atblock-colon",
14
- INLINECOLON = "Inline-colon",
15
- block_id = "Block Identifier",
22
+ INLINECOLON = "Inline-colon";
23
+
24
+ /**
25
+ * These names are used in error messages to tell you exactly which part
26
+ * of your code has a mistake.
27
+ */
28
+ export const block_id = "Block Identifier",
16
29
  block_value = "Block Value",
17
- block_id_2 = "Block Identifier 2",
30
+ block_key = "Block Key",
18
31
  block_end = "Block end",
19
32
  inline_id = "Inline Identifier",
20
- inline_value = "Inline Value",
21
- inline_id_2 = "Inline Identifier 2",
33
+ inline_text = "Inline Text",
22
34
  at_id = "At Identifier",
23
35
  at_value = "At Value",
24
- at_id_2 = "At Identifier 2",
36
+ atblock_key = "AtBlock Key",
25
37
  at_end = "Atblock End",
26
- block_end_2 = "Block End 2",
38
+ /** Reserved keyword for closing blocks */
27
39
  end_keyword = "end";