@codefast/cli 0.10.0 → 0.12.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 +84 -0
- package/README.md +66 -41
- package/dist/arrange/command.js +99 -136
- package/dist/arrange/domain/ast/collectors-cn.d.ts +2 -2
- package/dist/arrange/domain/ast/collectors-cn.js +2 -2
- package/dist/arrange/domain/ast/collectors-jsx.d.ts +2 -2
- package/dist/arrange/domain/ast/collectors-jsx.js +1 -1
- package/dist/arrange/domain/ast/collectors-tv.d.ts +2 -2
- package/dist/arrange/domain/ast/collectors-tv.js +5 -5
- package/dist/arrange/domain/ast/helpers.d.ts +2 -2
- package/dist/arrange/domain/ast/helpers.js +3 -4
- package/dist/arrange/domain/ast/simplify-targets.d.ts +1 -1
- package/dist/arrange/domain/ast/simplify-targets.js +23 -28
- package/dist/arrange/domain/ast/targets.d.ts +2 -2
- package/dist/arrange/domain/ast/targets.js +9 -9
- package/dist/arrange/{typescript-ast-translator.d.ts → domain/ast/translator.d.ts} +6 -5
- package/dist/arrange/{typescript-ast-translator.js → domain/ast/translator.js} +20 -23
- package/dist/arrange/domain/constants.d.ts +1 -1
- package/dist/arrange/domain/grouping-service.d.ts +2 -2
- package/dist/arrange/domain/grouping-service.js +3 -3
- package/dist/arrange/domain/grouping.js +3 -3
- package/dist/arrange/domain/imports.d.ts +1 -1
- package/dist/arrange/domain/imports.js +2 -2
- package/dist/arrange/domain/source-text-formatters.js +1 -1
- package/dist/arrange/domain/tailwind-token.js +1 -1
- package/dist/arrange/domain/token-classifier.d.ts +1 -1
- package/dist/arrange/domain/token-classifier.js +2 -2
- package/dist/arrange/domain/types.d.ts +3 -3
- package/dist/arrange/group/cli-result.d.ts +7 -0
- package/dist/arrange/group/cli-result.js +12 -0
- package/dist/arrange/group/cli-schema.d.ts +17 -0
- package/dist/arrange/group/cli-schema.js +13 -0
- package/dist/arrange/group/output.d.ts +7 -0
- package/dist/arrange/group/output.js +10 -0
- package/dist/arrange/group/suggest.d.ts +8 -0
- package/dist/arrange/{suggest.js → group/suggest.js} +2 -2
- package/dist/arrange/inspect/cli-result.d.ts +7 -0
- package/dist/arrange/inspect/cli-result.js +8 -0
- package/dist/arrange/inspect/cli-schema.d.ts +15 -0
- package/dist/arrange/inspect/cli-schema.js +9 -0
- package/dist/arrange/{domain → inspect/domain}/analyze-service.d.ts +2 -2
- package/dist/arrange/{domain → inspect/domain}/analyze-service.js +7 -7
- package/dist/arrange/inspect/output.d.ts +7 -0
- package/dist/arrange/inspect/output.js +42 -0
- package/dist/arrange/inspect/run.d.ts +10 -0
- package/dist/arrange/{analyze.js → inspect/run.js} +7 -7
- package/dist/arrange/prepare.d.ts +13 -0
- package/dist/arrange/{workspace.js → prepare.js} +9 -12
- package/dist/arrange/regroup/cli-result.d.ts +13 -0
- package/dist/arrange/regroup/cli-result.js +23 -0
- package/dist/arrange/regroup/cli-schema.d.ts +20 -0
- package/dist/arrange/regroup/cli-schema.js +14 -0
- package/dist/arrange/regroup/output.d.ts +14 -0
- package/dist/arrange/regroup/output.js +72 -0
- package/dist/arrange/{process-file.d.ts → regroup/process-file.d.ts} +3 -3
- package/dist/arrange/{process-file.js → regroup/process-file.js} +3 -3
- package/dist/arrange/regroup/run.d.ts +11 -0
- package/dist/arrange/{sync.js → regroup/run.js} +5 -5
- package/dist/arrange/resolve-target.d.ts +2 -2
- package/dist/arrange/resolve-target.js +2 -2
- package/dist/arrange/scan-target.d.ts +2 -2
- package/dist/arrange/scan-target.js +3 -3
- package/dist/arrange/simplify/cli-result.d.ts +7 -0
- package/dist/arrange/simplify/cli-result.js +8 -0
- package/dist/arrange/simplify/cli-schema.d.ts +17 -0
- package/dist/arrange/simplify/cli-schema.js +11 -0
- package/dist/arrange/simplify/fold-targets.d.ts +13 -0
- package/dist/arrange/simplify/fold-targets.js +139 -0
- package/dist/arrange/simplify/output.d.ts +7 -0
- package/dist/arrange/simplify/output.js +15 -0
- package/dist/arrange/simplify/process-file.d.ts +13 -0
- package/dist/arrange/simplify/process-file.js +49 -0
- package/dist/arrange/simplify/run.d.ts +14 -0
- package/dist/arrange/simplify/run.js +38 -0
- package/dist/arrange/simplify/variant-classname-probe.d.ts +35 -0
- package/dist/arrange/simplify/variant-classname-probe.js +95 -0
- package/dist/arrange/source-parse.d.ts +1 -1
- package/dist/arrange/source-parse.js +3 -3
- package/dist/audit/command.js +152 -212
- package/dist/audit/comments/cli-result.d.ts +13 -0
- package/dist/audit/comments/cli-result.js +22 -0
- package/dist/audit/comments/cli-schema.d.ts +19 -0
- package/dist/audit/comments/cli-schema.js +13 -0
- package/dist/audit/comments/output.d.ts +7 -0
- package/dist/audit/comments/output.js +27 -0
- package/dist/audit/comments/prepare.d.ts +16 -0
- package/dist/audit/comments/prepare.js +12 -0
- package/dist/audit/{run-comments.d.ts → comments/run.d.ts} +5 -5
- package/dist/audit/{run-comments.js → comments/run.js} +9 -9
- package/dist/audit/display-names/cli-result.d.ts +13 -0
- package/dist/audit/display-names/cli-result.js +22 -0
- package/dist/audit/display-names/cli-schema.d.ts +18 -0
- package/dist/audit/display-names/cli-schema.js +12 -0
- package/dist/audit/{domain → display-names/domain}/display-names.d.ts +1 -1
- package/dist/audit/display-names/output.d.ts +7 -0
- package/dist/audit/display-names/output.js +21 -0
- package/dist/audit/display-names/prepare.d.ts +16 -0
- package/dist/audit/display-names/prepare.js +12 -0
- package/dist/audit/display-names/run.d.ts +14 -0
- package/dist/audit/{run-display-names.js → display-names/run.js} +5 -5
- package/dist/audit/domain/types.d.ts +43 -0
- package/dist/audit/imports/cli-result.d.ts +13 -0
- package/dist/audit/imports/cli-result.js +22 -0
- package/dist/audit/imports/cli-schema.d.ts +18 -0
- package/dist/audit/imports/cli-schema.js +12 -0
- package/dist/audit/{domain → imports/domain}/import-policy.d.ts +3 -3
- package/dist/audit/{domain → imports/domain}/import-policy.js +4 -11
- package/dist/audit/imports/output.d.ts +7 -0
- package/dist/audit/imports/output.js +21 -0
- package/dist/audit/imports/prepare.d.ts +16 -0
- package/dist/audit/imports/prepare.js +12 -0
- package/dist/audit/imports/run.d.ts +14 -0
- package/dist/audit/{run-imports.js → imports/run.js} +6 -6
- package/dist/audit/links/cli-result.d.ts +13 -0
- package/dist/audit/links/cli-result.js +22 -0
- package/dist/audit/links/cli-schema.d.ts +18 -0
- package/dist/audit/links/cli-schema.js +12 -0
- package/dist/audit/{domain → links/domain}/markdown-links.d.ts +3 -3
- package/dist/audit/{domain → links/domain}/markdown-links.js +22 -8
- package/dist/audit/links/output.d.ts +7 -0
- package/dist/audit/links/output.js +21 -0
- package/dist/audit/links/prepare.d.ts +16 -0
- package/dist/audit/links/prepare.js +12 -0
- package/dist/audit/links/run.d.ts +14 -0
- package/dist/audit/{run-links.js → links/run.js} +4 -4
- package/dist/audit/prepare.d.ts +13 -52
- package/dist/audit/prepare.js +13 -136
- package/dist/audit/publish/cli-result.d.ts +13 -0
- package/dist/audit/publish/cli-result.js +22 -0
- package/dist/audit/publish/cli-schema.d.ts +18 -0
- package/dist/audit/publish/cli-schema.js +12 -0
- package/dist/audit/publish/domain/legacy-subpath.d.ts +8 -0
- package/dist/audit/publish/domain/legacy-subpath.js +22 -0
- package/dist/audit/publish/output.d.ts +7 -0
- package/dist/audit/publish/output.js +24 -0
- package/dist/audit/publish/prepare.d.ts +16 -0
- package/dist/audit/publish/prepare.js +12 -0
- package/dist/audit/publish/run.d.ts +14 -0
- package/dist/audit/publish/run.js +62 -0
- package/dist/audit/rtl/cli-result.d.ts +13 -0
- package/dist/audit/rtl/cli-result.js +22 -0
- package/dist/audit/rtl/cli-schema.d.ts +18 -0
- package/dist/audit/rtl/cli-schema.js +12 -0
- package/dist/audit/{domain → rtl/domain}/audit-file.d.ts +1 -1
- package/dist/audit/{domain → rtl/domain}/audit-file.js +2 -2
- package/dist/audit/{domain → rtl/domain}/tokenize.d.ts +1 -1
- package/dist/audit/rtl/output.d.ts +7 -0
- package/dist/audit/rtl/output.js +21 -0
- package/dist/audit/rtl/prepare.d.ts +13 -0
- package/dist/audit/rtl/prepare.js +41 -0
- package/dist/audit/rtl/run.d.ts +14 -0
- package/dist/audit/{run.js → rtl/run.js} +4 -4
- package/dist/bin.js +1 -1
- package/dist/cli.js +5 -5
- package/dist/core/cli/command-pipeline.d.ts +90 -0
- package/dist/core/cli/command-pipeline.js +83 -0
- package/dist/core/cli/format-error.d.ts +1 -1
- package/dist/core/cli/global-options.d.ts +1 -1
- package/dist/core/cli/global-options.js +1 -1
- package/dist/core/cli/resolve-root.d.ts +9 -0
- package/dist/core/cli/resolve-root.js +16 -0
- package/dist/core/cli/result-handle.d.ts +3 -9
- package/dist/core/cli/result-handle.js +4 -17
- package/dist/core/config/define-config.d.ts +1 -1
- package/dist/core/config/loader.d.ts +3 -3
- package/dist/core/config/loader.js +2 -2
- package/dist/core/config/schema.d.ts +1 -1
- package/dist/core/config/schema.js +1 -1
- package/dist/core/config/warnings.js +1 -1
- package/dist/core/config.d.ts +5 -5
- package/dist/core/config.js +4 -4
- package/dist/core/filesystem/{port.d.ts → filesystem.d.ts} +1 -1
- package/dist/core/filesystem/node.d.ts +3 -3
- package/dist/core/filesystem/node.js +1 -1
- package/dist/core/schema-parse.d.ts +2 -2
- package/dist/core/schema-parse.js +2 -2
- package/dist/core/source-text-edit.d.ts +14 -0
- package/dist/core/source-text-edit.js +22 -0
- package/dist/core/workspace/markdown-walk.d.ts +2 -2
- package/dist/core/workspace/markdown-walk.js +1 -1
- package/dist/core/workspace/package-version.d.ts +2 -2
- package/dist/core/workspace/package-version.js +2 -2
- package/dist/core/workspace/resolver.d.ts +3 -3
- package/dist/core/workspace/resolver.js +5 -5
- package/dist/core/workspace/source-walk.d.ts +2 -2
- package/dist/core/workspace/source-walk.js +1 -1
- package/dist/core/workspace/typescript-walk.d.ts +2 -2
- package/dist/core/workspace/typescript-walk.js +1 -1
- package/dist/core/workspace/walk-files.d.ts +2 -2
- package/dist/core/workspace/walk-files.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/mirror/cli-result.d.ts +1 -1
- package/dist/mirror/cli-result.js +1 -1
- package/dist/mirror/cli-schema.d.ts +2 -2
- package/dist/mirror/cli-schema.js +1 -1
- package/dist/mirror/command.js +36 -65
- package/dist/mirror/dist-filesystem-node.d.ts +8 -0
- package/dist/mirror/{dist-filesystem-impl.js → dist-filesystem-node.js} +3 -3
- package/dist/mirror/domain/dirent-guard.d.ts +1 -1
- package/dist/mirror/domain/exports.d.ts +2 -2
- package/dist/mirror/domain/exports.js +1 -1
- package/dist/mirror/domain/types.d.ts +59 -2
- package/dist/mirror/output.d.ts +1 -3
- package/dist/mirror/output.js +127 -2
- package/dist/mirror/package-path.d.ts +5 -5
- package/dist/mirror/package-path.js +3 -3
- package/dist/mirror/prepare.d.ts +6 -6
- package/dist/mirror/prepare.js +8 -12
- package/dist/mirror/run.d.ts +12 -0
- package/dist/mirror/{sync.js → run.js} +7 -7
- package/dist/mirror/supplement-exports.d.ts +3 -3
- package/dist/mirror/supplement-exports.js +2 -2
- package/dist/mirror/sync-workspace-package.d.ts +4 -4
- package/dist/mirror/sync-workspace-package.js +11 -14
- package/dist/mirror/write-exports.d.ts +3 -3
- package/dist/mirror/write-exports.js +3 -3
- package/dist/pack-slim/cli-result.d.ts +1 -1
- package/dist/pack-slim/cli-result.js +1 -1
- package/dist/pack-slim/cli-schema.d.ts +1 -1
- package/dist/pack-slim/cli-schema.js +1 -1
- package/dist/pack-slim/command.js +36 -71
- package/dist/pack-slim/domain/transform.d.ts +22 -1
- package/dist/pack-slim/domain/transform.js +65 -8
- package/dist/pack-slim/output.d.ts +1 -1
- package/dist/pack-slim/output.js +1 -1
- package/dist/pack-slim/prepare.d.ts +21 -0
- package/dist/pack-slim/prepare.js +14 -0
- package/dist/pack-slim/{sync.d.ts → run.d.ts} +6 -6
- package/dist/pack-slim/{sync.js → run.js} +5 -5
- package/dist/pack-slim/working-tree.d.ts +2 -2
- package/dist/pack-slim/working-tree.js +2 -2
- package/dist/tag/cli-result.d.ts +8 -2
- package/dist/tag/cli-result.js +15 -2
- package/dist/tag/cli-schema.d.ts +4 -4
- package/dist/tag/cli-schema.js +3 -4
- package/dist/tag/command.js +34 -61
- package/dist/tag/domain/skip-filter.d.ts +13 -0
- package/dist/tag/domain/skip-filter.js +29 -0
- package/dist/tag/domain/types.d.ts +22 -2
- package/dist/tag/domain/version-summary.d.ts +13 -0
- package/dist/tag/domain/version-summary.js +24 -0
- package/dist/tag/output.d.ts +4 -4
- package/dist/tag/output.js +7 -10
- package/dist/tag/prepare.d.ts +5 -5
- package/dist/tag/prepare.js +5 -5
- package/dist/tag/run.d.ts +10 -0
- package/dist/tag/{sync.js → run.js} +23 -53
- package/dist/tag/target/candidates.d.ts +8 -0
- package/dist/tag/{target-candidates.js → target/candidates.js} +3 -3
- package/dist/tag/{resolve-target-path.d.ts → target/resolve-path.d.ts} +2 -2
- package/dist/tag/target/runner.d.ts +8 -0
- package/dist/tag/{target-runner.js → target/runner.js} +3 -3
- package/dist/tag/{since-writer.d.ts → writer/since-writer.d.ts} +3 -3
- package/dist/tag/{since-writer.js → writer/since-writer.js} +1 -1
- package/dist/tag/{version-resolver.d.ts → writer/version-resolver.d.ts} +2 -2
- package/dist/tag/{version-resolver.js → writer/version-resolver.js} +1 -1
- package/package.json +15 -7
- package/dist/arrange/analyze.d.ts +0 -10
- package/dist/arrange/cli-schema.d.ts +0 -50
- package/dist/arrange/cli-schema.js +0 -34
- package/dist/arrange/output.d.ts +0 -26
- package/dist/arrange/output.js +0 -127
- package/dist/arrange/simplify-process-file.d.ts +0 -11
- package/dist/arrange/simplify-process-file.js +0 -30
- package/dist/arrange/simplify-sync.d.ts +0 -13
- package/dist/arrange/simplify-sync.js +0 -30
- package/dist/arrange/suggest.d.ts +0 -8
- package/dist/arrange/sync.d.ts +0 -11
- package/dist/arrange/workspace.d.ts +0 -13
- package/dist/audit/cli-schema.d.ts +0 -93
- package/dist/audit/cli-schema.js +0 -66
- package/dist/audit/output.d.ts +0 -91
- package/dist/audit/output.js +0 -213
- package/dist/audit/run-display-names.d.ts +0 -14
- package/dist/audit/run-imports.d.ts +0 -14
- package/dist/audit/run-links.d.ts +0 -14
- package/dist/audit/run.d.ts +0 -14
- package/dist/mirror/dist-filesystem-impl.d.ts +0 -8
- package/dist/mirror/sync-reporter.d.ts +0 -60
- package/dist/mirror/sync-reporter.js +0 -128
- package/dist/mirror/sync-types.d.ts +0 -43
- package/dist/mirror/sync-types.js +0 -1
- package/dist/mirror/sync.d.ts +0 -12
- package/dist/tag/sync.d.ts +0 -42
- package/dist/tag/target-candidates.d.ts +0 -8
- package/dist/tag/target-runner.d.ts +0 -8
- /package/dist/audit/{domain → comments/domain}/comment-content.d.ts +0 -0
- /package/dist/audit/{domain → comments/domain}/comment-content.js +0 -0
- /package/dist/audit/{domain → comments/domain}/comment-dividers.d.ts +0 -0
- /package/dist/audit/{domain → comments/domain}/comment-dividers.js +0 -0
- /package/dist/audit/{domain → comments/domain}/link-references.d.ts +0 -0
- /package/dist/audit/{domain → comments/domain}/link-references.js +0 -0
- /package/dist/audit/{domain → comments/domain}/since-versions.d.ts +0 -0
- /package/dist/audit/{domain → comments/domain}/since-versions.js +0 -0
- /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.d.ts +0 -0
- /package/dist/audit/{domain → comments/domain}/tsdoc-syntax.js +0 -0
- /package/dist/audit/{domain → display-names/domain}/display-names.js +0 -0
- /package/dist/audit/{domain → rtl/domain}/mappings.d.ts +0 -0
- /package/dist/audit/{domain → rtl/domain}/mappings.js +0 -0
- /package/dist/audit/{domain → rtl/domain}/tokenize.js +0 -0
- /package/dist/core/filesystem/{port.js → filesystem.js} +0 -0
- /package/dist/tag/{resolve-target-path.js → target/resolve-path.js} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { logger } from "#core/logger";
|
|
2
|
+
/**
|
|
3
|
+
* Human-readable link audit report.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.5.0
|
|
6
|
+
*/
|
|
7
|
+
export function presentLinkAuditResult(result) {
|
|
8
|
+
for (const file of result.files) {
|
|
9
|
+
logger.out(`\n${file.relativePath}`);
|
|
10
|
+
for (const { line, raw, reason } of file.breakages) {
|
|
11
|
+
logger.out(` ${line}: ${raw} → ${reason}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const allowlistSuffix = result.allowlistedCount > 0 ? ` (${result.allowlistedCount} allowlisted)` : "";
|
|
15
|
+
if (result.breakageCount > 0) {
|
|
16
|
+
logger.out(`\n✖ ${result.breakageCount} broken link(s)${allowlistSuffix}`);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
logger.out(`✓ ${result.linkCount} repo-local link(s) across ${result.scannedFileCount} document(s) all resolve${allowlistSuffix}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuditCommandPrelude } from "#audit/prepare";
|
|
2
|
+
import type { AppError } from "#core/errors";
|
|
3
|
+
import type { Filesystem } from "#core/filesystem/filesystem";
|
|
4
|
+
import type { Result } from "#core/result";
|
|
5
|
+
/**
|
|
6
|
+
* Loads config and resolves the scan target for `audit links`.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
|
|
9
|
+
* package cannot see the cross-package references that are the ones most likely to rot.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.5.0
|
|
12
|
+
*/
|
|
13
|
+
export declare function prepareLinkAudit(fs: Filesystem, args: {
|
|
14
|
+
readonly currentWorkingDirectory: string;
|
|
15
|
+
readonly rawTarget: string | undefined;
|
|
16
|
+
}): Promise<Result<AuditCommandPrelude, AppError>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { prepareRepoRootAudit } from "#audit/prepare";
|
|
2
|
+
/**
|
|
3
|
+
* Loads config and resolves the scan target for `audit links`.
|
|
4
|
+
*
|
|
5
|
+
* @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
|
|
6
|
+
* package cannot see the cross-package references that are the ones most likely to rot.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.5.0
|
|
9
|
+
*/
|
|
10
|
+
export async function prepareLinkAudit(fs, args) {
|
|
11
|
+
return prepareRepoRootAudit(fs, args, (config) => config.audit?.links?.allowlist ?? []);
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LinkAuditResult } from "#audit/domain/types";
|
|
2
|
+
import { AppError } from "#core/errors";
|
|
3
|
+
import type { Filesystem } from "#core/filesystem/filesystem";
|
|
4
|
+
import type { Result } from "#core/result";
|
|
5
|
+
/**
|
|
6
|
+
* Reports markdown links that point at nothing — a missing path, or an anchor the target does not offer.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.5.0
|
|
9
|
+
*/
|
|
10
|
+
export declare function runLinkAudit(fs: Filesystem, args: {
|
|
11
|
+
readonly rootDir: string;
|
|
12
|
+
readonly targetPath: string;
|
|
13
|
+
readonly allowlist: ReadonlyArray<string>;
|
|
14
|
+
}): Result<LinkAuditResult, AppError>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { collectMarkdownAnchors, scanMarkdownLinks } from "
|
|
3
|
-
import { AppError, messageFrom } from "
|
|
4
|
-
import { err, ok } from "
|
|
5
|
-
import { walkMarkdownFiles } from "
|
|
2
|
+
import { collectMarkdownAnchors, scanMarkdownLinks } from "#audit/links/domain/markdown-links";
|
|
3
|
+
import { AppError, messageFrom } from "#core/errors";
|
|
4
|
+
import { err, ok } from "#core/result";
|
|
5
|
+
import { walkMarkdownFiles } from "#core/workspace/markdown-walk";
|
|
6
6
|
/**
|
|
7
7
|
* Reports markdown links that point at nothing — a missing path, or an anchor the target does not offer.
|
|
8
8
|
*
|
package/dist/audit/prepare.d.ts
CHANGED
|
@@ -1,70 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import type {
|
|
1
|
+
import type { CodefastConfig } from "#core/config/schema";
|
|
2
|
+
import { AppError } from "#core/errors";
|
|
3
|
+
import type { Filesystem } from "#core/filesystem/filesystem";
|
|
4
|
+
import type { Result } from "#core/result";
|
|
4
5
|
/**
|
|
5
|
-
* Shared prelude for
|
|
6
|
+
* Shared prelude for an audit: repo root and the canonicalized scan target with its allowlist.
|
|
6
7
|
*
|
|
7
8
|
* @since 0.5.0-canary.6
|
|
8
9
|
*/
|
|
9
|
-
export type
|
|
10
|
+
export type AuditCommandPrelude = {
|
|
10
11
|
readonly rootDir: string;
|
|
11
12
|
readonly targetPath: string;
|
|
12
13
|
readonly allowlist: ReadonlyArray<string>;
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
+
* Resolves a path that may be absolute or relative to `rootDir`.
|
|
16
17
|
*
|
|
17
18
|
* @since 0.5.0-canary.6
|
|
18
19
|
*/
|
|
19
|
-
export declare function
|
|
20
|
-
readonly currentWorkingDirectory: string;
|
|
21
|
-
readonly rawTarget: string | undefined;
|
|
22
|
-
}): Promise<Result<RtlAuditCommandPrelude, AppError>>;
|
|
23
|
-
/**
|
|
24
|
-
* Loads config and resolves the scan target for `audit links`.
|
|
25
|
-
*
|
|
26
|
-
* @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
|
|
27
|
-
* package cannot see the cross-package references that are the ones most likely to rot.
|
|
28
|
-
*
|
|
29
|
-
* @since 0.5.0
|
|
30
|
-
*/
|
|
31
|
-
export declare function prepareLinkAudit(fs: FilesystemPort, args: {
|
|
32
|
-
readonly currentWorkingDirectory: string;
|
|
33
|
-
readonly rawTarget: string | undefined;
|
|
34
|
-
}): Promise<Result<RtlAuditCommandPrelude, AppError>>;
|
|
35
|
-
/**
|
|
36
|
-
* Loads config and resolves the scan target for `audit imports`.
|
|
37
|
-
*
|
|
38
|
-
* @remarks Defaults to the repo root: the import policy is repo-wide, and generated or vendored
|
|
39
|
-
* trees are already excluded by the shared walk.
|
|
40
|
-
*
|
|
41
|
-
* @since 0.10.0
|
|
42
|
-
*/
|
|
43
|
-
export declare function prepareImportsAudit(fs: FilesystemPort, args: {
|
|
44
|
-
readonly currentWorkingDirectory: string;
|
|
45
|
-
readonly rawTarget: string | undefined;
|
|
46
|
-
}): Promise<Result<RtlAuditCommandPrelude, AppError>>;
|
|
47
|
-
/**
|
|
48
|
-
* Loads config and resolves the scan target for `audit comments`.
|
|
49
|
-
*
|
|
50
|
-
* @remarks Defaults to the repo root: a divider convention that only holds inside one package
|
|
51
|
-
* is not a convention.
|
|
52
|
-
*
|
|
53
|
-
* @since 0.6.0
|
|
54
|
-
*/
|
|
55
|
-
export declare function prepareCommentAudit(fs: FilesystemPort, args: {
|
|
56
|
-
readonly currentWorkingDirectory: string;
|
|
57
|
-
readonly rawTarget: string | undefined;
|
|
58
|
-
}): Promise<Result<RtlAuditCommandPrelude, AppError>>;
|
|
20
|
+
export declare function resolveRepoRelativePath(rootDir: string, maybeRelative: string): string;
|
|
59
21
|
/**
|
|
60
|
-
* Loads config and resolves the scan target
|
|
22
|
+
* Loads config and resolves the repo root as the scan target, taking the allowlist the caller selects.
|
|
61
23
|
*
|
|
62
|
-
* @remarks
|
|
63
|
-
* has to hold across them.
|
|
24
|
+
* @remarks Every repo-wide audit shares this prelude; only the config key its allowlist comes from differs.
|
|
64
25
|
*
|
|
65
|
-
* @since 0.
|
|
26
|
+
* @since 0.11.0
|
|
66
27
|
*/
|
|
67
|
-
export declare function
|
|
28
|
+
export declare function prepareRepoRootAudit(fs: Filesystem, args: {
|
|
68
29
|
readonly currentWorkingDirectory: string;
|
|
69
30
|
readonly rawTarget: string | undefined;
|
|
70
|
-
}): Promise<Result<
|
|
31
|
+
}, selectAllowlist: (config: CodefastConfig) => ReadonlyArray<string>): Promise<Result<AuditCommandPrelude, AppError>>;
|
package/dist/audit/prepare.js
CHANGED
|
@@ -1,146 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { loadCodefastConfig } from "
|
|
3
|
-
import { AppError, messageFrom } from "
|
|
4
|
-
import { err, ok } from "
|
|
5
|
-
import { resolveProjectRoot } from "
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { loadCodefastConfig } from "#core/config";
|
|
3
|
+
import { AppError, messageFrom } from "#core/errors";
|
|
4
|
+
import { err, ok } from "#core/result";
|
|
5
|
+
import { resolveProjectRoot } from "#core/workspace/resolver";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Resolves a path that may be absolute or relative to `rootDir`.
|
|
8
8
|
*
|
|
9
9
|
* @since 0.5.0-canary.6
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
// Realpath so allowlist keys (`path.relative(rootDir, file)`) stay stable when cwd is a symlink.
|
|
15
|
-
rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
|
|
16
|
-
}
|
|
17
|
-
catch (caughtError) {
|
|
18
|
-
return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
|
|
19
|
-
}
|
|
20
|
-
const loadedOutcome = await loadCodefastConfig(rootDir, fs);
|
|
21
|
-
if (!loadedOutcome.ok) {
|
|
22
|
-
return loadedOutcome;
|
|
23
|
-
}
|
|
24
|
-
const { config } = loadedOutcome.value;
|
|
25
|
-
const rtlConfig = config.audit?.rtl ?? {};
|
|
26
|
-
const targetFromCli = args.rawTarget;
|
|
27
|
-
const targetFromConfig = rtlConfig.target;
|
|
28
|
-
const resolvedTargetInput = targetFromCli ?? targetFromConfig;
|
|
29
|
-
if (resolvedTargetInput === undefined) {
|
|
30
|
-
return err(new AppError("VALIDATION_ERROR", "Missing scan target: pass a path argument or set audit.rtl.target in codefast.config"));
|
|
31
|
-
}
|
|
32
|
-
const targetPath = resolveRepoRelativePath(targetFromCli !== undefined ? args.currentWorkingDirectory : rootDir, resolvedTargetInput);
|
|
33
|
-
if (!fs.existsSync(targetPath)) {
|
|
34
|
-
return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
|
|
35
|
-
}
|
|
36
|
-
return ok({
|
|
37
|
-
rootDir,
|
|
38
|
-
targetPath: fs.canonicalPathSync(targetPath),
|
|
39
|
-
allowlist: rtlConfig.allowlist ?? [],
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Loads config and resolves the scan target for `audit links`.
|
|
44
|
-
*
|
|
45
|
-
* @remarks Defaults to the repo root rather than a configured path: a link audit that only covers one
|
|
46
|
-
* package cannot see the cross-package references that are the ones most likely to rot.
|
|
47
|
-
*
|
|
48
|
-
* @since 0.5.0
|
|
49
|
-
*/
|
|
50
|
-
export async function prepareLinkAudit(fs, args) {
|
|
51
|
-
let rootDir;
|
|
52
|
-
try {
|
|
53
|
-
rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
|
|
54
|
-
}
|
|
55
|
-
catch (caughtError) {
|
|
56
|
-
return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
|
|
57
|
-
}
|
|
58
|
-
const loadedOutcome = await loadCodefastConfig(rootDir, fs);
|
|
59
|
-
if (!loadedOutcome.ok) {
|
|
60
|
-
return loadedOutcome;
|
|
61
|
-
}
|
|
62
|
-
const linksConfig = loadedOutcome.value.config.audit?.links ?? {};
|
|
63
|
-
const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
|
|
64
|
-
if (!fs.existsSync(targetPath)) {
|
|
65
|
-
return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
|
|
66
|
-
}
|
|
67
|
-
return ok({
|
|
68
|
-
rootDir,
|
|
69
|
-
targetPath: fs.canonicalPathSync(targetPath),
|
|
70
|
-
allowlist: linksConfig.allowlist ?? [],
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Loads config and resolves the scan target for `audit imports`.
|
|
75
|
-
*
|
|
76
|
-
* @remarks Defaults to the repo root: the import policy is repo-wide, and generated or vendored
|
|
77
|
-
* trees are already excluded by the shared walk.
|
|
78
|
-
*
|
|
79
|
-
* @since 0.10.0
|
|
80
|
-
*/
|
|
81
|
-
export async function prepareImportsAudit(fs, args) {
|
|
82
|
-
let rootDir;
|
|
83
|
-
try {
|
|
84
|
-
rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
|
|
85
|
-
}
|
|
86
|
-
catch (caughtError) {
|
|
87
|
-
return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
|
|
88
|
-
}
|
|
89
|
-
const loadedOutcome = await loadCodefastConfig(rootDir, fs);
|
|
90
|
-
if (!loadedOutcome.ok) {
|
|
91
|
-
return loadedOutcome;
|
|
92
|
-
}
|
|
93
|
-
const importsConfig = loadedOutcome.value.config.audit?.imports ?? {};
|
|
94
|
-
const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
|
|
95
|
-
if (!fs.existsSync(targetPath)) {
|
|
96
|
-
return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
|
|
97
|
-
}
|
|
98
|
-
return ok({
|
|
99
|
-
rootDir,
|
|
100
|
-
targetPath: fs.canonicalPathSync(targetPath),
|
|
101
|
-
allowlist: importsConfig.allowlist ?? [],
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Loads config and resolves the scan target for `audit comments`.
|
|
106
|
-
*
|
|
107
|
-
* @remarks Defaults to the repo root: a divider convention that only holds inside one package
|
|
108
|
-
* is not a convention.
|
|
109
|
-
*
|
|
110
|
-
* @since 0.6.0
|
|
111
|
-
*/
|
|
112
|
-
export async function prepareCommentAudit(fs, args) {
|
|
113
|
-
let rootDir;
|
|
114
|
-
try {
|
|
115
|
-
rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
|
|
116
|
-
}
|
|
117
|
-
catch (caughtError) {
|
|
118
|
-
return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
|
|
119
|
-
}
|
|
120
|
-
const loadedOutcome = await loadCodefastConfig(rootDir, fs);
|
|
121
|
-
if (!loadedOutcome.ok) {
|
|
122
|
-
return loadedOutcome;
|
|
123
|
-
}
|
|
124
|
-
const commentsConfig = loadedOutcome.value.config.audit?.comments ?? {};
|
|
125
|
-
const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
|
|
126
|
-
if (!fs.existsSync(targetPath)) {
|
|
127
|
-
return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
|
|
128
|
-
}
|
|
129
|
-
return ok({
|
|
130
|
-
rootDir,
|
|
131
|
-
targetPath: fs.canonicalPathSync(targetPath),
|
|
132
|
-
allowlist: commentsConfig.allowlist ?? [],
|
|
133
|
-
});
|
|
11
|
+
export function resolveRepoRelativePath(rootDir, maybeRelative) {
|
|
12
|
+
return path.isAbsolute(maybeRelative) ? path.resolve(maybeRelative) : path.resolve(rootDir, maybeRelative);
|
|
134
13
|
}
|
|
135
14
|
/**
|
|
136
|
-
* Loads config and resolves the scan target
|
|
15
|
+
* Loads config and resolves the repo root as the scan target, taking the allowlist the caller selects.
|
|
137
16
|
*
|
|
138
|
-
* @remarks
|
|
139
|
-
* has to hold across them.
|
|
17
|
+
* @remarks Every repo-wide audit shares this prelude; only the config key its allowlist comes from differs.
|
|
140
18
|
*
|
|
141
|
-
* @since 0.
|
|
19
|
+
* @since 0.11.0
|
|
142
20
|
*/
|
|
143
|
-
export async function
|
|
21
|
+
export async function prepareRepoRootAudit(fs, args, selectAllowlist) {
|
|
144
22
|
let rootDir;
|
|
145
23
|
try {
|
|
146
24
|
rootDir = fs.canonicalPathSync(resolveProjectRoot(args.currentWorkingDirectory, fs).rootDir);
|
|
@@ -152,7 +30,6 @@ export async function prepareDisplayNameAudit(fs, args) {
|
|
|
152
30
|
if (!loadedOutcome.ok) {
|
|
153
31
|
return loadedOutcome;
|
|
154
32
|
}
|
|
155
|
-
const displayNamesConfig = loadedOutcome.value.config.audit?.displayNames ?? {};
|
|
156
33
|
const targetPath = args.rawTarget === undefined ? rootDir : resolveRepoRelativePath(args.currentWorkingDirectory, args.rawTarget);
|
|
157
34
|
if (!fs.existsSync(targetPath)) {
|
|
158
35
|
return err(new AppError("NOT_FOUND", `Not found: ${targetPath}`));
|
|
@@ -160,6 +37,6 @@ export async function prepareDisplayNameAudit(fs, args) {
|
|
|
160
37
|
return ok({
|
|
161
38
|
rootDir,
|
|
162
39
|
targetPath: fs.canonicalPathSync(targetPath),
|
|
163
|
-
allowlist:
|
|
40
|
+
allowlist: selectAllowlist(loadedOutcome.value.config),
|
|
164
41
|
});
|
|
165
42
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PublishAuditResult } from "#audit/domain/types";
|
|
2
|
+
/**
|
|
3
|
+
* Exit `1` when any `#/` import or unshipped publish target remains.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.12.0
|
|
6
|
+
*/
|
|
7
|
+
export declare function exitCodeForPublishAuditResult(result: PublishAuditResult): number;
|
|
8
|
+
/**
|
|
9
|
+
* Machine-readable publish audit summary for `--json`.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.12.0
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatPublishAuditJsonOutput(result: PublishAuditResult, rootDir: string): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#core/exit-codes";
|
|
2
|
+
/**
|
|
3
|
+
* Exit `1` when any `#/` import or unshipped publish target remains.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.12.0
|
|
6
|
+
*/
|
|
7
|
+
export function exitCodeForPublishAuditResult(result) {
|
|
8
|
+
return result.legacyImportCount > 0 || result.unshipped.length > 0 ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Machine-readable publish audit summary for `--json`.
|
|
12
|
+
*
|
|
13
|
+
* @since 0.12.0
|
|
14
|
+
*/
|
|
15
|
+
export function formatPublishAuditJsonOutput(result, rootDir) {
|
|
16
|
+
return JSON.stringify({
|
|
17
|
+
schemaVersion: 1,
|
|
18
|
+
ok: result.legacyImportCount === 0 && result.unshipped.length === 0,
|
|
19
|
+
cwd: rootDir,
|
|
20
|
+
result,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Resolved request for a single publish audit run.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.12.0
|
|
6
|
+
*/
|
|
7
|
+
export type PublishAuditRunRequest = {
|
|
8
|
+
readonly rootDir: string;
|
|
9
|
+
readonly targetPath: string;
|
|
10
|
+
readonly allowlist?: ReadonlyArray<string> | undefined;
|
|
11
|
+
readonly json: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Zod schema for {@link PublishAuditRunRequest}.
|
|
15
|
+
*
|
|
16
|
+
* @since 0.12.0
|
|
17
|
+
*/
|
|
18
|
+
export declare const publishAuditRunRequestSchema: z.ZodType<PublishAuditRunRequest>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for {@link PublishAuditRunRequest}.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.12.0
|
|
6
|
+
*/
|
|
7
|
+
export const publishAuditRunRequestSchema = z.object({
|
|
8
|
+
rootDir: z.string().min(1),
|
|
9
|
+
targetPath: z.string().min(1),
|
|
10
|
+
allowlist: z.array(z.string()).optional(),
|
|
11
|
+
json: z.boolean(),
|
|
12
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Detects `#/`-prefixed internal import specifiers, which Node's ESM resolver rejects on the floor. */
|
|
2
|
+
import type { LegacySubpathImport } from "#audit/domain/types";
|
|
3
|
+
/**
|
|
4
|
+
* Every `#/`-prefixed import specifier in a source file, with its line number.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.12.0
|
|
7
|
+
*/
|
|
8
|
+
export declare function scanLegacySubpathImports(content: string): Array<LegacySubpathImport>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Detects `#/`-prefixed internal import specifiers, which Node's ESM resolver rejects on the floor. */
|
|
2
|
+
// A `#/` specifier in import position — after `from`, `import(`, or `require(`. Anchoring on the keyword
|
|
3
|
+
// rules out an unrelated string that merely contains `#/`, such as this rule's own diagnostic text.
|
|
4
|
+
const LEGACY_SUBPATH_SPECIFIER = /(?:\bfrom|\bimport|\brequire)\b\s*\(?\s*(["']#\/[^"']*["'])/g;
|
|
5
|
+
/**
|
|
6
|
+
* Every `#/`-prefixed import specifier in a source file, with its line number.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.12.0
|
|
9
|
+
*/
|
|
10
|
+
export function scanLegacySubpathImports(content) {
|
|
11
|
+
const found = [];
|
|
12
|
+
const lines = content.split("\n");
|
|
13
|
+
for (const [index, line] of lines.entries()) {
|
|
14
|
+
for (const match of line.matchAll(LEGACY_SUBPATH_SPECIFIER)) {
|
|
15
|
+
const raw = match[1];
|
|
16
|
+
if (raw !== undefined) {
|
|
17
|
+
found.push({ line: index + 1, raw });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { logger } from "#core/logger";
|
|
2
|
+
/**
|
|
3
|
+
* Human-readable publish audit report.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.12.0
|
|
6
|
+
*/
|
|
7
|
+
export function presentPublishAuditResult(result) {
|
|
8
|
+
for (const file of result.legacyImportFiles) {
|
|
9
|
+
logger.out(`\n${file.relativePath}`);
|
|
10
|
+
for (const { line, raw } of file.imports) {
|
|
11
|
+
logger.out(` ${line}: ${raw} → use a bare "#" prefix, not "#/"`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
for (const { packageName, field, subpath, target } of result.unshipped) {
|
|
15
|
+
logger.out(`\n${packageName}: ${field}["${subpath}"] → ${target} is not shipped by "files"`);
|
|
16
|
+
}
|
|
17
|
+
const problems = result.legacyImportCount + result.unshipped.length;
|
|
18
|
+
if (problems > 0) {
|
|
19
|
+
logger.out(`\n✖ ${result.legacyImportCount} legacy "#/" import(s), ${result.unshipped.length} unshipped target(s)`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
logger.out(`✓ No "#/" imports across ${result.scannedFileCount} file(s); every publish target ships across ${result.packageCount} package(s)`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuditCommandPrelude } from "#audit/prepare";
|
|
2
|
+
import type { AppError } from "#core/errors";
|
|
3
|
+
import type { Filesystem } from "#core/filesystem/filesystem";
|
|
4
|
+
import type { Result } from "#core/result";
|
|
5
|
+
/**
|
|
6
|
+
* Loads config and resolves the scan target for `audit publish`.
|
|
7
|
+
*
|
|
8
|
+
* @remarks Defaults to the repo root: the audit walks every published package's source and manifest, so
|
|
9
|
+
* a single-package target would miss the cross-package surface. It takes no allowlist.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.12.0
|
|
12
|
+
*/
|
|
13
|
+
export declare function preparePublishAudit(fs: Filesystem, args: {
|
|
14
|
+
readonly currentWorkingDirectory: string;
|
|
15
|
+
readonly rawTarget: string | undefined;
|
|
16
|
+
}): Promise<Result<AuditCommandPrelude, AppError>>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { prepareRepoRootAudit } from "#audit/prepare";
|
|
2
|
+
/**
|
|
3
|
+
* Loads config and resolves the scan target for `audit publish`.
|
|
4
|
+
*
|
|
5
|
+
* @remarks Defaults to the repo root: the audit walks every published package's source and manifest, so
|
|
6
|
+
* a single-package target would miss the cross-package surface. It takes no allowlist.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.12.0
|
|
9
|
+
*/
|
|
10
|
+
export async function preparePublishAudit(fs, args) {
|
|
11
|
+
return prepareRepoRootAudit(fs, args, () => []);
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PublishAuditResult } from "#audit/domain/types";
|
|
2
|
+
import { AppError } from "#core/errors";
|
|
3
|
+
import type { Filesystem } from "#core/filesystem/filesystem";
|
|
4
|
+
import type { Result } from "#core/result";
|
|
5
|
+
/**
|
|
6
|
+
* Reports what would break a consumer's install: a `#/`-prefixed import Node's ESM resolver rejects on
|
|
7
|
+
* the floor, and an `exports`/`imports` target the slimmed publish manifest does not ship.
|
|
8
|
+
*
|
|
9
|
+
* @since 0.12.0
|
|
10
|
+
*/
|
|
11
|
+
export declare function runPublishAudit(fs: Filesystem, args: {
|
|
12
|
+
readonly rootDir: string;
|
|
13
|
+
readonly targetPath: string;
|
|
14
|
+
}): Promise<Result<PublishAuditResult, AppError>>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { scanLegacySubpathImports } from "#audit/publish/domain/legacy-subpath";
|
|
3
|
+
import { AppError, messageFrom } from "#core/errors";
|
|
4
|
+
import { err, ok } from "#core/result";
|
|
5
|
+
import { listWorkspacePackageDirectories } from "#core/workspace/resolver";
|
|
6
|
+
import { sourceCommentLanguage, walkSourceFiles } from "#core/workspace/source-walk";
|
|
7
|
+
import { packageJsonFileName } from "#core/workspace/well-known-files";
|
|
8
|
+
import { unshippedPublishTargets } from "#pack-slim/domain/transform";
|
|
9
|
+
/**
|
|
10
|
+
* Reports what would break a consumer's install: a `#/`-prefixed import Node's ESM resolver rejects on
|
|
11
|
+
* the floor, and an `exports`/`imports` target the slimmed publish manifest does not ship.
|
|
12
|
+
*
|
|
13
|
+
* @since 0.12.0
|
|
14
|
+
*/
|
|
15
|
+
export async function runPublishAudit(fs, args) {
|
|
16
|
+
try {
|
|
17
|
+
const { rootDir, targetPath } = args;
|
|
18
|
+
const legacyImportFiles = [];
|
|
19
|
+
let legacyImportCount = 0;
|
|
20
|
+
// Tests are not published and may hold `#/` fixtures on purpose, so the specifier scan skips them.
|
|
21
|
+
const sourceFiles = walkSourceFiles(targetPath, fs).filter((filePath) => sourceCommentLanguage(filePath) === "js" && !filePath.split(path.sep).includes("tests"));
|
|
22
|
+
for (const absolutePath of sourceFiles) {
|
|
23
|
+
const imports = scanLegacySubpathImports(fs.readFileSync(absolutePath, "utf8"));
|
|
24
|
+
if (imports.length === 0) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
legacyImportCount += imports.length;
|
|
28
|
+
legacyImportFiles.push({ relativePath: toPosixPath(path.relative(rootDir, absolutePath)), imports });
|
|
29
|
+
}
|
|
30
|
+
const layout = await listWorkspacePackageDirectories(rootDir, fs, true);
|
|
31
|
+
const unshipped = [];
|
|
32
|
+
let packageCount = 0;
|
|
33
|
+
for (const packageDir of layout.packageDirectoryPathsAbsolute) {
|
|
34
|
+
const manifestPath = path.join(packageDir, packageJsonFileName);
|
|
35
|
+
if (!fs.existsSync(manifestPath)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
39
|
+
if (manifest.private === true) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
packageCount++;
|
|
43
|
+
const packageName = typeof manifest.name === "string" ? manifest.name : toPosixPath(path.relative(rootDir, packageDir));
|
|
44
|
+
for (const target of unshippedPublishTargets(manifest)) {
|
|
45
|
+
unshipped.push({ packageName, field: target.field, subpath: target.subpath, target: target.target });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return ok({
|
|
49
|
+
legacyImportFiles,
|
|
50
|
+
unshipped,
|
|
51
|
+
legacyImportCount,
|
|
52
|
+
scannedFileCount: sourceFiles.length,
|
|
53
|
+
packageCount,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
catch (caughtError) {
|
|
57
|
+
return err(new AppError("INFRA_FAILURE", messageFrom(caughtError), caughtError));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function toPosixPath(filePath) {
|
|
61
|
+
return filePath.split(path.sep).join("/");
|
|
62
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RtlAuditResult } from "#audit/domain/types";
|
|
2
|
+
/**
|
|
3
|
+
* Exit `1` when any non-allowlisted violation remains.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.5.0-canary.6
|
|
6
|
+
*/
|
|
7
|
+
export declare function exitCodeForRtlAuditResult(result: RtlAuditResult): number;
|
|
8
|
+
/**
|
|
9
|
+
* Machine-readable RTL audit summary for `--json`.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.5.0-canary.6
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatRtlAuditJsonOutput(result: RtlAuditResult, rootDir: string): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CLI_EXIT_GENERAL_ERROR, CLI_EXIT_SUCCESS } from "#core/exit-codes";
|
|
2
|
+
/**
|
|
3
|
+
* Exit `1` when any non-allowlisted violation remains.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.5.0-canary.6
|
|
6
|
+
*/
|
|
7
|
+
export function exitCodeForRtlAuditResult(result) {
|
|
8
|
+
return result.violationCount > 0 ? CLI_EXIT_GENERAL_ERROR : CLI_EXIT_SUCCESS;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Machine-readable RTL audit summary for `--json`.
|
|
12
|
+
*
|
|
13
|
+
* @since 0.5.0-canary.6
|
|
14
|
+
*/
|
|
15
|
+
export function formatRtlAuditJsonOutput(result, rootDir) {
|
|
16
|
+
return JSON.stringify({
|
|
17
|
+
schemaVersion: 1,
|
|
18
|
+
ok: result.violationCount === 0,
|
|
19
|
+
cwd: rootDir,
|
|
20
|
+
result,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Resolved request for a single RTL audit run.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.5.0-canary.6
|
|
6
|
+
*/
|
|
7
|
+
export type RtlAuditRunRequest = {
|
|
8
|
+
readonly rootDir: string;
|
|
9
|
+
readonly targetPath: string;
|
|
10
|
+
readonly allowlist?: ReadonlyArray<string> | undefined;
|
|
11
|
+
readonly json: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Zod schema for {@link RtlAuditRunRequest}.
|
|
15
|
+
*
|
|
16
|
+
* @since 0.5.0-canary.6
|
|
17
|
+
*/
|
|
18
|
+
export declare const rtlAuditRunRequestSchema: z.ZodType<RtlAuditRunRequest>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for {@link RtlAuditRunRequest}.
|
|
4
|
+
*
|
|
5
|
+
* @since 0.5.0-canary.6
|
|
6
|
+
*/
|
|
7
|
+
export const rtlAuditRunRequestSchema = z.object({
|
|
8
|
+
rootDir: z.string().min(1),
|
|
9
|
+
targetPath: z.string().min(1),
|
|
10
|
+
allowlist: z.array(z.string()).optional(),
|
|
11
|
+
json: z.boolean(),
|
|
12
|
+
});
|