@triflare/fx 1.0.3 → 2.1.0-beta.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 (68) hide show
  1. package/README.md +59 -0
  2. package/bin/fx.js +4 -1162
  3. package/package.json +8 -4
  4. package/product.yml +1 -1
  5. package/src/brand.js +9 -3
  6. package/src/catalog.js +103 -0
  7. package/src/cli/commands/build.js +98 -0
  8. package/src/cli/commands/catalog.js +42 -0
  9. package/src/cli/commands/check.js +44 -0
  10. package/src/cli/commands/completion.js +54 -0
  11. package/src/cli/commands/decompile.js +266 -0
  12. package/src/cli/commands/dev.js +179 -0
  13. package/src/cli/commands/extension.js +110 -0
  14. package/src/cli/commands/feature.js +114 -0
  15. package/src/cli/commands/fmt.js +173 -0
  16. package/src/cli/commands/index.js +45 -0
  17. package/src/cli/commands/init.js +169 -0
  18. package/src/cli/commands/lint.js +270 -0
  19. package/src/cli/commands/package.js +137 -0
  20. package/src/cli/commands/sprite/add.js +85 -0
  21. package/src/cli/commands/sprite/build.js +62 -0
  22. package/src/cli/commands/sprite/helpers.js +66 -0
  23. package/src/cli/commands/sprite/index.js +29 -0
  24. package/src/cli/commands/sprite/list.js +31 -0
  25. package/src/cli/commands/sprite/remove.js +51 -0
  26. package/src/cli/commands/vendor/add.js +98 -0
  27. package/src/cli/commands/vendor/helpers.js +50 -0
  28. package/src/cli/commands/vendor/index.js +39 -0
  29. package/src/cli/commands/vendor/install.js +64 -0
  30. package/src/cli/commands/vendor/list.js +45 -0
  31. package/src/cli/commands/vendor/migrate.js +47 -0
  32. package/src/cli/commands/vendor/outdated.js +51 -0
  33. package/src/cli/commands/vendor/remove.js +34 -0
  34. package/src/cli/commands/vendor/update.js +49 -0
  35. package/src/cli/commands/vendor/verify.js +44 -0
  36. package/src/cli/completion/bash.js +10 -0
  37. package/src/cli/completion/fish.js +9 -0
  38. package/src/cli/completion/index.js +97 -0
  39. package/src/cli/completion/zsh.js +11 -0
  40. package/src/cli/context.js +270 -0
  41. package/src/cli/define-command.js +147 -0
  42. package/src/cli/errors.js +111 -0
  43. package/src/cli/format.js +31 -0
  44. package/src/cli/prompts.js +183 -0
  45. package/src/cli/reporter.js +203 -0
  46. package/src/cli/run.js +248 -0
  47. package/src/cli/templates/index.js +112 -0
  48. package/src/cli/theme.js +84 -0
  49. package/src/compiler.js +133 -0
  50. package/src/config-edit.js +399 -1
  51. package/src/config.js +174 -4
  52. package/src/decompiler.js +45 -0
  53. package/src/extensions.js +72 -19
  54. package/src/features.js +339 -0
  55. package/src/formatter.js +499 -0
  56. package/src/index.js +31 -0
  57. package/src/lexer.js +45 -4
  58. package/src/lint/analyze.js +1414 -0
  59. package/src/lint/config-file.js +97 -0
  60. package/src/lint/config.js +174 -0
  61. package/src/lint/rules.js +461 -0
  62. package/src/linter.js +220 -0
  63. package/src/merge.js +109 -0
  64. package/src/parser.js +53 -13
  65. package/src/project.js +7 -87
  66. package/src/vendor.js +1323 -0
  67. package/vendor/pm-packager-dist/.fx-build.json +1 -1
  68. package/vendor/tempvars/fx-tempvars.js +321 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Browser-safe `fx.yml` reader for editor tooling.
3
+ *
4
+ * The full config loader (`src/config.js`) needs `node:fs` to search for the
5
+ * file, so editors that only have the file's text use this instead. It reads
6
+ * the settings lint diagnostics depend on — `fx.partialSprites`, `fx.lint` and
7
+ * the declared extension names — and ignores everything else.
8
+ */
9
+
10
+ import * as yaml from "js-yaml";
11
+ import { normalizeLintConfig } from "./config.js";
12
+
13
+ /** Extension name from a vendor path such as `extensions/signals.js`. */
14
+ function extensionName(source) {
15
+ const base = String(source).split(/[\\/]/).pop() ?? "";
16
+ return base.replace(/\.js$/i, "");
17
+ }
18
+
19
+ /**
20
+ * @param {string} text raw `fx.yml`/`fx.yaml` contents
21
+ * @returns {{
22
+ * config: {fx: {partialSprites: boolean}},
23
+ * lintConfig: object,
24
+ * declaredExtensions: string[],
25
+ * projectName: string|null,
26
+ * error?: string,
27
+ * }}
28
+ */
29
+ export function parseProjectConfigText(text) {
30
+ let raw;
31
+ try {
32
+ raw = yaml.load(text) ?? {};
33
+ } catch (error) {
34
+ return {
35
+ config: null,
36
+ lintConfig: null,
37
+ declaredExtensions: [],
38
+ projectName: null,
39
+ error: error instanceof Error ? error.message : String(error),
40
+ };
41
+ }
42
+ if (typeof raw !== "object" || Array.isArray(raw)) {
43
+ return {
44
+ config: null,
45
+ lintConfig: null,
46
+ declaredExtensions: [],
47
+ projectName: null,
48
+ error: "fx.yml must contain a mapping at the top level",
49
+ };
50
+ }
51
+
52
+ const fx =
53
+ raw.fx && typeof raw.fx === "object" && !Array.isArray(raw.fx)
54
+ ? raw.fx
55
+ : {};
56
+ const project =
57
+ raw.project &&
58
+ typeof raw.project === "object" &&
59
+ !Array.isArray(raw.project)
60
+ ? raw.project
61
+ : {};
62
+
63
+ let lintConfig;
64
+ try {
65
+ lintConfig = normalizeLintConfig(fx.lint ?? {});
66
+ } catch (error) {
67
+ return {
68
+ config: null,
69
+ lintConfig: null,
70
+ declaredExtensions: [],
71
+ projectName: typeof project.name === "string" ? project.name : null,
72
+ error: error instanceof Error ? error.message : String(error),
73
+ };
74
+ }
75
+
76
+ const declaredExtensions = new Set();
77
+ if (
78
+ raw.vendor &&
79
+ typeof raw.vendor === "object" &&
80
+ !Array.isArray(raw.vendor)
81
+ ) {
82
+ for (const name of Object.keys(raw.vendor)) declaredExtensions.add(name);
83
+ }
84
+ if (Array.isArray(project.extensions)) {
85
+ for (const source of project.extensions) {
86
+ const name = extensionName(source);
87
+ if (name) declaredExtensions.add(name);
88
+ }
89
+ }
90
+
91
+ return {
92
+ config: { fx: { partialSprites: Boolean(fx.partialSprites) } },
93
+ lintConfig,
94
+ declaredExtensions: [...declaredExtensions],
95
+ projectName: typeof project.name === "string" ? project.name : null,
96
+ };
97
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * `fx.lint` configuration and rule selection.
3
+ *
4
+ * Keeping this separate from the engine lets `src/config.js` validate the
5
+ * `lint:` block without importing the analyzer (and its vendor/extension
6
+ * dependencies), so configuration loading stays side-effect free.
7
+ */
8
+
9
+ import {
10
+ META_RULE_IDS,
11
+ PRESET_NAMES,
12
+ PRESETS,
13
+ RULES,
14
+ ruleById,
15
+ } from "./rules.js";
16
+
17
+ /** Default lint settings when `fx.yml` has no `lint:` block. */
18
+ export const DEFAULT_LINT = {
19
+ extends: "recommended",
20
+ rules: {},
21
+ };
22
+
23
+ const SEVERITY_ALIASES = {
24
+ error: "error",
25
+ warn: "warning",
26
+ warning: "warning",
27
+ off: "off",
28
+ none: "off",
29
+ };
30
+
31
+ /**
32
+ * Normalize a severity string.
33
+ * @param {unknown} value
34
+ * @returns {'error'|'warning'|'off'|null}
35
+ */
36
+ export function normalizeSeverity(value) {
37
+ if (typeof value !== "string") return null;
38
+ return SEVERITY_ALIASES[value.trim().toLowerCase()] ?? null;
39
+ }
40
+
41
+ /**
42
+ * Validate and normalize an `fx.lint` mapping.
43
+ *
44
+ * @param {unknown} raw
45
+ * @param {(message: string) => Error} [makeError]
46
+ * @returns {{extends: string, rules: Record<string, 'error'|'warning'|'off'>}}
47
+ */
48
+ export function normalizeLintConfig(
49
+ raw = {},
50
+ makeError = (message) => new Error(message),
51
+ ) {
52
+ const lint = { extends: DEFAULT_LINT.extends, rules: {} };
53
+ if (raw == null) return lint;
54
+ if (typeof raw !== "object" || Array.isArray(raw))
55
+ throw makeError("fx.lint must be a mapping");
56
+
57
+ const unknownKeys = Object.keys(raw).filter(
58
+ (key) => !["extends", "rules"].includes(key),
59
+ );
60
+ if (unknownKeys.length)
61
+ throw makeError(
62
+ `unknown fx.lint setting(s): ${unknownKeys
63
+ .map((key) => `"${key}"`)
64
+ .join(", ")}`,
65
+ );
66
+
67
+ if (raw.extends != null) {
68
+ if (typeof raw.extends !== "string")
69
+ throw makeError("fx.lint.extends must be a preset name");
70
+ const preset = raw.extends.trim().toLowerCase();
71
+ if (!PRESET_NAMES.includes(preset))
72
+ throw makeError(
73
+ `unknown lint preset ${JSON.stringify(raw.extends)}; ` +
74
+ `expected one of: ${PRESET_NAMES.join(", ")}`,
75
+ );
76
+ lint.extends = preset;
77
+ }
78
+
79
+ if (raw.rules != null) {
80
+ if (typeof raw.rules !== "object" || Array.isArray(raw.rules))
81
+ throw makeError("fx.lint.rules must be a mapping of rule ID to severity");
82
+ for (const [rawId, rawSeverity] of Object.entries(raw.rules)) {
83
+ const rule = ruleById(rawId);
84
+ if (!rule)
85
+ throw makeError(
86
+ `unknown lint rule ${JSON.stringify(rawId)} in fx.lint.rules`,
87
+ );
88
+ if (META_RULE_IDS.includes(rule.id))
89
+ throw makeError(`fx.lint.rules cannot configure ${rule.id}`);
90
+ const severity = normalizeSeverity(rawSeverity);
91
+ if (!severity)
92
+ throw makeError(
93
+ `fx.lint.rules.${rawId} must be one of: error, warn, off`,
94
+ );
95
+ lint.rules[rule.id] = severity;
96
+ }
97
+ }
98
+
99
+ return lint;
100
+ }
101
+
102
+ /**
103
+ * The preset a run actually uses: `strict` raises a weaker configured preset
104
+ * but never downgrades a stronger one such as `all`.
105
+ *
106
+ * @param {ReturnType<typeof normalizeLintConfig>} [lint]
107
+ * @param {boolean} [strict]
108
+ * @returns {string}
109
+ */
110
+ export function effectivePreset(lint = DEFAULT_LINT, strict = false) {
111
+ const configured = PRESET_NAMES.includes(lint?.extends)
112
+ ? lint.extends
113
+ : DEFAULT_LINT.extends;
114
+ if (!strict) return configured;
115
+ return PRESET_NAMES.indexOf(configured) >= PRESET_NAMES.indexOf("strict")
116
+ ? configured
117
+ : "strict";
118
+ }
119
+
120
+ /**
121
+ * Resolve every rule's effective severity for a lint run.
122
+ *
123
+ * Presets only decide which rules start enabled; overrides can enable a rule
124
+ * outside the preset or turn one off. `strict` escalates the preset even when
125
+ * `fx.yml` asks for something lower, without downgrading a stronger preset.
126
+ *
127
+ * @param {ReturnType<typeof normalizeLintConfig>} [lint]
128
+ * @param {{strict?: boolean, overrides?: Record<string, string>}} [options]
129
+ * @returns {Map<string, 'error'|'warning'|'off'>}
130
+ */
131
+ export function resolveRuleSeverities(
132
+ lint = DEFAULT_LINT,
133
+ { strict = false, overrides = {} } = {},
134
+ ) {
135
+ const presetName = effectivePreset(lint, strict);
136
+ const enabled = new Set(PRESETS[presetName] ?? PRESETS.recommended);
137
+ const severities = new Map();
138
+ for (const id of Object.keys(RULES)) {
139
+ if (META_RULE_IDS.includes(id)) continue;
140
+ severities.set(id, enabled.has(id) ? RULES[id].severity : "off");
141
+ }
142
+
143
+ const apply = (rawOverrides) => {
144
+ for (const [rawId, rawSeverity] of Object.entries(rawOverrides || {})) {
145
+ const rule = ruleById(rawId);
146
+ if (!rule) continue;
147
+ const severity = normalizeSeverity(rawSeverity);
148
+ if (!severity) continue;
149
+ severities.set(rule.id, severity);
150
+ }
151
+ };
152
+ apply(lint.rules);
153
+ apply(overrides);
154
+ return severities;
155
+ }
156
+
157
+ /**
158
+ * Parse a `--rule` value: `FX201`, `FX201=error`, `FX201:off` or a preset
159
+ * escalation such as `strict`. Unknown rules are reported by the caller so a
160
+ * typo does not silently do nothing.
161
+ *
162
+ * @param {string} value
163
+ * @returns {{id: string, severity?: string}}
164
+ */
165
+ export function parseRuleOption(value) {
166
+ const text = String(value).trim();
167
+ const match = text.match(/^([^=:]+)\s*[=:]\s*(.+)$/);
168
+ if (match)
169
+ return {
170
+ id: match[1].trim(),
171
+ severity: normalizeSeverity(match[2]) ?? match[2].trim(),
172
+ };
173
+ return { id: text };
174
+ }