@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.
- package/README.md +59 -0
- package/bin/fx.js +4 -1162
- package/package.json +8 -4
- package/product.yml +1 -1
- package/src/brand.js +9 -3
- package/src/catalog.js +103 -0
- package/src/cli/commands/build.js +98 -0
- package/src/cli/commands/catalog.js +42 -0
- package/src/cli/commands/check.js +44 -0
- package/src/cli/commands/completion.js +54 -0
- package/src/cli/commands/decompile.js +266 -0
- package/src/cli/commands/dev.js +179 -0
- package/src/cli/commands/extension.js +110 -0
- package/src/cli/commands/feature.js +114 -0
- package/src/cli/commands/fmt.js +173 -0
- package/src/cli/commands/index.js +45 -0
- package/src/cli/commands/init.js +169 -0
- package/src/cli/commands/lint.js +270 -0
- package/src/cli/commands/package.js +137 -0
- package/src/cli/commands/sprite/add.js +85 -0
- package/src/cli/commands/sprite/build.js +62 -0
- package/src/cli/commands/sprite/helpers.js +66 -0
- package/src/cli/commands/sprite/index.js +29 -0
- package/src/cli/commands/sprite/list.js +31 -0
- package/src/cli/commands/sprite/remove.js +51 -0
- package/src/cli/commands/vendor/add.js +98 -0
- package/src/cli/commands/vendor/helpers.js +50 -0
- package/src/cli/commands/vendor/index.js +39 -0
- package/src/cli/commands/vendor/install.js +64 -0
- package/src/cli/commands/vendor/list.js +45 -0
- package/src/cli/commands/vendor/migrate.js +47 -0
- package/src/cli/commands/vendor/outdated.js +51 -0
- package/src/cli/commands/vendor/remove.js +34 -0
- package/src/cli/commands/vendor/update.js +49 -0
- package/src/cli/commands/vendor/verify.js +44 -0
- package/src/cli/completion/bash.js +10 -0
- package/src/cli/completion/fish.js +9 -0
- package/src/cli/completion/index.js +97 -0
- package/src/cli/completion/zsh.js +11 -0
- package/src/cli/context.js +270 -0
- package/src/cli/define-command.js +147 -0
- package/src/cli/errors.js +111 -0
- package/src/cli/format.js +31 -0
- package/src/cli/prompts.js +183 -0
- package/src/cli/reporter.js +203 -0
- package/src/cli/run.js +248 -0
- package/src/cli/templates/index.js +112 -0
- package/src/cli/theme.js +84 -0
- package/src/compiler.js +133 -0
- package/src/config-edit.js +399 -1
- package/src/config.js +174 -4
- package/src/decompiler.js +45 -0
- package/src/extensions.js +72 -19
- package/src/features.js +339 -0
- package/src/formatter.js +499 -0
- package/src/index.js +31 -0
- package/src/lexer.js +45 -4
- package/src/lint/analyze.js +1414 -0
- package/src/lint/config-file.js +97 -0
- package/src/lint/config.js +174 -0
- package/src/lint/rules.js +461 -0
- package/src/linter.js +220 -0
- package/src/merge.js +109 -0
- package/src/parser.js +53 -13
- package/src/project.js +7 -87
- package/src/vendor.js +1323 -0
- package/vendor/pm-packager-dist/.fx-build.json +1 -1
- 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
|
+
}
|