@codefast/cli 0.9.0 → 0.10.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.
- package/CHANGELOG.md +28 -0
- package/README.md +329 -149
- package/dist/arrange/analyze.d.ts +10 -0
- package/dist/arrange/cli-schema.d.ts +50 -0
- package/dist/arrange/command.d.ts +7 -0
- package/dist/arrange/domain/analyze-service.d.ts +18 -0
- package/dist/arrange/domain/ast/ast-node.d.ts +394 -0
- package/dist/arrange/domain/ast/collectors-cn.d.ts +26 -0
- package/dist/arrange/domain/ast/collectors-jsx.d.ts +8 -0
- package/dist/arrange/domain/ast/collectors-tv.d.ts +34 -0
- package/dist/arrange/domain/ast/helpers.d.ts +36 -0
- package/dist/arrange/domain/ast/helpers.js +1 -0
- package/dist/arrange/domain/ast/simplify-targets.d.ts +22 -0
- package/dist/arrange/domain/ast/targets.d.ts +20 -0
- package/dist/arrange/domain/constants.d.ts +111 -0
- package/dist/arrange/domain/grouping-service.d.ts +100 -0
- package/dist/arrange/domain/grouping.d.ts +21 -0
- package/dist/arrange/domain/imports.d.ts +14 -0
- package/dist/arrange/domain/source-text-formatters.d.ts +33 -0
- package/dist/arrange/domain/tailwind-token.d.ts +24 -0
- package/dist/arrange/domain/token-classifier.d.ts +47 -0
- package/dist/arrange/domain/types.d.ts +208 -0
- package/dist/arrange/output.d.ts +26 -0
- package/dist/arrange/process-file.d.ts +11 -0
- package/dist/arrange/resolve-target.d.ts +10 -0
- package/dist/arrange/resolve-target.js +3 -16
- package/dist/arrange/scan-target.d.ts +7 -0
- package/dist/arrange/simplify-process-file.d.ts +11 -0
- package/dist/arrange/simplify-sync.d.ts +13 -0
- package/dist/arrange/source-parse.d.ts +7 -0
- package/dist/arrange/suggest.d.ts +8 -0
- package/dist/arrange/sync.d.ts +11 -0
- package/dist/arrange/typescript-ast-translator.d.ts +31 -0
- package/dist/arrange/workspace.d.ts +13 -0
- package/dist/arrange/workspace.js +2 -2
- package/dist/audit/cli-schema.d.ts +93 -0
- package/dist/audit/cli-schema.js +3 -3
- package/dist/audit/command.d.ts +8 -0
- package/dist/audit/command.js +12 -12
- package/dist/audit/domain/audit-file.d.ts +7 -0
- package/dist/audit/domain/comment-content.d.ts +26 -0
- package/dist/audit/domain/comment-dividers.d.ts +62 -0
- package/dist/audit/domain/display-names.d.ts +11 -0
- package/dist/audit/domain/import-policy.d.ts +34 -0
- package/dist/audit/domain/import-policy.js +147 -0
- package/dist/audit/domain/link-references.d.ts +40 -0
- package/dist/audit/domain/mappings.d.ts +45 -0
- package/dist/audit/domain/markdown-links.d.ts +44 -0
- package/dist/audit/domain/since-versions.d.ts +26 -0
- package/dist/audit/domain/tokenize.d.ts +14 -0
- package/dist/audit/domain/tsdoc-syntax.d.ts +20 -0
- package/dist/audit/domain/types.d.ts +171 -0
- package/dist/audit/output.d.ts +91 -0
- package/dist/audit/output.js +11 -11
- package/dist/audit/prepare.d.ts +70 -0
- package/dist/audit/prepare.js +11 -11
- package/dist/audit/run-comments.d.ts +17 -0
- package/dist/audit/run-display-names.d.ts +14 -0
- package/dist/audit/run-imports.d.ts +14 -0
- package/dist/audit/{run-react.js → run-imports.js} +15 -5
- package/dist/audit/run-links.d.ts +14 -0
- package/dist/audit/run.d.ts +14 -0
- package/dist/bin.d.ts +2 -0
- package/dist/cli.d.ts +6 -0
- package/dist/core/cli/format-error.d.ts +7 -0
- package/dist/core/cli/global-options.d.ts +15 -0
- package/dist/core/cli/positional.d.ts +6 -0
- package/dist/core/cli/result-handle.d.ts +19 -0
- package/dist/core/config/define-config.d.ts +7 -0
- package/dist/core/config/define-config.js +8 -0
- package/dist/core/config/loader.d.ts +18 -0
- package/dist/core/config/loader.js +2 -7
- package/dist/core/config/schema.d.ts +99 -0
- package/dist/core/config/schema.js +7 -85
- package/dist/core/config/warnings.d.ts +6 -0
- package/dist/core/config.d.ts +12 -0
- package/dist/core/errors.d.ts +25 -0
- package/dist/core/exit-codes.d.ts +18 -0
- package/dist/core/filesystem/node.d.ts +7 -0
- package/dist/core/filesystem/node.js +1 -0
- package/dist/core/filesystem/port.d.ts +44 -0
- package/dist/core/glob.d.ts +19 -0
- package/dist/core/logger.d.ts +9 -0
- package/dist/core/result.d.ts +30 -0
- package/dist/core/schema-parse.d.ts +9 -0
- package/dist/core/source-text-edit.d.ts +33 -0
- package/dist/core/verbose-diagnostics.d.ts +6 -0
- package/dist/core/workspace/ancestor-directories.d.ts +12 -0
- package/dist/core/workspace/ancestor-directories.js +30 -0
- package/dist/core/workspace/markdown-walk.d.ts +7 -0
- package/dist/core/workspace/markdown-walk.js +2 -20
- package/dist/core/workspace/package-version.d.ts +9 -0
- package/dist/core/workspace/package-version.js +8 -12
- package/dist/core/workspace/resolver.d.ts +39 -0
- package/dist/core/workspace/resolver.js +58 -75
- package/dist/core/workspace/skip-directories.d.ts +6 -0
- package/dist/core/workspace/source-walk.d.ts +16 -0
- package/dist/core/workspace/source-walk.js +2 -19
- package/dist/core/workspace/typescript-walk.d.ts +7 -0
- package/dist/core/workspace/typescript-walk.js +2 -23
- package/dist/core/workspace/walk-files.d.ts +7 -0
- package/dist/core/workspace/walk-files.js +27 -0
- package/dist/core/workspace/well-known-files.d.ts +18 -0
- package/dist/core/workspace/well-known-files.js +18 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/mirror/cli-result.d.ts +13 -0
- package/dist/mirror/cli-schema.d.ts +8 -0
- package/dist/mirror/command.d.ts +7 -0
- package/dist/mirror/dist-filesystem-impl.d.ts +8 -0
- package/dist/mirror/domain/constants.d.ts +18 -0
- package/dist/mirror/domain/constants.js +0 -12
- package/dist/mirror/domain/dirent-guard.d.ts +10 -0
- package/dist/mirror/domain/dist-filesystem.d.ts +9 -0
- package/dist/mirror/domain/errors.d.ts +24 -0
- package/dist/mirror/domain/exports.d.ts +36 -0
- package/dist/mirror/domain/package-display-name.d.ts +8 -0
- package/dist/mirror/domain/path-normalizer.d.ts +6 -0
- package/dist/mirror/domain/types.d.ts +131 -0
- package/dist/mirror/output.d.ts +23 -0
- package/dist/mirror/package-path.d.ts +19 -0
- package/dist/mirror/prepare.d.ts +15 -0
- package/dist/mirror/prepare.js +2 -2
- package/dist/mirror/supplement-exports.d.ts +27 -0
- package/dist/mirror/supplement-exports.js +2 -2
- package/dist/mirror/sync-reporter.d.ts +60 -0
- package/dist/mirror/sync-reporter.js +4 -0
- package/dist/mirror/sync-types.d.ts +43 -0
- package/dist/mirror/sync-workspace-package.d.ts +9 -0
- package/dist/mirror/sync-workspace-package.js +3 -3
- package/dist/mirror/sync.d.ts +12 -0
- package/dist/mirror/sync.js +5 -3
- package/dist/mirror/write-exports.d.ts +15 -0
- package/dist/pack-slim/cli-result.d.ts +13 -0
- package/dist/pack-slim/cli-schema.d.ts +17 -0
- package/dist/pack-slim/command.d.ts +7 -0
- package/dist/pack-slim/command.js +2 -2
- package/dist/pack-slim/domain/transform.d.ts +69 -0
- package/dist/pack-slim/domain/types.d.ts +46 -0
- package/dist/pack-slim/output.d.ts +15 -0
- package/dist/pack-slim/sync.d.ts +23 -0
- package/dist/pack-slim/sync.js +4 -4
- package/dist/pack-slim/working-tree.d.ts +20 -0
- package/dist/tag/cli-result.d.ts +7 -0
- package/dist/tag/cli-schema.d.ts +8 -0
- package/dist/tag/command.d.ts +7 -0
- package/dist/tag/domain/types.d.ts +111 -0
- package/dist/tag/output.d.ts +17 -0
- package/dist/tag/prepare.d.ts +13 -0
- package/dist/tag/prepare.js +2 -2
- package/dist/tag/resolve-target-path.d.ts +10 -0
- package/dist/tag/since-writer.d.ts +32 -0
- package/dist/tag/sync.d.ts +42 -0
- package/dist/tag/target-candidates.d.ts +8 -0
- package/dist/tag/target-candidates.js +1 -1
- package/dist/tag/target-runner.d.ts +8 -0
- package/dist/tag/version-resolver.d.ts +7 -0
- package/package.json +12 -1
- package/dist/audit/domain/react-imports.js +0 -91
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Pure transforms that slim a package's manifest and dist for publish. */
|
|
2
|
+
/**
|
|
3
|
+
* What slimming one manifest removed.
|
|
4
|
+
*/
|
|
5
|
+
interface ManifestSlimReport {
|
|
6
|
+
readonly filesSrcRemoved: boolean;
|
|
7
|
+
readonly exportsSourceRemoved: number;
|
|
8
|
+
readonly importsSourceRemoved: number;
|
|
9
|
+
readonly importsUnshippedRemoved: number;
|
|
10
|
+
readonly scriptsRemoved: number;
|
|
11
|
+
readonly devDependenciesRemoved: number;
|
|
12
|
+
readonly changed: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The slimmed manifest paired with the report of what it dropped.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.8.1
|
|
18
|
+
*/
|
|
19
|
+
export interface SlimManifestResult {
|
|
20
|
+
readonly manifest: Record<string, unknown>;
|
|
21
|
+
readonly report: ManifestSlimReport;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The result of stripping the `sourceMappingURL` directive from an emitted file's text.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.8.1
|
|
27
|
+
*/
|
|
28
|
+
export interface StripCommentResult {
|
|
29
|
+
readonly text: string;
|
|
30
|
+
readonly stripped: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether a dist entry is a source-map sidecar (`*.map`).
|
|
34
|
+
*
|
|
35
|
+
* @since 0.8.1
|
|
36
|
+
*/
|
|
37
|
+
export declare function isSourceMapFile(fileName: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Whether a dist entry is an emitted file that may carry a `sourceMappingURL` directive.
|
|
40
|
+
*
|
|
41
|
+
* @since 0.8.1
|
|
42
|
+
*/
|
|
43
|
+
export declare function isMapAnnotatedFile(fileName: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Whether a script name is an install or publish lifecycle hook, with or without its `pre`/`post` prefix.
|
|
46
|
+
*
|
|
47
|
+
* @remarks Publish hooks stay because `pnpm publish` runs them right after pack-slim; install hooks stay because a
|
|
48
|
+
* consumer's package manager runs them.
|
|
49
|
+
*
|
|
50
|
+
* @since 0.9.0
|
|
51
|
+
*/
|
|
52
|
+
export declare function isLifecycleScript(name: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Produces a publish manifest carrying only what a consumer's `tsc` and Node read.
|
|
55
|
+
*
|
|
56
|
+
* @remarks Operates on a structural clone, so the caller's manifest is left intact. A consumer never enables `source`
|
|
57
|
+
* and resolves `#/` through `types`/`default` to `dist`, so dropping the source lane, the `imports` left pointing
|
|
58
|
+
* outside `files`, the scripts that are not lifecycle hooks, and `devDependencies` leaves the published surface whole.
|
|
59
|
+
*
|
|
60
|
+
* @since 0.8.1
|
|
61
|
+
*/
|
|
62
|
+
export declare function slimPublishManifest(manifest: Record<string, unknown>): SlimManifestResult;
|
|
63
|
+
/**
|
|
64
|
+
* Strips every `sourceMappingURL` directive line from an emitted file's text.
|
|
65
|
+
*
|
|
66
|
+
* @since 0.8.1
|
|
67
|
+
*/
|
|
68
|
+
export declare function stripSourceMappingComment(text: string): StripCommentResult;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Stats and progress types for a pack-slim run. */
|
|
2
|
+
/**
|
|
3
|
+
* The outcome of slimming one workspace package.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.8.1
|
|
6
|
+
*/
|
|
7
|
+
export interface PackSlimPackageStats {
|
|
8
|
+
name: string;
|
|
9
|
+
path: string;
|
|
10
|
+
skipped: boolean;
|
|
11
|
+
skipReason: string;
|
|
12
|
+
error: string | null;
|
|
13
|
+
filesSrcRemoved: boolean;
|
|
14
|
+
exportsSourceRemoved: number;
|
|
15
|
+
importsSourceRemoved: number;
|
|
16
|
+
importsUnshippedRemoved: number;
|
|
17
|
+
scriptsRemoved: number;
|
|
18
|
+
devDependenciesRemoved: number;
|
|
19
|
+
mapFilesDeleted: number;
|
|
20
|
+
sourceCommentsStripped: number;
|
|
21
|
+
changed: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The aggregate stats of a pack-slim run across every targeted package.
|
|
25
|
+
*
|
|
26
|
+
* @since 0.8.1
|
|
27
|
+
*/
|
|
28
|
+
export interface PackSlimRunStats {
|
|
29
|
+
packagesFound: number;
|
|
30
|
+
packagesProcessed: number;
|
|
31
|
+
packagesSkipped: number;
|
|
32
|
+
packagesErrored: number;
|
|
33
|
+
packagesChanged: number;
|
|
34
|
+
totalMapFilesDeleted: number;
|
|
35
|
+
packageDetails: Array<PackSlimPackageStats>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The progress events a pack-slim run emits as it works through the packages.
|
|
39
|
+
*
|
|
40
|
+
* @since 0.8.1
|
|
41
|
+
*/
|
|
42
|
+
export interface PackSlimProgressListener {
|
|
43
|
+
onBanner?(): void;
|
|
44
|
+
onPackageComplete?(stats: PackSlimPackageStats, ordinal: number, total: number): void;
|
|
45
|
+
onComplete?(stats: PackSlimRunStats, elapsedSeconds: number): void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PackSlimPackageStats, PackSlimProgressListener, PackSlimRunStats } from "#/pack-slim/domain/types";
|
|
2
|
+
/**
|
|
3
|
+
* A progress listener that renders pack-slim run events as human-readable CLI lines.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.8.1
|
|
6
|
+
*/
|
|
7
|
+
export declare class PackSlimProgressPresenter implements PackSlimProgressListener {
|
|
8
|
+
private dryRun;
|
|
9
|
+
configure(options: {
|
|
10
|
+
readonly dryRun: boolean;
|
|
11
|
+
}): void;
|
|
12
|
+
onBanner(): void;
|
|
13
|
+
onPackageComplete(stats: PackSlimPackageStats, ordinal: number, total: number): void;
|
|
14
|
+
onComplete(stats: PackSlimRunStats, elapsedSeconds: number): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AppError } from "#/core/errors";
|
|
2
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
3
|
+
import type { Result } from "#/core/result";
|
|
4
|
+
import type { PackSlimRunRequest } from "#/pack-slim/cli-schema";
|
|
5
|
+
import type { PackSlimProgressListener, PackSlimRunStats } from "#/pack-slim/domain/types";
|
|
6
|
+
/**
|
|
7
|
+
* A pack-slim run request paired with an optional progress listener.
|
|
8
|
+
*
|
|
9
|
+
* @since 0.8.1
|
|
10
|
+
*/
|
|
11
|
+
export type PackSlimRunInput = PackSlimRunRequest & {
|
|
12
|
+
readonly listener?: PackSlimProgressListener | undefined;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Slims every published package's manifest and build output for publish and returns the aggregate stats.
|
|
16
|
+
*
|
|
17
|
+
* @remarks Meant to run on an ephemeral CI checkout right before `changeset publish`: it rewrites `package.json` down to
|
|
18
|
+
* what a consumer reads, drops `dist` source maps, and clears their now-dangling `sourceMappingURL` directives, so the
|
|
19
|
+
* tarball ships only `dist` runtime and types. Private packages are skipped because `changeset publish` never publishes them.
|
|
20
|
+
*
|
|
21
|
+
* @since 0.8.1
|
|
22
|
+
*/
|
|
23
|
+
export declare function runPackSlim(fs: FilesystemPort, input: PackSlimRunInput): Promise<Result<PackSlimRunStats, AppError>>;
|
package/dist/pack-slim/sync.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { AppError, messageFrom } from "#/core/errors";
|
|
3
3
|
import { err, ok } from "#/core/result";
|
|
4
4
|
import { listWorkspacePackageDirectories } from "#/core/workspace/resolver";
|
|
5
|
-
import {
|
|
5
|
+
import { distDirName, packageJsonFileName } from "#/core/workspace/well-known-files";
|
|
6
6
|
import { isMapAnnotatedFile, isSourceMapFile, slimPublishManifest, stripSourceMappingComment, } from "#/pack-slim/domain/transform";
|
|
7
7
|
/**
|
|
8
8
|
* Slims every published package's manifest and build output for publish and returns the aggregate stats.
|
|
@@ -47,7 +47,7 @@ export async function runPackSlim(fs, input) {
|
|
|
47
47
|
async function resolveTargets(fs, rootDir, packageFilter) {
|
|
48
48
|
if (packageFilter !== undefined) {
|
|
49
49
|
const packageDir = path.resolve(rootDir, packageFilter);
|
|
50
|
-
if (!fs.existsSync(path.join(packageDir,
|
|
50
|
+
if (!fs.existsSync(path.join(packageDir, packageJsonFileName))) {
|
|
51
51
|
throw new Error(`No package.json under "${packageFilter}"`);
|
|
52
52
|
}
|
|
53
53
|
return [packageDir];
|
|
@@ -56,7 +56,7 @@ async function resolveTargets(fs, rootDir, packageFilter) {
|
|
|
56
56
|
return [...layout.packageDirectoryPathsAbsolute].sort((left, right) => left.localeCompare(right));
|
|
57
57
|
}
|
|
58
58
|
async function slimWorkspacePackage(fs, packageDir, write) {
|
|
59
|
-
const packageJsonPath = path.join(packageDir,
|
|
59
|
+
const packageJsonPath = path.join(packageDir, packageJsonFileName);
|
|
60
60
|
const pkgStats = {
|
|
61
61
|
name: path.basename(packageDir),
|
|
62
62
|
path: packageDir,
|
|
@@ -103,7 +103,7 @@ async function slimWorkspacePackage(fs, packageDir, write) {
|
|
|
103
103
|
if (report.changed && write) {
|
|
104
104
|
await fs.writeFile(packageJsonPath, `${JSON.stringify(slimmed, null, 2)}\n`, "utf8");
|
|
105
105
|
}
|
|
106
|
-
await pruneDist(fs, path.join(packageDir,
|
|
106
|
+
await pruneDist(fs, path.join(packageDir, distDirName), write, pkgStats);
|
|
107
107
|
pkgStats.changed = report.changed || pkgStats.mapFilesDeleted > 0 || pkgStats.sourceCommentsStripped > 0;
|
|
108
108
|
}
|
|
109
109
|
catch (caughtError) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AppError } from "#/core/errors";
|
|
2
|
+
import type { Result } from "#/core/result";
|
|
3
|
+
/**
|
|
4
|
+
* Whether git's tracked-only porcelain output reports any uncommitted change.
|
|
5
|
+
*
|
|
6
|
+
* @remarks The output is read with `--untracked-files=no`, so untracked and gitignored paths (like the freshly built
|
|
7
|
+
* `dist`) never appear — any non-blank line is a staged or unstaged change to a tracked file.
|
|
8
|
+
*
|
|
9
|
+
* @since 0.8.1
|
|
10
|
+
*/
|
|
11
|
+
export declare function hasUncommittedTrackedChanges(porcelainOutput: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Refuses when the git working tree carries uncommitted tracked changes, so a destructive slim never lands on real work.
|
|
14
|
+
*
|
|
15
|
+
* @remarks pack-slim rewrites tracked `package.json` files and deletes build output; its result must never be committed.
|
|
16
|
+
* A caller passing `--force` skips this, and `--dry-run` never reaches it because it writes nothing.
|
|
17
|
+
*
|
|
18
|
+
* @since 0.8.1
|
|
19
|
+
*/
|
|
20
|
+
export declare function ensureWorkingTreeClean(rootDir: string): Result<void, AppError>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { CodefastConfig } from "#/core/config/schema";
|
|
2
|
+
/**
|
|
3
|
+
* Per-file outcome of a tag run.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.3.16-canary.0
|
|
6
|
+
*/
|
|
7
|
+
export type TagFileResult = {
|
|
8
|
+
filePath: string;
|
|
9
|
+
taggedDeclarations: number;
|
|
10
|
+
changed: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Outcome of tagging one target: the version stamped and the per-file tallies.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.3.16-canary.0
|
|
16
|
+
*/
|
|
17
|
+
export type TagRunResult = {
|
|
18
|
+
version: string;
|
|
19
|
+
filesScanned: number;
|
|
20
|
+
filesChanged: number;
|
|
21
|
+
taggedDeclarations: number;
|
|
22
|
+
fileResults: Array<TagFileResult>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Options for one target's tag run.
|
|
26
|
+
*
|
|
27
|
+
* @since 0.3.16-canary.0
|
|
28
|
+
*/
|
|
29
|
+
export type TagRunOptions = {
|
|
30
|
+
write: boolean;
|
|
31
|
+
};
|
|
32
|
+
type TagTargetCandidateSource = "explicit-target" | "workspace-package" | "repo-src-fallback";
|
|
33
|
+
/**
|
|
34
|
+
* How a resolved tag target was chosen.
|
|
35
|
+
*
|
|
36
|
+
* @since 0.3.16-canary.0
|
|
37
|
+
*/
|
|
38
|
+
type TagTargetSource = "explicit-target" | "workspace-package-selected-src" | "workspace-package-selected-root" | "repo-src-fallback";
|
|
39
|
+
/**
|
|
40
|
+
* A candidate path a tag run may resolve into a target.
|
|
41
|
+
*
|
|
42
|
+
* @since 0.3.16-canary.0
|
|
43
|
+
*/
|
|
44
|
+
export type TagTargetCandidate = {
|
|
45
|
+
candidatePath: string;
|
|
46
|
+
rootRelativeCandidatePath: string;
|
|
47
|
+
source: TagTargetCandidateSource;
|
|
48
|
+
packageDir: string | null;
|
|
49
|
+
packageName: string | null;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* A directory or file a tag run will stamp, with its owning package when known.
|
|
53
|
+
*
|
|
54
|
+
* @since 0.3.16-canary.0
|
|
55
|
+
*/
|
|
56
|
+
export type TagResolvedTarget = {
|
|
57
|
+
targetPath: string;
|
|
58
|
+
rootRelativeTargetPath: string;
|
|
59
|
+
source: TagTargetSource;
|
|
60
|
+
packageDir: string | null;
|
|
61
|
+
packageName: string | null;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* One target's execution outcome, carrying either its run result or its error.
|
|
65
|
+
*
|
|
66
|
+
* @since 0.3.16-canary.0
|
|
67
|
+
*/
|
|
68
|
+
export type TagTargetExecutionResult = {
|
|
69
|
+
target: TagResolvedTarget;
|
|
70
|
+
targetExists: boolean;
|
|
71
|
+
runError: string | null;
|
|
72
|
+
result: TagRunResult | null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Callbacks a tag run invokes as each target starts and completes.
|
|
76
|
+
*
|
|
77
|
+
* @since 0.3.16-canary.0
|
|
78
|
+
*/
|
|
79
|
+
export interface TagProgressListener {
|
|
80
|
+
onTargetStarted: (target: TagResolvedTarget) => void;
|
|
81
|
+
onTargetCompleted: (target: TagResolvedTarget, result: TagTargetExecutionResult) => void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Aggregate outcome of a tag run across every selected target.
|
|
85
|
+
*
|
|
86
|
+
* @since 0.3.16-canary.0
|
|
87
|
+
*/
|
|
88
|
+
export type TagSyncResult = {
|
|
89
|
+
mode: "applied" | "dry-run";
|
|
90
|
+
selectedTargets: Array<TagResolvedTarget>;
|
|
91
|
+
skippedPackages: Array<string>;
|
|
92
|
+
targetResults: Array<TagTargetExecutionResult>;
|
|
93
|
+
filesScanned: number;
|
|
94
|
+
filesChanged: number;
|
|
95
|
+
taggedDeclarations: number;
|
|
96
|
+
versionSummary: string;
|
|
97
|
+
distinctVersions: Array<string>;
|
|
98
|
+
modifiedFiles: Array<string>;
|
|
99
|
+
hookError: string | null;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Everything the `tag` action needs resolved before a run: root, config, and target path.
|
|
103
|
+
*
|
|
104
|
+
* @since 0.3.16-canary.0
|
|
105
|
+
*/
|
|
106
|
+
export interface TagCommandPrelude {
|
|
107
|
+
readonly rootDir: string;
|
|
108
|
+
readonly config: CodefastConfig;
|
|
109
|
+
readonly resolvedTargetPath: string | undefined;
|
|
110
|
+
}
|
|
111
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TagProgressListener, TagResolvedTarget, TagSyncResult, TagTargetExecutionResult } from "#/tag/domain/types";
|
|
2
|
+
/**
|
|
3
|
+
* A progress listener that prints a line as each tag target starts and completes.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.3.16-canary.0
|
|
6
|
+
*/
|
|
7
|
+
export declare class TagSyncProgressPresenter implements TagProgressListener {
|
|
8
|
+
onTargetStarted(target: TagResolvedTarget): void;
|
|
9
|
+
onTargetCompleted(target: TagResolvedTarget, result: TagTargetExecutionResult): void;
|
|
10
|
+
private static formatProgress;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Prints a tag run's target table, warnings, and summary, and returns the exit code.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.3.16-canary.0
|
|
16
|
+
*/
|
|
17
|
+
export declare function presentTagSyncResult(result: TagSyncResult, rootDir: string): number;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AppError } from "#/core/errors";
|
|
2
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
3
|
+
import type { Result } from "#/core/result";
|
|
4
|
+
import type { TagCommandPrelude } from "#/tag/domain/types";
|
|
5
|
+
/**
|
|
6
|
+
* Resolves the repo root, config, and optional target path into the prelude a tag run starts from.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.3.16-canary.0
|
|
9
|
+
*/
|
|
10
|
+
export declare function prepareTagSync(fs: FilesystemPort, args: {
|
|
11
|
+
readonly currentWorkingDirectory: string;
|
|
12
|
+
readonly rawTarget: string | undefined;
|
|
13
|
+
}): Promise<Result<TagCommandPrelude, AppError>>;
|
package/dist/tag/prepare.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadCodefastConfig } from "#/core/config";
|
|
2
2
|
import { ok } from "#/core/result";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveProjectRoot } from "#/core/workspace/resolver";
|
|
4
4
|
import { resolveProvidedTagTargetPath } from "#/tag/resolve-target-path";
|
|
5
5
|
/**
|
|
6
6
|
* Resolves the repo root, config, and optional target path into the prelude a tag run starts from.
|
|
@@ -10,7 +10,7 @@ import { resolveProvidedTagTargetPath } from "#/tag/resolve-target-path";
|
|
|
10
10
|
export async function prepareTagSync(fs, args) {
|
|
11
11
|
let rootDir;
|
|
12
12
|
try {
|
|
13
|
-
rootDir =
|
|
13
|
+
rootDir = resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir;
|
|
14
14
|
}
|
|
15
15
|
catch {
|
|
16
16
|
rootDir = args.currentWorkingDirectory;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
2
|
+
/**
|
|
3
|
+
* Canonicalizes the user-provided target path, or returns `undefined` when none was given.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.3.16-canary.0
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveProvidedTagTargetPath(fs: FilesystemPort, args: {
|
|
8
|
+
readonly currentWorkingDirectory: string;
|
|
9
|
+
readonly rawTarget: string | undefined;
|
|
10
|
+
}): string | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
2
|
+
import type { TagFileResult } from "#/tag/domain/types";
|
|
3
|
+
/**
|
|
4
|
+
* The writer that adds missing `@since` tags to a file's exported declarations.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.3.16-canary.0
|
|
7
|
+
*/
|
|
8
|
+
export declare class TagSinceWriter {
|
|
9
|
+
private readonly fs;
|
|
10
|
+
private readonly sinceDocumentationTag;
|
|
11
|
+
constructor(fs: FilesystemPort);
|
|
12
|
+
applySinceTagsToFile(filePath: string, version: string, write: boolean): TagFileResult;
|
|
13
|
+
/**
|
|
14
|
+
* The taggable declaration a top-level statement introduces, resolving the
|
|
15
|
+
* `export … <decl>` wrapper to the wrapper node — its `start` sits at `export`,
|
|
16
|
+
* matching `ts.getStart` on a modifier-bearing declaration.
|
|
17
|
+
*/
|
|
18
|
+
private taggableDeclarationOf;
|
|
19
|
+
private declarationNames;
|
|
20
|
+
private addDeclarationName;
|
|
21
|
+
private collectLocalNamedDeclarations;
|
|
22
|
+
private collectExportedDeclarations;
|
|
23
|
+
/**
|
|
24
|
+
* The JSDoc block documenting `anchor`: the nearest preceding `/** … *\/` whose
|
|
25
|
+
* gap to the declaration is whitespace only, mirroring TS comment attachment.
|
|
26
|
+
*/
|
|
27
|
+
private associatedJsDoc;
|
|
28
|
+
private jsDocHasSinceTag;
|
|
29
|
+
private makeJSDocSinceLine;
|
|
30
|
+
private makeSinceOnlyJSDocBlock;
|
|
31
|
+
private makeDeclarationSinceLine;
|
|
32
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AppError } from "#/core/errors";
|
|
2
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
3
|
+
import type { Result } from "#/core/result";
|
|
4
|
+
import type { TagProgressListener, TagSyncResult, TagTargetCandidate } from "#/tag/domain/types";
|
|
5
|
+
/**
|
|
6
|
+
* The inputs a tag run is invoked with.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.3.16-canary.0
|
|
9
|
+
*/
|
|
10
|
+
export type TagSyncRunRequest = {
|
|
11
|
+
rootDir: string;
|
|
12
|
+
write: boolean;
|
|
13
|
+
json?: boolean | undefined;
|
|
14
|
+
targetPath?: string | undefined;
|
|
15
|
+
skipPackages?: Array<string> | undefined;
|
|
16
|
+
config?: unknown;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A run request paired with an optional progress listener.
|
|
20
|
+
*
|
|
21
|
+
* @since 0.3.16-canary.0
|
|
22
|
+
*/
|
|
23
|
+
export type TagSyncExecutionInput = TagSyncRunRequest & {
|
|
24
|
+
readonly listener?: TagProgressListener | undefined;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Runs the tag sync across the selected targets and returns the aggregate result.
|
|
28
|
+
*
|
|
29
|
+
* @since 0.3.16-canary.0
|
|
30
|
+
*/
|
|
31
|
+
export declare function runTagSync(fs: FilesystemPort, input: TagSyncExecutionInput): Promise<Result<TagSyncResult, AppError>>;
|
|
32
|
+
/**
|
|
33
|
+
* Partition tag target candidates into those to tag and those to skip, matching
|
|
34
|
+
* each candidate's package name against `skipPackages` as glob patterns.
|
|
35
|
+
* Candidates without a package name (e.g. an explicit-target path) are never skipped.
|
|
36
|
+
*
|
|
37
|
+
* @since 0.5.0-canary.0
|
|
38
|
+
*/
|
|
39
|
+
export declare function filterSkippedCandidates(targetCandidates: Array<TagTargetCandidate>, skipPackages: ReadonlyArray<string> | undefined): {
|
|
40
|
+
includedCandidates: Array<TagTargetCandidate>;
|
|
41
|
+
skippedPackages: Array<string>;
|
|
42
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
2
|
+
import type { TagTargetCandidate } from "#/tag/domain/types";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the candidate targets for a tag run: the explicit target, or the discovered workspace packages.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.3.16-canary.0
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveTagTargetCandidates(fs: FilesystemPort, rootDir: string, explicitTarget: string | undefined): Promise<Array<TagTargetCandidate>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { listWorkspacePackageDirectories } from "#/core/workspace/resolver";
|
|
4
|
-
|
|
4
|
+
import { packageJsonFileName } from "#/core/workspace/well-known-files";
|
|
5
5
|
const packageJsonNameSchema = z.looseObject({
|
|
6
6
|
name: z.string().min(1).optional(),
|
|
7
7
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
2
|
+
import type { TagRunOptions, TagRunResult } from "#/tag/domain/types";
|
|
3
|
+
/**
|
|
4
|
+
* Stamps `@since` tags across one target's TypeScript files and returns the run result.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.3.16-canary.0
|
|
7
|
+
*/
|
|
8
|
+
export declare function runTagOnTarget(fs: FilesystemPort, targetPath: string, opts: TagRunOptions): TagRunResult;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FilesystemPort } from "#/core/filesystem/port";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the `version` of the nearest enclosing `package.json` above a target path.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.3.16-canary.0
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveNearestPackageVersion(fs: FilesystemPort, targetPath: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codefast/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Developer CLI for the Codefast monorepo (arrange, audit, mirror, pack-slim, tag)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -31,11 +31,22 @@
|
|
|
31
31
|
"LICENSE"
|
|
32
32
|
],
|
|
33
33
|
"type": "module",
|
|
34
|
+
"main": "./dist/index.js",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
34
37
|
"imports": {
|
|
35
38
|
"#/*": {
|
|
39
|
+
"types": "./dist/*.d.ts",
|
|
36
40
|
"default": "./dist/*.js"
|
|
37
41
|
}
|
|
38
42
|
},
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": "./dist/index.d.ts",
|
|
46
|
+
"import": "./dist/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
39
50
|
"publishConfig": {
|
|
40
51
|
"access": "public"
|
|
41
52
|
},
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { parseSync } from "oxc-parser";
|
|
2
|
-
function isOxcNode(value) {
|
|
3
|
-
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
4
|
-
}
|
|
5
|
-
function isIdentifierNamed(node, name) {
|
|
6
|
-
return isOxcNode(node) && node.type === "Identifier" && node.name === name;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Scans one TypeScript source for React import-policy violations.
|
|
10
|
-
*
|
|
11
|
-
* @remarks Three violation kinds: `import * as React`, a default `React` import (type-only
|
|
12
|
-
* included), and — only when no import binds `React` — an implicit `React.*` UMD-global type
|
|
13
|
-
* reference, which tsc accepts silently through the `export as namespace React` in `@types/react`.
|
|
14
|
-
*
|
|
15
|
-
* @since 0.8.0
|
|
16
|
-
*/
|
|
17
|
-
export function auditReactImportSource(filePath, sourceText) {
|
|
18
|
-
const { program } = parseSync(filePath, sourceText);
|
|
19
|
-
const statements = program.body;
|
|
20
|
-
const violations = [];
|
|
21
|
-
let bindsReact = false;
|
|
22
|
-
for (const statement of statements) {
|
|
23
|
-
if (statement.type !== "ImportDeclaration") {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
const source = statement.source;
|
|
27
|
-
if (!isOxcNode(source) || source.value !== "react") {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
const specifiers = Array.isArray(statement.specifiers) ? statement.specifiers.filter(isOxcNode) : [];
|
|
31
|
-
bindsReact ||= specifiers.some((specifier) => isIdentifierNamed(specifier.local, "React"));
|
|
32
|
-
for (const specifier of specifiers) {
|
|
33
|
-
if (specifier.type === "ImportNamespaceSpecifier") {
|
|
34
|
-
violations.push({
|
|
35
|
-
line: lineOfOffset(sourceText, statement.start),
|
|
36
|
-
raw: firstLineOf(sourceText.slice(statement.start, statement.end)),
|
|
37
|
-
reason: 'namespace React import — import members by name from "react"',
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else if (specifier.type === "ImportDefaultSpecifier") {
|
|
41
|
-
violations.push({
|
|
42
|
-
line: lineOfOffset(sourceText, statement.start),
|
|
43
|
-
raw: firstLineOf(sourceText.slice(statement.start, statement.end)),
|
|
44
|
-
reason: 'default React import — import members by name from "react"',
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// A bound `React` means the import itself is flagged above; qualified names under it are
|
|
50
|
-
// symptoms, not extra findings.
|
|
51
|
-
if (!bindsReact) {
|
|
52
|
-
collectUmdGlobalReferences(program, sourceText, violations);
|
|
53
|
-
}
|
|
54
|
-
violations.sort((a, b) => a.line - b.line);
|
|
55
|
-
return violations;
|
|
56
|
-
}
|
|
57
|
-
function collectUmdGlobalReferences(node, sourceText, violations) {
|
|
58
|
-
if (node.type === "TSQualifiedName" && isIdentifierNamed(node.left, "React")) {
|
|
59
|
-
violations.push({
|
|
60
|
-
line: lineOfOffset(sourceText, node.start),
|
|
61
|
-
raw: sourceText.slice(node.start, node.end),
|
|
62
|
-
reason: 'implicit React.* UMD global — add import type { … } from "react"',
|
|
63
|
-
});
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
for (const value of Object.values(node)) {
|
|
67
|
-
if (Array.isArray(value)) {
|
|
68
|
-
for (const item of value) {
|
|
69
|
-
if (isOxcNode(item)) {
|
|
70
|
-
collectUmdGlobalReferences(item, sourceText, violations);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else if (isOxcNode(value)) {
|
|
75
|
-
collectUmdGlobalReferences(value, sourceText, violations);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function lineOfOffset(sourceText, offset) {
|
|
80
|
-
let line = 1;
|
|
81
|
-
for (let index = 0; index < offset; index++) {
|
|
82
|
-
if (sourceText.charCodeAt(index) === 10) {
|
|
83
|
-
line++;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return line;
|
|
87
|
-
}
|
|
88
|
-
function firstLineOf(text) {
|
|
89
|
-
const newlineIndex = text.indexOf("\n");
|
|
90
|
-
return newlineIndex === -1 ? text : text.slice(0, newlineIndex);
|
|
91
|
-
}
|