sommark 3.3.3 → 4.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.
Files changed (61) 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 +8 -16
  6. package/cli/commands/build.js +24 -4
  7. package/cli/commands/color.js +22 -26
  8. package/cli/commands/help.js +10 -10
  9. package/cli/commands/init.js +19 -42
  10. package/cli/commands/print.js +20 -12
  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 +7 -8
  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 +37 -56
  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 +237 -151
  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/escapeHTML.js +13 -6
  33. package/helpers/kebabize.js +6 -0
  34. package/helpers/peek.js +9 -0
  35. package/helpers/removeChar.js +26 -13
  36. package/helpers/safeDataParser.js +114 -0
  37. package/helpers/utils.js +140 -158
  38. package/index.js +198 -188
  39. package/mappers/languages/html.js +105 -213
  40. package/mappers/languages/json.js +122 -171
  41. package/mappers/languages/markdown.js +355 -108
  42. package/mappers/languages/mdx.js +76 -114
  43. package/mappers/languages/xml.js +114 -0
  44. package/mappers/mapper.js +152 -123
  45. package/mappers/shared/index.js +22 -0
  46. package/package.json +26 -6
  47. package/SOMMARK-SPEC.md +0 -481
  48. package/cli/commands/list.js +0 -124
  49. package/constants/html_tags.js +0 -146
  50. package/core/pluginManager.js +0 -149
  51. package/core/plugins/comment-remover.js +0 -47
  52. package/core/plugins/module-system.js +0 -176
  53. package/core/plugins/raw-content-plugin.js +0 -78
  54. package/core/plugins/rules-validation-plugin.js +0 -231
  55. package/core/plugins/sommark-format.js +0 -244
  56. package/coverage_test.js +0 -21
  57. package/debug.js +0 -15
  58. package/helpers/camelize.js +0 -2
  59. package/helpers/defaultTheme.js +0 -3
  60. package/test_format_fix.js +0 -42
  61. package/v3-todo.smark +0 -73
@@ -1,48 +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 = startDir;
27
- while (currentDir !== path.parse(currentDir).root) {
28
- const configPath = path.join(currentDir, CONFIG_FILE_NAME);
29
- try {
30
- await fs.access(configPath);
31
- return configPath;
32
- } catch {
33
- currentDir = path.dirname(currentDir);
34
- }
35
- }
36
- return null;
37
- }
38
-
39
- /**
40
- * 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.
41
14
  */
42
15
  async function loadConfigFile(configPath) {
43
16
  if (!configPath) return null;
44
17
  try {
45
- // Use a timestamp to bypass cache for dynamic updates in LSP
46
18
  const configURL = `${pathToFileURL(configPath).href}?t=${Date.now()}`;
47
19
  const loadedModule = await import(configURL);
48
20
  return loadedModule.default || loadedModule;
@@ -52,48 +24,57 @@ async function loadConfigFile(configPath) {
52
24
  }
53
25
 
54
26
  /**
55
- * Finds and loads the configuration starting from targetPath.
56
- * 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.
57
32
  */
58
33
  export async function findAndLoadConfig(targetPath) {
59
- const startDir = targetPath ? (await fs.stat(targetPath)).isDirectory() ? targetPath : path.dirname(targetPath) : process.cwd();
60
-
61
- let configPath = await findConfig(startDir);
62
-
63
- if (!configPath) {
64
- // As a fallback, check the current working directory of the process
65
- // This helps LSP find the project config when running in the project root
66
- const localConfigPath = path.join(process.cwd(), CONFIG_FILE_NAME);
34
+ let startDir = process.cwd();
35
+ let configPath = null;
36
+
37
+ // 1. Check if targetPath is an explicit config file path
38
+ if (targetPath) {
67
39
  try {
68
- await fs.access(localConfigPath);
69
- configPath = localConfigPath;
40
+ const stats = await fs.stat(targetPath);
41
+ if (stats.isFile() && targetPath.endsWith(".js")) {
42
+ configPath = path.resolve(targetPath);
43
+ } else {
44
+ startDir = stats.isDirectory() ? targetPath : path.dirname(targetPath);
45
+ }
70
46
  } catch {
71
- // Not in CWD
47
+ // Path doesn't exist
72
48
  }
73
49
  }
74
50
 
51
+ // 2. Check the current folder
75
52
  if (!configPath) {
76
- const globalConfigPath = path.join(getConfigDir(), CONFIG_FILE_NAME);
53
+ const localConfig = path.join(startDir, CONFIG_FILE_NAME);
77
54
  try {
78
- await fs.access(globalConfigPath);
79
- configPath = globalConfigPath;
55
+ await fs.access(localConfig);
56
+ configPath = localConfig;
80
57
  } catch {
81
- // No config found
58
+ // No local config found
82
59
  }
83
60
  }
84
-
61
+
85
62
  const defaultConfig = {
86
63
  outputFile: "output",
87
64
  outputDir: startDir,
88
65
  mappingFile: null,
89
- plugins: [],
90
- priority: []
66
+ removeComments: true,
91
67
  };
92
68
 
93
69
  if (configPath) {
94
70
  const loadedConfig = await loadConfigFile(configPath);
95
71
  if (loadedConfig) {
96
- return { ...defaultConfig, ...loadedConfig, resolvedConfigPath: configPath };
72
+ const finalConfig = { ...defaultConfig, ...loadedConfig, resolvedConfigPath: configPath };
73
+ if (loadedConfig.outputDir) {
74
+ const configDir = path.dirname(configPath);
75
+ finalConfig.outputDir = path.resolve(configDir, loadedConfig.outputDir);
76
+ }
77
+ return finalConfig;
97
78
  }
98
79
  }
99
80
 
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";