@codefast/cli 0.3.16-canary.2 → 0.4.0-canary.4
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 +254 -86
- package/dist/arrange/analyze.mjs +2 -2
- package/dist/arrange/command.mjs +51 -27
- package/dist/arrange/domain/analyze-service.mjs +2 -2
- package/dist/arrange/domain/ast/collectors-cn.mjs +1 -1
- package/dist/arrange/domain/ast/collectors-tv.mjs +2 -2
- package/dist/arrange/domain/ast/helpers.mjs +2 -2
- package/dist/arrange/domain/ast/simplify-targets.mjs +109 -0
- package/dist/arrange/domain/ast/targets.mjs +25 -10
- package/dist/arrange/domain/grouping-service.mjs +1 -1
- package/dist/arrange/domain/grouping.mjs +5 -5
- package/dist/arrange/domain/imports.mjs +50 -2
- package/dist/arrange/domain/token-classifier.mjs +12 -12
- package/dist/arrange/output.mjs +11 -3
- package/dist/arrange/process-file.mjs +1 -1
- package/dist/arrange/scan-target.mjs +10 -1
- package/dist/arrange/simplify-process-file.mjs +35 -0
- package/dist/arrange/simplify-sync.mjs +32 -0
- package/dist/arrange/suggest.mjs +1 -1
- package/dist/arrange/sync.mjs +1 -1
- package/dist/arrange/workspace.mjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/core/cli/result-handle.mjs +1 -1
- package/dist/core/config/schema.mjs +31 -10
- package/dist/core/source-text-edit.mjs +1 -1
- package/dist/core/workspace/resolver.mjs +3 -3
- package/dist/mirror/cli-result.mjs +2 -1
- package/dist/mirror/cli-schema.mjs +2 -1
- package/dist/mirror/command.mjs +12 -11
- package/dist/mirror/domain/exports.mjs +16 -19
- package/dist/mirror/output.mjs +3 -0
- package/dist/mirror/supplement-exports.mjs +114 -0
- package/dist/mirror/sync-reporter.mjs +5 -2
- package/dist/mirror/sync-workspace-package.mjs +35 -29
- package/dist/mirror/sync.mjs +2 -1
- package/dist/mirror/write-exports.mjs +3 -2
- package/dist/tag/command.mjs +6 -6
- package/dist/tag/output.mjs +1 -1
- package/dist/tag/sync.mjs +1 -1
- package/dist/tag/target-runner.mjs +1 -1
- package/package.json +10 -10
|
@@ -47,7 +47,7 @@ function endAfterOptionalCommaFollowingInSource(source, tokenEnd) {
|
|
|
47
47
|
* @since 0.3.16-canary.0
|
|
48
48
|
*/
|
|
49
49
|
function applyEditsDescending(sourceText, edits) {
|
|
50
|
-
const sorted = [...edits].
|
|
50
|
+
const sorted = [...edits].toSorted((editA, editB) => editB.start - editA.start);
|
|
51
51
|
let out = sourceText;
|
|
52
52
|
for (const edit of sorted) out = out.slice(0, edit.start) + edit.replacement + out.slice(edit.end);
|
|
53
53
|
return out;
|
|
@@ -92,13 +92,13 @@ async function readWorkspaceYaml(rootDir, fs) {
|
|
|
92
92
|
try {
|
|
93
93
|
raw = await fs.readFile(workspaceYamlPath, "utf8");
|
|
94
94
|
} catch (caughtReadError) {
|
|
95
|
-
throw new Error(`Failed to read ${wf}: ${messageFrom(caughtReadError)}
|
|
95
|
+
throw new Error(`Failed to read ${wf}: ${messageFrom(caughtReadError)}`, { cause: caughtReadError });
|
|
96
96
|
}
|
|
97
97
|
let doc;
|
|
98
98
|
try {
|
|
99
99
|
doc = parse(raw);
|
|
100
100
|
} catch (caughtYamlParseError) {
|
|
101
|
-
throw new Error(`Failed to parse ${wf}: ${messageFrom(caughtYamlParseError)}
|
|
101
|
+
throw new Error(`Failed to parse ${wf}: ${messageFrom(caughtYamlParseError)}`, { cause: caughtYamlParseError });
|
|
102
102
|
}
|
|
103
103
|
if (doc === null || doc === void 0) throw new Error(`${wf} must define a mapping at the document root`);
|
|
104
104
|
return {
|
|
@@ -153,7 +153,7 @@ async function listWorkspacePackageDirectories(rootDirectoryPathAbsolute, fs, su
|
|
|
153
153
|
if (!suppressGlobPermissionDiagnostics) logger.out(`⚠ Skipping workspace glob "${pattern}" (${messageFrom(caughtGlobError)})`);
|
|
154
154
|
continue;
|
|
155
155
|
}
|
|
156
|
-
throw new Error(`Invalid workspace glob "${pattern}": ${messageFrom(caughtGlobError)}
|
|
156
|
+
throw new Error(`Invalid workspace glob "${pattern}": ${messageFrom(caughtGlobError)}`, { cause: caughtGlobError });
|
|
157
157
|
}
|
|
158
158
|
for (const matchedPath of matches) {
|
|
159
159
|
const posix = toPosix(matchedPath);
|
|
@@ -9,10 +9,11 @@ function exitCodeForMirrorSyncResult(stats) {
|
|
|
9
9
|
/**
|
|
10
10
|
* @since 0.3.16-canary.0
|
|
11
11
|
*/
|
|
12
|
-
function formatMirrorSyncJsonOutput(stats, elapsedSeconds) {
|
|
12
|
+
function formatMirrorSyncJsonOutput(stats, elapsedSeconds, write = true) {
|
|
13
13
|
return JSON.stringify({
|
|
14
14
|
schemaVersion: 1,
|
|
15
15
|
ok: stats.packagesErrored === 0,
|
|
16
|
+
write,
|
|
16
17
|
elapsedSeconds,
|
|
17
18
|
stats
|
|
18
19
|
});
|
|
@@ -6,7 +6,8 @@ import { z } from "zod";
|
|
|
6
6
|
const mirrorSyncRunRequestSchema = z.object({
|
|
7
7
|
rootDir: z.string().min(1),
|
|
8
8
|
packageFilter: z.string().optional(),
|
|
9
|
-
config: z.unknown().optional()
|
|
9
|
+
config: z.unknown().optional(),
|
|
10
|
+
write: z.boolean().optional()
|
|
10
11
|
});
|
|
11
12
|
//#endregion
|
|
12
13
|
export { mirrorSyncRunRequestSchema };
|
package/dist/mirror/command.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
2
1
|
import { logger } from "../core/logger.mjs";
|
|
2
|
+
import { readOptionalPositionalArg } from "../core/cli/positional.mjs";
|
|
3
3
|
import { consumeCliAppError } from "../core/cli/result-handle.mjs";
|
|
4
4
|
import { nodeFilesystem } from "../core/filesystem/node.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
6
6
|
import { globalCliCommanderOptionsSchema } from "../core/cli/global-options.mjs";
|
|
7
|
-
import { prepareMirrorSync } from "./prepare.mjs";
|
|
8
|
-
import { runMirrorSync } from "./sync.mjs";
|
|
9
|
-
import { mirrorSyncRunRequestSchema } from "./cli-schema.mjs";
|
|
10
7
|
import { exitCodeForMirrorSyncResult, formatMirrorSyncJsonOutput } from "./cli-result.mjs";
|
|
8
|
+
import { mirrorSyncRunRequestSchema } from "./cli-schema.mjs";
|
|
11
9
|
import { MirrorSyncProgressPresenter } from "./output.mjs";
|
|
10
|
+
import { prepareMirrorSync } from "./prepare.mjs";
|
|
11
|
+
import { runMirrorSync } from "./sync.mjs";
|
|
12
12
|
import process from "node:process";
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
//#region src/mirror/command.ts
|
|
@@ -16,8 +16,7 @@ import { Command } from "commander";
|
|
|
16
16
|
* @since 0.3.16-canary.0
|
|
17
17
|
*/
|
|
18
18
|
function createMirrorCommand() {
|
|
19
|
-
|
|
20
|
-
cmd.command("sync").description("Write package.json exports from dist/ for workspace packages").argument("[package]", "Optional package path relative to repo root (e.g. packages/ui)").option("-v, --verbose", "Print extra diagnostics", false).option("--json", "Print one JSON summary on stdout (suppresses human progress)", false).action(async (packageArg, opts, command) => {
|
|
19
|
+
return new Command("mirror").description("Write package.json exports from dist/ for workspace packages").argument("[package]", "Optional package path relative to repo root (e.g. packages/ui)").option("--dry-run", "Report what would change without writing package.json", false).option("-v, --verbose", "Print extra diagnostics", false).option("--json", "Print one JSON summary on stdout (suppresses human progress)", false).action(async (packageArg, opts, command) => {
|
|
21
20
|
const globalOptionsOutcome = parseWithSchema(globalCliCommanderOptionsSchema, command.optsWithGlobals?.() ?? command.opts());
|
|
22
21
|
if (!consumeCliAppError(globalOptionsOutcome)) return;
|
|
23
22
|
const prelude = await prepareMirrorSync(nodeFilesystem, {
|
|
@@ -26,11 +25,13 @@ function createMirrorCommand() {
|
|
|
26
25
|
globals: globalOptionsOutcome.value
|
|
27
26
|
});
|
|
28
27
|
if (!consumeCliAppError(prelude)) return;
|
|
28
|
+
const write = !opts.dryRun;
|
|
29
29
|
const { rootDir, config, packageFilter } = prelude.value;
|
|
30
30
|
const parsed = parseWithSchema(mirrorSyncRunRequestSchema, {
|
|
31
31
|
rootDir,
|
|
32
32
|
config: config.mirror ?? {},
|
|
33
|
-
packageFilter
|
|
33
|
+
packageFilter,
|
|
34
|
+
write
|
|
34
35
|
});
|
|
35
36
|
if (!consumeCliAppError(parsed)) return;
|
|
36
37
|
const json = !!opts.json;
|
|
@@ -40,7 +41,8 @@ function createMirrorCommand() {
|
|
|
40
41
|
const listener = json ? void 0 : progressPresenter;
|
|
41
42
|
if (!json) progressPresenter.configure({
|
|
42
43
|
noColor,
|
|
43
|
-
verbose
|
|
44
|
+
verbose,
|
|
45
|
+
dryRun: !write
|
|
44
46
|
});
|
|
45
47
|
const startTime = performance.now();
|
|
46
48
|
const outcome = await runMirrorSync(nodeFilesystem, {
|
|
@@ -48,10 +50,9 @@ function createMirrorCommand() {
|
|
|
48
50
|
listener
|
|
49
51
|
});
|
|
50
52
|
if (!consumeCliAppError(outcome)) return;
|
|
51
|
-
if (json) logger.out(formatMirrorSyncJsonOutput(outcome.value, (performance.now() - startTime) / 1e3));
|
|
53
|
+
if (json) logger.out(formatMirrorSyncJsonOutput(outcome.value, (performance.now() - startTime) / 1e3, write));
|
|
52
54
|
process.exitCode = exitCodeForMirrorSyncResult(outcome.value);
|
|
53
55
|
});
|
|
54
|
-
return cmd;
|
|
55
56
|
}
|
|
56
57
|
//#endregion
|
|
57
58
|
export { createMirrorCommand };
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { PACKAGE_JSON_EXPORT, VALID_DTS_EXTENSIONS, VALID_JS_EXTENSIONS } from "./constants.mjs";
|
|
2
2
|
import * as nodePath from "node:path";
|
|
3
3
|
//#region src/mirror/domain/exports.ts
|
|
4
|
-
function resolvePackageScopedConfig(configMap, pkgMeta) {
|
|
5
|
-
if (!configMap) return;
|
|
6
|
-
return configMap[pkgMeta.packageName];
|
|
7
|
-
}
|
|
8
4
|
function groupDistFilesByModule(relativeDistFiles) {
|
|
9
5
|
const distModulesByPath = /* @__PURE__ */ new Map();
|
|
10
6
|
for (const relativeDistFile of relativeDistFiles) {
|
|
@@ -110,14 +106,11 @@ function getExportSortGroup(exportPath, pathTransform) {
|
|
|
110
106
|
/**
|
|
111
107
|
* @since 0.3.16-canary.0
|
|
112
108
|
*/
|
|
113
|
-
function createPathTransform(
|
|
114
|
-
|
|
115
|
-
if (!pathConfig) return null;
|
|
116
|
-
const { removePrefix } = pathConfig;
|
|
117
|
-
if (!removePrefix) return null;
|
|
109
|
+
function createPathTransform(strip) {
|
|
110
|
+
if (!strip) return null;
|
|
118
111
|
return (exportPath) => {
|
|
119
|
-
if (!exportPath.startsWith(
|
|
120
|
-
const trimmedExportPath = exportPath.slice(
|
|
112
|
+
if (!exportPath.startsWith(strip)) return exportPath;
|
|
113
|
+
const trimmedExportPath = exportPath.slice(strip.length);
|
|
121
114
|
if (trimmedExportPath && trimmedExportPath !== "." && !trimmedExportPath.startsWith("./")) return `./${trimmedExportPath}`;
|
|
122
115
|
return trimmedExportPath;
|
|
123
116
|
};
|
|
@@ -174,7 +167,7 @@ async function generateCssExports(fileSystemService, distDir, cssConfig) {
|
|
|
174
167
|
*
|
|
175
168
|
* @since 0.3.16-canary.0
|
|
176
169
|
*/
|
|
177
|
-
async function generateExports(fileSystemService, distDir, pathTransform, cssConfig,
|
|
170
|
+
async function generateExports(fileSystemService, distDir, pathTransform, cssConfig, extraExports, options) {
|
|
178
171
|
const relativeDistFiles = await fileSystemService.listRelativeFilesRecursively(distDir);
|
|
179
172
|
if (!relativeDistFiles.length) return {
|
|
180
173
|
exports: { [PACKAGE_JSON_EXPORT]: PACKAGE_JSON_EXPORT },
|
|
@@ -197,23 +190,27 @@ async function generateExports(fileSystemService, distDir, pathTransform, cssCon
|
|
|
197
190
|
let exportPath = originalExportPath;
|
|
198
191
|
if (pathTransform) exportPath = pathTransform(exportPath);
|
|
199
192
|
const exportEntry = {};
|
|
193
|
+
if (options?.source) if (typeof options.source === "string" && exportPath === ".") exportEntry.source = options.source;
|
|
194
|
+
else exportEntry.source = (options.resolveSourcePath ?? ((p) => `./src/${p}.ts`))(distModuleEntry.path);
|
|
200
195
|
const declarationFile = distModuleEntry.files.dts;
|
|
201
|
-
if (declarationFile) exportEntry.types = `./dist/${declarationFile}`;
|
|
202
|
-
if (
|
|
203
|
-
|
|
196
|
+
if (declarationFile && options?.types !== false) exportEntry.types = `./dist/${declarationFile}`;
|
|
197
|
+
if (options?.import !== false) {
|
|
198
|
+
if (distModuleEntry.files.mjs) exportEntry.import = `./dist/${distModuleEntry.files.mjs}`;
|
|
199
|
+
else if (distModuleEntry.files.js) exportEntry.import = `./dist/${distModuleEntry.files.js}`;
|
|
200
|
+
}
|
|
204
201
|
if (distModuleEntry.files.cjs) exportEntry.require = `./dist/${distModuleEntry.files.cjs}`;
|
|
205
202
|
moduleExportsBySpecifier[exportPath] = exportEntry;
|
|
206
203
|
originalPathBySpecifier[exportPath] = originalExportPath;
|
|
207
204
|
}
|
|
208
|
-
let sortedSpecifiers = Object.keys(moduleExportsBySpecifier).
|
|
205
|
+
let sortedSpecifiers = Object.keys(moduleExportsBySpecifier).toSorted((leftSpecifier, rightSpecifier) => compareExportSortKeys(getExportSortKey(leftSpecifier, pathTransform), getExportSortKey(rightSpecifier, pathTransform)));
|
|
209
206
|
const sortedExports = {};
|
|
210
207
|
for (const exportKey of sortedSpecifiers) sortedExports[exportKey] = moduleExportsBySpecifier[exportKey];
|
|
211
208
|
const cssExports = await generateCssExports(fileSystemService, distDir, cssConfig ?? { enabled: true });
|
|
212
209
|
Object.assign(sortedExports, cssExports);
|
|
213
|
-
for (const [specifier, mappedPath] of Object.entries(
|
|
210
|
+
for (const [specifier, mappedPath] of Object.entries(extraExports || {})) if (specifier !== "./package.json") sortedExports[specifier] = mappedPath;
|
|
214
211
|
for (const cssSpecifier of Object.keys(cssExports)) if (!(cssSpecifier in originalPathBySpecifier)) originalPathBySpecifier[cssSpecifier] = cssSpecifier;
|
|
215
|
-
for (const
|
|
216
|
-
sortedSpecifiers = Object.keys(sortedExports).filter((exportKey) => exportKey !== PACKAGE_JSON_EXPORT).
|
|
212
|
+
for (const extraSpecifier of Object.keys(extraExports || {})) if (extraSpecifier !== "./package.json" && !(extraSpecifier in originalPathBySpecifier)) originalPathBySpecifier[extraSpecifier] = extraSpecifier;
|
|
213
|
+
sortedSpecifiers = Object.keys(sortedExports).filter((exportKey) => exportKey !== PACKAGE_JSON_EXPORT).toSorted((leftSpecifier, rightSpecifier) => compareExportSortKeys(getExportSortKey(leftSpecifier, pathTransform), getExportSortKey(rightSpecifier, pathTransform)));
|
|
217
214
|
const finalExports = {};
|
|
218
215
|
for (const exportKey of sortedSpecifiers) finalExports[exportKey] = sortedExports[exportKey];
|
|
219
216
|
finalExports[PACKAGE_JSON_EXPORT] = PACKAGE_JSON_EXPORT;
|
package/dist/mirror/output.mjs
CHANGED
|
@@ -8,12 +8,15 @@ const cliLogger = logger;
|
|
|
8
8
|
var MirrorSyncProgressPresenter = class {
|
|
9
9
|
reporter = new MirrorSyncReporter();
|
|
10
10
|
verbose = false;
|
|
11
|
+
dryRun = false;
|
|
11
12
|
configure(options) {
|
|
12
13
|
this.verbose = options.verbose;
|
|
14
|
+
this.dryRun = options.dryRun;
|
|
13
15
|
this.reporter.configureMirrorColors(options.noColor);
|
|
14
16
|
}
|
|
15
17
|
onBanner() {
|
|
16
18
|
this.reporter.mirrorBanner(cliLogger);
|
|
19
|
+
if (this.dryRun) this.reporter.mirrorDryRunNotice(cliLogger);
|
|
17
20
|
}
|
|
18
21
|
onProcessingMode(mode) {
|
|
19
22
|
this.reporter.mirrorProcessingMode(cliLogger, mode);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { DIST_DIR } from "./domain/constants.mjs";
|
|
2
|
+
import { writePackageJsonExportsAtomic } from "./write-exports.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
//#region src/mirror/supplement-exports.ts
|
|
5
|
+
const DTS_EXTENSIONS = [
|
|
6
|
+
".d.mts",
|
|
7
|
+
".d.ts",
|
|
8
|
+
".d.cts"
|
|
9
|
+
];
|
|
10
|
+
const JS_EXTENSIONS = [".mjs", ".js"];
|
|
11
|
+
/**
|
|
12
|
+
* Infer the dist module path (e.g. `"index"`, `"components/button"`) from an existing
|
|
13
|
+
* conditional export entry. Prefers `import` / `require` values because their extensions
|
|
14
|
+
* are simpler than `.d.mts` etc.
|
|
15
|
+
*/
|
|
16
|
+
function inferModulePath(specifier, entry) {
|
|
17
|
+
for (const key of ["import", "require"]) {
|
|
18
|
+
const value = entry[key];
|
|
19
|
+
if (typeof value === "string" && value.startsWith("./dist/")) {
|
|
20
|
+
const relative = value.slice(7);
|
|
21
|
+
for (const ext of JS_EXTENSIONS) if (relative.endsWith(ext)) return relative.slice(0, -ext.length);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const typesValue = entry.types;
|
|
25
|
+
if (typeof typesValue === "string" && typesValue.startsWith("./dist/")) {
|
|
26
|
+
const relative = typesValue.slice(7);
|
|
27
|
+
for (const ext of DTS_EXTENSIONS) if (relative.endsWith(ext)) return relative.slice(0, -ext.length);
|
|
28
|
+
}
|
|
29
|
+
if (specifier === ".") return "index";
|
|
30
|
+
if (specifier.startsWith("./")) return specifier.slice(2);
|
|
31
|
+
return specifier;
|
|
32
|
+
}
|
|
33
|
+
function findDtsSpecifier(fs, distDir, modulePath) {
|
|
34
|
+
for (const ext of DTS_EXTENSIONS) if (fs.existsSync(path.join(distDir, `${modulePath}${ext}`))) return `./dist/${modulePath}${ext}`;
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function findImportSpecifier(fs, distDir, modulePath) {
|
|
38
|
+
for (const ext of JS_EXTENSIONS) if (fs.existsSync(path.join(distDir, `${modulePath}${ext}`))) return `./dist/${modulePath}${ext}`;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Rebuild an export entry in canonical key order, adding any missing conditions.
|
|
43
|
+
* Key order: source → types → import → require → (remaining original keys).
|
|
44
|
+
*/
|
|
45
|
+
function buildSupplementedEntry(specifier, existing, modulePath, distDir, fs, options) {
|
|
46
|
+
const result = {};
|
|
47
|
+
const knownKeys = new Set([
|
|
48
|
+
"source",
|
|
49
|
+
"types",
|
|
50
|
+
"import",
|
|
51
|
+
"require"
|
|
52
|
+
]);
|
|
53
|
+
if ("source" in existing) result.source = existing.source;
|
|
54
|
+
else if (options.source) if (typeof options.source === "string" && specifier === ".") result.source = options.source;
|
|
55
|
+
else result.source = options.resolveSourcePath(modulePath);
|
|
56
|
+
if ("types" in existing) result.types = existing.types;
|
|
57
|
+
else if (options.types) {
|
|
58
|
+
const found = findDtsSpecifier(fs, distDir, modulePath);
|
|
59
|
+
if (found) result.types = found;
|
|
60
|
+
}
|
|
61
|
+
if ("import" in existing) result.import = existing.import;
|
|
62
|
+
else if (options.import) {
|
|
63
|
+
const found = findImportSpecifier(fs, distDir, modulePath);
|
|
64
|
+
if (found) result.import = found;
|
|
65
|
+
}
|
|
66
|
+
if ("require" in existing) result.require = existing.require;
|
|
67
|
+
for (const [key, value] of Object.entries(existing)) if (!knownKeys.has(key) && !(key in result)) result[key] = value;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @since 0.3.16-canary.0
|
|
72
|
+
*/
|
|
73
|
+
async function supplementExportsInPackageJson(fs, packageJsonPath, packageDir, options, write = true) {
|
|
74
|
+
const raw = await fs.readFile(packageJsonPath, "utf8");
|
|
75
|
+
const existingExports = JSON.parse(raw).exports;
|
|
76
|
+
if (!existingExports || typeof existingExports !== "object" || Array.isArray(existingExports)) return { supplementedSpecifiers: [] };
|
|
77
|
+
const distDir = path.join(packageDir, DIST_DIR);
|
|
78
|
+
const supplementedSpecifiers = [];
|
|
79
|
+
const supplementedExports = {};
|
|
80
|
+
const originalPathBySpecifier = {};
|
|
81
|
+
for (const [specifier, entry] of Object.entries(existingExports)) {
|
|
82
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
83
|
+
supplementedExports[specifier] = entry;
|
|
84
|
+
originalPathBySpecifier[specifier] = specifier;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const entryRecord = entry;
|
|
88
|
+
const supplemented = buildSupplementedEntry(specifier, entryRecord, inferModulePath(specifier, entryRecord), distDir, fs, options);
|
|
89
|
+
if (JSON.stringify(supplemented) !== JSON.stringify(entryRecord)) supplementedSpecifiers.push(specifier);
|
|
90
|
+
supplementedExports[specifier] = supplemented;
|
|
91
|
+
originalPathBySpecifier[specifier] = specifier;
|
|
92
|
+
}
|
|
93
|
+
await writePackageJsonExportsAtomic(fs, packageJsonPath, {
|
|
94
|
+
generatedExports: supplementedExports,
|
|
95
|
+
managedExportSpecifiers: Object.keys(supplementedExports),
|
|
96
|
+
originalPathBySpecifier
|
|
97
|
+
}, write);
|
|
98
|
+
return { supplementedSpecifiers };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build a `resolveSourcePath` closure that checks the filesystem for `.tsx` before
|
|
102
|
+
* falling back to `.ts`. Mirrors the logic used in normal (non-custom) mode.
|
|
103
|
+
*
|
|
104
|
+
* @since 0.3.16-canary.0
|
|
105
|
+
*/
|
|
106
|
+
function buildSourcePathResolver(fs, packageDir) {
|
|
107
|
+
const srcDir = path.join(packageDir, "src");
|
|
108
|
+
return (modulePath) => {
|
|
109
|
+
const tsxPath = path.join(srcDir, `${modulePath}.tsx`);
|
|
110
|
+
return fs.existsSync(tsxPath) ? `./src/${modulePath}.tsx` : `./src/${modulePath}.ts`;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { buildSourcePathResolver, supplementExportsInPackageJson };
|
|
@@ -14,7 +14,7 @@ const ANSI = {
|
|
|
14
14
|
brightCyan: "\x1B[96m"
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
|
-
* Console implementation: ANSI styling and layout for mirror
|
|
17
|
+
* Console implementation: ANSI styling and layout for the mirror command.
|
|
18
18
|
*
|
|
19
19
|
* @since 0.3.16-canary.0
|
|
20
20
|
*/
|
|
@@ -27,6 +27,9 @@ var MirrorSyncReporter = class {
|
|
|
27
27
|
logger.out(`\n${this.paint("📦 Mirror — package exports", ANSI.bold + ANSI.cyan)}`);
|
|
28
28
|
logger.out(`${this.paint("═".repeat(60), ANSI.dim)}\n`);
|
|
29
29
|
}
|
|
30
|
+
mirrorDryRunNotice(logger) {
|
|
31
|
+
logger.out(`${this.paint("Dry run — no files will be written.", ANSI.yellow)}\n`);
|
|
32
|
+
}
|
|
30
33
|
mirrorProcessingMode(logger, mode) {
|
|
31
34
|
if (mode.kind === "single") {
|
|
32
35
|
logger.out(`${this.paint("Processing single package...", ANSI.dim)}\n`);
|
|
@@ -65,7 +68,7 @@ var MirrorSyncReporter = class {
|
|
|
65
68
|
const breakdown = [];
|
|
66
69
|
if (generatedDistAssetCounts.jsCount > 0) breakdown.push(this.paint(`${generatedDistAssetCounts.jsCount} modules`, ANSI.green));
|
|
67
70
|
if (generatedDistAssetCounts.cssCount > 0) breakdown.push(this.paint(`${generatedDistAssetCounts.cssCount} CSS`, ANSI.magenta));
|
|
68
|
-
if (pkgStats.
|
|
71
|
+
if (pkgStats.extraExports > 0) breakdown.push(this.paint(`${pkgStats.extraExports} custom`, ANSI.yellow));
|
|
69
72
|
const totalExportsText = this.paint(`${pkgStats.totalExports} exports`, ANSI.brightCyan);
|
|
70
73
|
if (breakdown.length === 0) logger.out(` ${this.paint("└─", ANSI.dim)} ${totalExportsText}`);
|
|
71
74
|
else logger.out(` ${this.paint("└─", ANSI.dim)} ${breakdown.join(" + ")} = ${totalExportsText}`);
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { messageFrom } from "../core/errors.mjs";
|
|
2
|
+
import { createMirrorDistFilesystem } from "./dist-filesystem-impl.mjs";
|
|
2
3
|
import { DIST_DIR, PACKAGE_JSON } from "./domain/constants.mjs";
|
|
3
4
|
import { createPathTransform, generateExports } from "./domain/exports.mjs";
|
|
4
5
|
import { resolvePackageDisplayName } from "./domain/package-display-name.mjs";
|
|
5
6
|
import { writePackageJsonExportsAtomic } from "./write-exports.mjs";
|
|
6
|
-
import {
|
|
7
|
+
import { buildSourcePathResolver, supplementExportsInPackageJson } from "./supplement-exports.mjs";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
//#region src/mirror/sync-workspace-package.ts
|
|
9
10
|
/**
|
|
10
11
|
* @since 0.3.16-canary.0
|
|
11
12
|
*/
|
|
12
|
-
async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, config) {
|
|
13
|
+
async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, config, write = true) {
|
|
13
14
|
const pathJoin = path.join;
|
|
14
15
|
const pathResolve = path.resolve;
|
|
15
16
|
const pathBasename = path.basename;
|
|
@@ -23,7 +24,7 @@ async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, confi
|
|
|
23
24
|
path: packageDir,
|
|
24
25
|
jsModules: 0,
|
|
25
26
|
cssExports: 0,
|
|
26
|
-
|
|
27
|
+
extraExports: 0,
|
|
27
28
|
totalExports: 0,
|
|
28
29
|
hasTransform: false,
|
|
29
30
|
cssConfigStatus: "",
|
|
@@ -49,8 +50,8 @@ async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, confi
|
|
|
49
50
|
pkgStats.name = folderBasename;
|
|
50
51
|
packageJsonParseError = caughtError;
|
|
51
52
|
}
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
53
|
+
const pkgConfig = config[pkgStats.name];
|
|
54
|
+
if (pkgConfig === false) {
|
|
54
55
|
pkgStats.skipped = true;
|
|
55
56
|
pkgStats.skipReason = "configured to skip";
|
|
56
57
|
return pkgStats;
|
|
@@ -70,34 +71,39 @@ async function syncExportsForWorkspacePackage(fs, rootDir, packagePathStr, confi
|
|
|
70
71
|
return pkgStats;
|
|
71
72
|
}
|
|
72
73
|
try {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
74
|
+
const resolveSourcePath = buildSourcePathResolver(fs, packageDir);
|
|
75
|
+
const exportOptions = {
|
|
76
|
+
source: pkgConfig?.source ?? true,
|
|
77
|
+
types: pkgConfig?.types ?? true,
|
|
78
|
+
import: pkgConfig?.import ?? true,
|
|
79
|
+
resolveSourcePath
|
|
80
|
+
};
|
|
81
|
+
if (pkgConfig?.preserve) {
|
|
82
|
+
const { supplementedSpecifiers } = await supplementExportsInPackageJson(fs, packageJsonPath, packageDir, exportOptions, write);
|
|
83
|
+
pkgStats.totalExports = supplementedSpecifiers.length;
|
|
84
|
+
} else {
|
|
85
|
+
const pathTransform = createPathTransform(pkgConfig?.strip);
|
|
86
|
+
pkgStats.hasTransform = !!pathTransform;
|
|
87
|
+
const cssConfig = pkgConfig?.css;
|
|
88
|
+
if (cssConfig === false) pkgStats.cssConfigStatus = "disabled";
|
|
89
|
+
else if (cssConfig !== void 0) pkgStats.cssConfigStatus = "configured";
|
|
90
|
+
const extraExports = pkgConfig?.exports ?? {};
|
|
91
|
+
const generatedExports = await generateExports(distFilesystem, distDir, pathTransform, cssConfig, extraExports, exportOptions);
|
|
92
|
+
const { prunedKeys } = await writePackageJsonExportsAtomic(fs, packageJsonPath, {
|
|
93
|
+
generatedExports: generatedExports.exports,
|
|
94
|
+
managedExportSpecifiers: Object.keys(generatedExports.exports),
|
|
95
|
+
originalPathBySpecifier: generatedExports.originalPathBySpecifier
|
|
96
|
+
}, write);
|
|
97
|
+
pkgStats.jsModules = generatedExports.jsCount;
|
|
98
|
+
pkgStats.cssExports = generatedExports.cssCount;
|
|
99
|
+
pkgStats.extraExports = Object.keys(extraExports).length;
|
|
100
|
+
pkgStats.totalExports = Object.keys(generatedExports.exports).length;
|
|
101
|
+
pkgStats.prunedExportKeys = prunedKeys;
|
|
102
|
+
}
|
|
90
103
|
} catch (caughtError) {
|
|
91
104
|
pkgStats.error = messageFrom(caughtError);
|
|
92
105
|
}
|
|
93
106
|
return pkgStats;
|
|
94
107
|
}
|
|
95
|
-
function resolvePackageScopedConfig(configMap, packageMeta) {
|
|
96
|
-
if (!configMap) return;
|
|
97
|
-
return configMap[packageMeta.packageName];
|
|
98
|
-
}
|
|
99
|
-
function isPackageSkipped(skipPackagesList, packageMeta) {
|
|
100
|
-
return !!skipPackagesList?.includes(packageMeta.packageName);
|
|
101
|
-
}
|
|
102
108
|
//#endregion
|
|
103
109
|
export { syncExportsForWorkspacePackage };
|
package/dist/mirror/sync.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import path from "node:path";
|
|
|
12
12
|
async function runMirrorSync(fs, input) {
|
|
13
13
|
const config = input.config ?? {};
|
|
14
14
|
const { listener } = input;
|
|
15
|
+
const write = input.write ?? true;
|
|
15
16
|
listener?.onBanner();
|
|
16
17
|
const startTime = performance.now();
|
|
17
18
|
try {
|
|
@@ -47,7 +48,7 @@ async function runMirrorSync(fs, input) {
|
|
|
47
48
|
}
|
|
48
49
|
let ordinal = 1;
|
|
49
50
|
for (const pkgPath of targetPackages) {
|
|
50
|
-
const pkgStats = await syncExportsForWorkspacePackage(fs, input.rootDir, pkgPath, config);
|
|
51
|
+
const pkgStats = await syncExportsForWorkspacePackage(fs, input.rootDir, pkgPath, config, write);
|
|
51
52
|
stats.packageDetails.push(pkgStats);
|
|
52
53
|
listener?.onPackageComplete(pkgStats, ordinal, targetPackages.length);
|
|
53
54
|
ordinal++;
|
|
@@ -8,7 +8,7 @@ import { MirrorError, MirrorErrorCode } from "./domain/errors.mjs";
|
|
|
8
8
|
*
|
|
9
9
|
* @since 0.3.16-canary.0
|
|
10
10
|
*/
|
|
11
|
-
async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeInput) {
|
|
11
|
+
async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeInput, write = true) {
|
|
12
12
|
function containsDistTarget(value) {
|
|
13
13
|
if (typeof value === "string") return value.startsWith("./dist/");
|
|
14
14
|
if (Array.isArray(value)) return value.some((entryValue) => containsDistTarget(entryValue));
|
|
@@ -76,7 +76,8 @@ async function writePackageJsonExportsAtomic(fs, packageJsonPath, mergeInput) {
|
|
|
76
76
|
} else packageJson.files = ["dist"];
|
|
77
77
|
const sortedExportMap = {};
|
|
78
78
|
const hasCatchAllWildcard = "./*" in mergedExportMap;
|
|
79
|
-
for (const exportSpecifier of Object.keys(mergedExportMap).
|
|
79
|
+
for (const exportSpecifier of Object.keys(mergedExportMap).toSorted((leftSpecifier, rightSpecifier) => compareExportSpecifiers(leftSpecifier, rightSpecifier, originalPathBySpecifier, hasCatchAllWildcard))) sortedExportMap[exportSpecifier] = mergedExportMap[exportSpecifier];
|
|
80
|
+
if (!write) return { prunedKeys };
|
|
80
81
|
packageJson.exports = sortedExportMap;
|
|
81
82
|
const serialized = JSON.stringify(packageJson, null, 2) + "\n";
|
|
82
83
|
const tmpPath = `${packageJsonPath}.tmp`;
|
package/dist/tag/command.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
2
1
|
import { logger } from "../core/logger.mjs";
|
|
2
|
+
import { readOptionalPositionalArg } from "../core/cli/positional.mjs";
|
|
3
3
|
import { consumeCliAppError } from "../core/cli/result-handle.mjs";
|
|
4
4
|
import { nodeFilesystem } from "../core/filesystem/node.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { prepareTagSync } from "./prepare.mjs";
|
|
7
|
-
import { runTagSync } from "./sync.mjs";
|
|
8
|
-
import { tagSyncRunRequestSchema } from "./cli-schema.mjs";
|
|
5
|
+
import { parseWithSchema } from "../core/schema-parse.mjs";
|
|
9
6
|
import { exitCodeForTagSyncResult } from "./cli-result.mjs";
|
|
7
|
+
import { tagSyncRunRequestSchema } from "./cli-schema.mjs";
|
|
10
8
|
import { TagSyncProgressPresenter, presentTagSyncResult } from "./output.mjs";
|
|
9
|
+
import { prepareTagSync } from "./prepare.mjs";
|
|
10
|
+
import { runTagSync } from "./sync.mjs";
|
|
11
11
|
import process from "node:process";
|
|
12
12
|
import { Command } from "commander";
|
|
13
13
|
//#region src/tag/command.ts
|
|
@@ -15,7 +15,7 @@ import { Command } from "commander";
|
|
|
15
15
|
* @since 0.3.16-canary.0
|
|
16
16
|
*/
|
|
17
17
|
function createTagCommand() {
|
|
18
|
-
return new Command("tag").description("Add @since <version> JSDoc tags to exported declarations").
|
|
18
|
+
return new Command("tag").description("Add @since <version> JSDoc tags to exported declarations").argument("[target]", "Directory or file to tag (default: auto-discover workspace packages)").option("--dry-run", "Show summary without writing files", false).option("--json", "Print one JSON summary on stdout (suppresses human progress)", false).action(async (target, opts) => {
|
|
19
19
|
const prelude = await prepareTagSync(nodeFilesystem, {
|
|
20
20
|
currentWorkingDirectory: process.cwd(),
|
|
21
21
|
rawTarget: readOptionalPositionalArg(target)
|
package/dist/tag/output.mjs
CHANGED
package/dist/tag/sync.mjs
CHANGED
|
@@ -20,7 +20,7 @@ async function runTagSync(fs, input) {
|
|
|
20
20
|
const modifiedFiles = allFileResults.filter((entry) => entry.changed).map((entry) => entry.filePath);
|
|
21
21
|
const hookError = input.write && modifiedFiles.length > 0 ? await runTagOnAfterWriteHook(tagConfig?.onAfterWrite, modifiedFiles) : null;
|
|
22
22
|
const versionsSet = extractDistinctVersions(targetExecutionResults);
|
|
23
|
-
const distinctVersions = [...versionsSet].
|
|
23
|
+
const distinctVersions = [...versionsSet].toSorted((left, right) => left.localeCompare(right));
|
|
24
24
|
return ok({
|
|
25
25
|
mode: input.write ? "applied" : "dry-run",
|
|
26
26
|
selectedTargets,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { walkTsxFiles } from "../core/workspace/typescript-walk.mjs";
|
|
2
|
-
import { resolveNearestPackageVersion } from "./version-resolver.mjs";
|
|
3
2
|
import { TagSinceWriter } from "./since-writer.mjs";
|
|
3
|
+
import { resolveNearestPackageVersion } from "./version-resolver.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
//#region src/tag/target-runner.ts
|
|
6
6
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codefast/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-canary.4",
|
|
4
4
|
"description": "Developer CLI for the Codefast monorepo (arrange, mirror, tag)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"commander": "^
|
|
54
|
+
"commander": "^15.0.0",
|
|
55
55
|
"jiti": "^2.7.0",
|
|
56
56
|
"picomatch": "^4.0.4",
|
|
57
57
|
"typescript": "^6.0.3",
|
|
@@ -59,17 +59,17 @@
|
|
|
59
59
|
"zod": "^4.4.3"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^25.
|
|
62
|
+
"@types/node": "^25.9.2",
|
|
63
63
|
"@types/picomatch": "^4.0.3",
|
|
64
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
65
|
-
"@vitest/coverage-v8": "^4.1.
|
|
66
|
-
"tsdown": "^0.22.
|
|
67
|
-
"vite": "^8.0.
|
|
68
|
-
"vitest": "^4.1.
|
|
69
|
-
"@codefast/typescript-config": "0.
|
|
64
|
+
"@typescript/native-preview": "7.0.0-dev.20260604.1",
|
|
65
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
66
|
+
"tsdown": "^0.22.2",
|
|
67
|
+
"vite": "^8.0.16",
|
|
68
|
+
"vitest": "^4.1.8",
|
|
69
|
+
"@codefast/typescript-config": "0.4.0-canary.4"
|
|
70
70
|
},
|
|
71
71
|
"engines": {
|
|
72
|
-
"node": ">=
|
|
72
|
+
"node": ">=24.0.0"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"build": "tsdown",
|