teamix-evo 0.20.1 → 0.20.3
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 +1 -1
- package/dist/core/index.js +236 -4
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +276 -8
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -170,7 +170,7 @@ TEAMIX_DEBUG=1 teamix-evo tokens init opentrek
|
|
|
170
170
|
|
|
171
171
|
| 命令 | 说明 |
|
|
172
172
|
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
173
|
-
| `teamix-evo init [-y] [--dry-run] [--variant <n>]` | 普通版接入:检测冲突 → wizard →
|
|
173
|
+
| `teamix-evo init [-y] [--dry-run] [--variant <n>]` | 普通版接入:检测冲突 → wizard → 静默落地 → 自动提交,并校验默认 Git 工作区干净 |
|
|
174
174
|
| `teamix-evo update [--dry-run] [--cwd <dir>]` | 一键升级已装资源(tokens + skills,ADR 0003 三态 + ADR 0035 短路) |
|
|
175
175
|
| `teamix-evo migrate [--cwd <dir>] [--json]` | shadcn 项目迁移前置检查(AI skill 引导实际迁移) |
|
|
176
176
|
| `teamix-evo graft [--variant <v>] [--json] [--cwd <dir>]` | 叠加 Teamix Evo 到传统组件库项目(双栈共存,ADR 0047) |
|
package/dist/core/index.js
CHANGED
|
@@ -2027,6 +2027,7 @@ async function loadUiData(packageName) {
|
|
|
2027
2027
|
// src/core/ui-installer.ts
|
|
2028
2028
|
import * as path12 from "path";
|
|
2029
2029
|
import * as fs10 from "fs/promises";
|
|
2030
|
+
import { isBuiltin } from "module";
|
|
2030
2031
|
import { resolveUiEntryOrder } from "@teamix-evo/registry";
|
|
2031
2032
|
|
|
2032
2033
|
// src/utils/transform-imports.ts
|
|
@@ -2080,6 +2081,12 @@ async function installUiEntries(options) {
|
|
|
2080
2081
|
} = options;
|
|
2081
2082
|
const orderedIds = resolveUiEntryOrder(manifest.entries, requested);
|
|
2082
2083
|
const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
2084
|
+
const sourceContents = await preflightUiEntrySources({
|
|
2085
|
+
manifest,
|
|
2086
|
+
orderedIds,
|
|
2087
|
+
packageRoot,
|
|
2088
|
+
entryPackageRoot
|
|
2089
|
+
});
|
|
2083
2090
|
const resources = [];
|
|
2084
2091
|
const npmDeps = {};
|
|
2085
2092
|
let created = 0;
|
|
@@ -2108,7 +2115,12 @@ async function installUiEntries(options) {
|
|
|
2108
2115
|
}
|
|
2109
2116
|
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2110
2117
|
const sourceAbs = path12.resolve(rootForEntry, file.source);
|
|
2111
|
-
const raw =
|
|
2118
|
+
const raw = sourceContents.get(sourceAbs);
|
|
2119
|
+
if (raw === void 0) {
|
|
2120
|
+
throw new Error(
|
|
2121
|
+
`UI install preflight did not load source file "${file.source}" for entry "${entry.id}". No files were written.`
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2112
2124
|
const transformed = rewriteImports(raw, aliases, { flatten });
|
|
2113
2125
|
if (exists) {
|
|
2114
2126
|
const current = await fs10.readFile(targetAbs, "utf-8");
|
|
@@ -2161,6 +2173,189 @@ async function installUiEntries(options) {
|
|
|
2161
2173
|
skipped
|
|
2162
2174
|
};
|
|
2163
2175
|
}
|
|
2176
|
+
var PROJECT_RUNTIME_PACKAGES = /* @__PURE__ */ new Set(["react", "react-dom"]);
|
|
2177
|
+
async function preflightUiEntrySources(options) {
|
|
2178
|
+
const { manifest, orderedIds, packageRoot, entryPackageRoot } = options;
|
|
2179
|
+
const sourceContents = /* @__PURE__ */ new Map();
|
|
2180
|
+
const aliasProviders = buildSourceAliasProviders(manifest.entries);
|
|
2181
|
+
const sourceProviders = buildRelativeSourceProviders(
|
|
2182
|
+
manifest.entries,
|
|
2183
|
+
packageRoot,
|
|
2184
|
+
entryPackageRoot
|
|
2185
|
+
);
|
|
2186
|
+
const issues = [];
|
|
2187
|
+
for (const id of orderedIds) {
|
|
2188
|
+
const entry = manifest.entries.find((candidate) => candidate.id === id);
|
|
2189
|
+
if (!entry) continue;
|
|
2190
|
+
const declaredRegistry = new Set(entry.registryDependencies ?? []);
|
|
2191
|
+
const declaredPackages = new Set(Object.keys(entry.dependencies ?? {}));
|
|
2192
|
+
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2193
|
+
for (const file of entry.files) {
|
|
2194
|
+
const sourceAbs = path12.resolve(rootForEntry, file.source);
|
|
2195
|
+
const source = await fs10.readFile(sourceAbs, "utf-8");
|
|
2196
|
+
sourceContents.set(sourceAbs, source);
|
|
2197
|
+
if (manifest.package !== "ui") continue;
|
|
2198
|
+
for (const specifier of extractModuleSpecifiers(source)) {
|
|
2199
|
+
if (specifier.startsWith("@/")) {
|
|
2200
|
+
const provider = aliasProviders.get(specifier);
|
|
2201
|
+
if (!provider) {
|
|
2202
|
+
issues.push({
|
|
2203
|
+
entryId: entry.id,
|
|
2204
|
+
source: file.source,
|
|
2205
|
+
message: `unresolved registry import "${specifier}"`
|
|
2206
|
+
});
|
|
2207
|
+
} else if (provider !== entry.id && !declaredRegistry.has(provider)) {
|
|
2208
|
+
issues.push({
|
|
2209
|
+
entryId: entry.id,
|
|
2210
|
+
source: file.source,
|
|
2211
|
+
message: `undeclared registry dependency "${provider}" (import "${specifier}")`
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
if (specifier.startsWith(".")) {
|
|
2217
|
+
const provider = resolveRelativeProvider(
|
|
2218
|
+
path12.resolve(path12.dirname(sourceAbs), specifier),
|
|
2219
|
+
sourceProviders
|
|
2220
|
+
);
|
|
2221
|
+
if (!provider) {
|
|
2222
|
+
issues.push({
|
|
2223
|
+
entryId: entry.id,
|
|
2224
|
+
source: file.source,
|
|
2225
|
+
message: `unshipped or unresolved relative import "${specifier}"`
|
|
2226
|
+
});
|
|
2227
|
+
} else if (provider !== entry.id && !declaredRegistry.has(provider)) {
|
|
2228
|
+
issues.push({
|
|
2229
|
+
entryId: entry.id,
|
|
2230
|
+
source: file.source,
|
|
2231
|
+
message: `undeclared registry dependency "${provider}" (relative import "${specifier}")`
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
const packageName = externalPackageName(specifier);
|
|
2237
|
+
if (!isBuiltin(specifier) && !PROJECT_RUNTIME_PACKAGES.has(packageName) && !declaredPackages.has(packageName)) {
|
|
2238
|
+
issues.push({
|
|
2239
|
+
entryId: entry.id,
|
|
2240
|
+
source: file.source,
|
|
2241
|
+
message: `undeclared npm dependency "${packageName}" (import "${specifier}")`
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
if (issues.length > 0) {
|
|
2248
|
+
const details = issues.sort(
|
|
2249
|
+
(a, b) => `${a.entryId}:${a.source}:${a.message}`.localeCompare(
|
|
2250
|
+
`${b.entryId}:${b.source}:${b.message}`
|
|
2251
|
+
)
|
|
2252
|
+
).map(
|
|
2253
|
+
(issue) => `- Entry "${issue.entryId}" (${issue.source}): ${issue.message}`
|
|
2254
|
+
).join("\n");
|
|
2255
|
+
throw new Error(
|
|
2256
|
+
[
|
|
2257
|
+
"UI install preflight failed. No files were written.",
|
|
2258
|
+
details,
|
|
2259
|
+
"Fix registryDependencies/dependencies in the package manifest, publish the corrected package, and retry."
|
|
2260
|
+
].join("\n")
|
|
2261
|
+
);
|
|
2262
|
+
}
|
|
2263
|
+
return sourceContents;
|
|
2264
|
+
}
|
|
2265
|
+
function extractModuleSpecifiers(source) {
|
|
2266
|
+
const specifiers = /* @__PURE__ */ new Set();
|
|
2267
|
+
const staticPattern = /\b(?:import|export)\s+(?:type\s+)?(?:[^'";]*?\s+from\s+)?(['"])([^'"]+)\1/g;
|
|
2268
|
+
const dynamicPattern = /\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g;
|
|
2269
|
+
for (const pattern of [staticPattern, dynamicPattern]) {
|
|
2270
|
+
let match;
|
|
2271
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
2272
|
+
if (match[2]) specifiers.add(match[2]);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
return specifiers;
|
|
2276
|
+
}
|
|
2277
|
+
function buildSourceAliasProviders(entries) {
|
|
2278
|
+
const providers = /* @__PURE__ */ new Map();
|
|
2279
|
+
for (const entry of entries) {
|
|
2280
|
+
for (const file of entry.files) {
|
|
2281
|
+
const target = stripModuleExtension(file.targetName);
|
|
2282
|
+
const aliases = sourceAliases(file.targetAlias, target);
|
|
2283
|
+
for (const alias of aliases) {
|
|
2284
|
+
const current = providers.get(alias);
|
|
2285
|
+
if (current && current !== entry.id) {
|
|
2286
|
+
throw new Error(
|
|
2287
|
+
`UI install preflight found ambiguous source alias "${alias}" for entries "${current}" and "${entry.id}". No files were written.`
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
providers.set(alias, entry.id);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
return providers;
|
|
2295
|
+
}
|
|
2296
|
+
function sourceAliases(targetAlias, target) {
|
|
2297
|
+
switch (targetAlias) {
|
|
2298
|
+
case "components":
|
|
2299
|
+
return [`@/components/${target}`, `@/components/ui/${target}`];
|
|
2300
|
+
case "business":
|
|
2301
|
+
return [
|
|
2302
|
+
`@/components/business/${target}`,
|
|
2303
|
+
`@/business/${target}`
|
|
2304
|
+
];
|
|
2305
|
+
case "hooks":
|
|
2306
|
+
return [`@/hooks/${target}`];
|
|
2307
|
+
case "utils":
|
|
2308
|
+
return [`@/utils/${target}`, `@/lib/utils/${target}`];
|
|
2309
|
+
case "lib":
|
|
2310
|
+
return [`@/lib/${target}`];
|
|
2311
|
+
case "blocks":
|
|
2312
|
+
return [`@/blocks/${target}`];
|
|
2313
|
+
default:
|
|
2314
|
+
return [];
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
function buildRelativeSourceProviders(entries, packageRoot, entryPackageRoot) {
|
|
2318
|
+
const providers = /* @__PURE__ */ new Map();
|
|
2319
|
+
for (const entry of entries) {
|
|
2320
|
+
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2321
|
+
for (const file of entry.files) {
|
|
2322
|
+
const absolute = path12.resolve(rootForEntry, file.source);
|
|
2323
|
+
for (const candidate of relativeSourceCandidates(absolute)) {
|
|
2324
|
+
providers.set(candidate, entry.id);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
return providers;
|
|
2329
|
+
}
|
|
2330
|
+
function resolveRelativeProvider(absolute, providers) {
|
|
2331
|
+
for (const candidate of relativeSourceCandidates(absolute)) {
|
|
2332
|
+
const provider = providers.get(candidate);
|
|
2333
|
+
if (provider) return provider;
|
|
2334
|
+
}
|
|
2335
|
+
return void 0;
|
|
2336
|
+
}
|
|
2337
|
+
function relativeSourceCandidates(absolute) {
|
|
2338
|
+
const extension = path12.extname(absolute);
|
|
2339
|
+
if (extension) return [absolute];
|
|
2340
|
+
return [
|
|
2341
|
+
absolute,
|
|
2342
|
+
`${absolute}.ts`,
|
|
2343
|
+
`${absolute}.tsx`,
|
|
2344
|
+
`${absolute}.js`,
|
|
2345
|
+
`${absolute}.jsx`,
|
|
2346
|
+
path12.join(absolute, "index.ts"),
|
|
2347
|
+
path12.join(absolute, "index.tsx"),
|
|
2348
|
+
path12.join(absolute, "index.js"),
|
|
2349
|
+
path12.join(absolute, "index.jsx")
|
|
2350
|
+
];
|
|
2351
|
+
}
|
|
2352
|
+
function stripModuleExtension(value) {
|
|
2353
|
+
return value.replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
2354
|
+
}
|
|
2355
|
+
function externalPackageName(specifier) {
|
|
2356
|
+
const parts = specifier.split("/");
|
|
2357
|
+
return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0] ?? specifier;
|
|
2358
|
+
}
|
|
2164
2359
|
function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
2165
2360
|
const aliasDir = aliases[file.targetAlias];
|
|
2166
2361
|
if (!aliasDir) {
|
|
@@ -2502,7 +2697,16 @@ async function listBizUiEntries(variant, packageRoot) {
|
|
|
2502
2697
|
import * as path14 from "path";
|
|
2503
2698
|
import * as fs12 from "fs";
|
|
2504
2699
|
import { execa } from "execa";
|
|
2505
|
-
|
|
2700
|
+
function renderEslintConfig(tailwindCssConfigPath) {
|
|
2701
|
+
const tailwindSettings = tailwindCssConfigPath ? `
|
|
2702
|
+
{
|
|
2703
|
+
settings: {
|
|
2704
|
+
tailwindcss: {
|
|
2705
|
+
cssConfigPath: '${tailwindCssConfigPath}',
|
|
2706
|
+
},
|
|
2707
|
+
},
|
|
2708
|
+
},` : "";
|
|
2709
|
+
return `/**
|
|
2506
2710
|
* teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
|
|
2507
2711
|
* - Repo-wide: no-color-literal / no-arbitrary-tw-value / no-raw-color-scale /
|
|
2508
2712
|
* no-large-radius / prefer-gap-over-space / no-manual-dark-classnames /
|
|
@@ -2513,8 +2717,30 @@ var ESLINT_CONFIG_CONTENT = `/**
|
|
|
2513
2717
|
*/
|
|
2514
2718
|
import consumerPreset from '@teamix-evo/eslint-config/presets/consumer';
|
|
2515
2719
|
|
|
2516
|
-
export default [
|
|
2720
|
+
export default [
|
|
2721
|
+
...consumerPreset,${tailwindSettings}
|
|
2722
|
+
];
|
|
2517
2723
|
`;
|
|
2724
|
+
}
|
|
2725
|
+
var TAILWIND_CSS_CANDIDATES = [
|
|
2726
|
+
"src/index.css",
|
|
2727
|
+
"src/globals.css",
|
|
2728
|
+
"src/app/globals.css",
|
|
2729
|
+
"app/globals.css",
|
|
2730
|
+
"styles/globals.css",
|
|
2731
|
+
"src/styles/tailwind.css"
|
|
2732
|
+
];
|
|
2733
|
+
async function detectTailwindCssConfigPath(projectRoot) {
|
|
2734
|
+
for (const candidate of TAILWIND_CSS_CANDIDATES) {
|
|
2735
|
+
const content = await readFileOrNull(path14.join(projectRoot, candidate));
|
|
2736
|
+
if (content && /@(?:import\s+['"]tailwindcss(?:\/[^'"]*)?['"]|theme\b|tailwind\b)/.test(
|
|
2737
|
+
content
|
|
2738
|
+
)) {
|
|
2739
|
+
return `./${candidate}`;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
return null;
|
|
2743
|
+
}
|
|
2518
2744
|
var STYLELINT_CONFIG_CONTENT = `/** @type {import('stylelint').Config} */
|
|
2519
2745
|
module.exports = {
|
|
2520
2746
|
extends: ['@teamix-evo/stylelint-config/presets/consumer'],
|
|
@@ -2579,7 +2805,13 @@ async function runLintInit(options) {
|
|
|
2579
2805
|
let wroteEslint = false;
|
|
2580
2806
|
let wroteStylelint = false;
|
|
2581
2807
|
if (eslintNeedsWrite) {
|
|
2582
|
-
await
|
|
2808
|
+
const tailwindCssConfigPath = await detectTailwindCssConfigPath(
|
|
2809
|
+
projectRoot
|
|
2810
|
+
);
|
|
2811
|
+
await writeFileSafe(
|
|
2812
|
+
eslintConfigPath,
|
|
2813
|
+
renderEslintConfig(tailwindCssConfigPath)
|
|
2814
|
+
);
|
|
2583
2815
|
logger.debug(`Wrote eslint.config.js \u2192 ${eslintConfigPath}`);
|
|
2584
2816
|
wroteEslint = true;
|
|
2585
2817
|
}
|