@ontrails/warden 1.0.0-beta.30 → 1.0.0-beta.39
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 +105 -0
- package/README.md +23 -1
- package/bin/warden.ts +1 -0
- package/package.json +9 -9
- package/src/cli.ts +160 -14
- package/src/command.ts +48 -5
- package/src/config.ts +9 -0
- package/src/drift.ts +116 -7
- package/src/fix.ts +8 -2
- package/src/formatters.ts +3 -8
- package/src/index.ts +32 -2
- package/src/project-context.ts +286 -3
- package/src/rules/ast.ts +4 -0
- package/src/rules/duplicate-exported-symbol.ts +211 -0
- package/src/rules/duplicate-public-contract.ts +2 -1
- package/src/rules/governed-symbol-residue.ts +131 -0
- package/src/rules/implementation-returns-result.ts +1 -3
- package/src/rules/index.ts +44 -3
- package/src/rules/metadata.ts +108 -14
- package/src/rules/no-legacy-cli-alias-export.ts +247 -0
- package/src/rules/no-retired-cross-vocabulary.ts +19 -9
- package/src/rules/permit-governance.ts +1 -1
- package/src/rules/public-export-example-coverage.ts +5 -0
- package/src/rules/public-internal-deep-imports.ts +3 -63
- package/src/rules/registry-names.ts +12 -2
- package/src/rules/retired-vocabulary.ts +396 -0
- package/src/rules/signal-graph-coaching.ts +32 -3
- package/src/rules/surface-overlay-coherence.ts +262 -0
- package/src/rules/{surface-facet-coherence.ts → surface-trailhead-coherence.ts} +46 -42
- package/src/rules/trail-fork-coaching.ts +1 -1
- package/src/rules/trailhead-override-divergence.ts +356 -0
- package/src/rules/types.ts +84 -4
- package/src/rules/webhook-route-collision.ts +64 -1
- package/src/trails/duplicate-exported-symbol.trail.ts +48 -0
- package/src/trails/duplicate-public-contract.trail.ts +1 -1
- package/src/trails/governed-symbol-residue.trail.ts +24 -0
- package/src/trails/index.ts +6 -1
- package/src/trails/no-legacy-cli-alias-export.trail.ts +41 -0
- package/src/trails/schema.ts +39 -0
- package/src/trails/surface-overlay-coherence.trail.ts +24 -0
- package/src/trails/{surface-facet-coherence.trail.ts → surface-trailhead-coherence.trail.ts} +5 -5
- package/src/trails/trail-fork-coaching.trail.ts +1 -1
- package/src/trails/trailhead-override-divergence.trail.ts +47 -0
- package/src/trails/wrap-rule.ts +10 -0
- package/src/workspaces.ts +30 -69
package/src/trails/index.ts
CHANGED
|
@@ -10,10 +10,12 @@ export { deprecationWithoutGuidanceTrail } from './deprecation-without-guidance.
|
|
|
10
10
|
export { duplicatePublicContractTrail } from './duplicate-public-contract.trail.js';
|
|
11
11
|
export { draftFileMarkingTrail } from './draft-file-marking.trail.js';
|
|
12
12
|
export { draftVisibleDebtTrail } from './draft-visible-debt.trail.js';
|
|
13
|
+
export { duplicateExportedSymbolTrail } from './duplicate-exported-symbol.trail.js';
|
|
13
14
|
export { errorMappingCompletenessTrail } from './error-mapping-completeness.trail.js';
|
|
14
15
|
export { exampleValidTrail } from './example-valid.trail.js';
|
|
15
16
|
export { firesDeclarationsTrail } from './fires-declarations.trail.js';
|
|
16
17
|
export { forkWithoutPreservedBlazeTrail } from './fork-without-preserved-blaze.trail.js';
|
|
18
|
+
export { governedSymbolResidueTrail } from './governed-symbol-residue.trail.js';
|
|
17
19
|
export { implementationReturnsResultTrail } from './implementation-returns-result.trail.js';
|
|
18
20
|
export { incompleteAccessorForStandardOpTrail } from './incomplete-accessor-for-standard-op.trail.js';
|
|
19
21
|
export { incompleteCrudTrail } from './incomplete-crud.trail.js';
|
|
@@ -26,6 +28,7 @@ export { missingReconcileTrail } from './missing-reconcile.trail.js';
|
|
|
26
28
|
export { onReferencesExistTrail } from './on-references-exist.trail.js';
|
|
27
29
|
export { noDevPermitInSourceTrail } from './no-dev-permit-in-source.trail.js';
|
|
28
30
|
export { noDestructuredComposeTrail } from './no-destructured-compose.trail.js';
|
|
31
|
+
export { noLegacyCliAliasExportTrail } from './no-legacy-cli-alias-export.trail.js';
|
|
29
32
|
export { noLegacyLayerImportsTrail } from './no-legacy-layer-imports.trail.js';
|
|
30
33
|
export { noDirectImplementationCallTrail } from './no-direct-implementation-call.trail.js';
|
|
31
34
|
export { noNativeErrorResultTrail } from './no-native-error-result.trail.js';
|
|
@@ -54,8 +57,10 @@ export { resourceMockCoverageTrail } from './resource-mock-coverage.trail.js';
|
|
|
54
57
|
export { scheduledDestroyIntentTrail } from './scheduled-destroy-intent.trail.js';
|
|
55
58
|
export { signalGraphCoachingTrail } from './signal-graph-coaching.trail.js';
|
|
56
59
|
export { staticResourceAccessorPreferenceTrail } from './static-resource-accessor-preference.trail.js';
|
|
57
|
-
export {
|
|
60
|
+
export { surfaceOverlayCoherenceTrail } from './surface-overlay-coherence.trail.js';
|
|
61
|
+
export { surfaceTrailheadCoherenceTrail } from './surface-trailhead-coherence.trail.js';
|
|
58
62
|
export { trailForkCoachingTrail } from './trail-fork-coaching.trail.js';
|
|
63
|
+
export { trailheadOverrideDivergenceTrail } from './trailhead-override-divergence.trail.js';
|
|
59
64
|
export { unmaterializedActivationSourceTrail } from './unmaterialized-activation-source.trail.js';
|
|
60
65
|
export { unreachableDetourShadowingTrail } from './unreachable-detour-shadowing.trail.js';
|
|
61
66
|
export { validDetourContractTrail } from './valid-detour-contract.trail.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { noLegacyCliAliasExport } from '../rules/no-legacy-cli-alias-export.js';
|
|
2
|
+
import { wrapRule } from './wrap-rule.js';
|
|
3
|
+
|
|
4
|
+
export const noLegacyCliAliasExportTrail = wrapRule({
|
|
5
|
+
examples: [
|
|
6
|
+
{
|
|
7
|
+
expected: { diagnostics: [] },
|
|
8
|
+
input: {
|
|
9
|
+
filePath: 'apps/example/src/app.ts',
|
|
10
|
+
sourceCode: `import { surfaceOverlay } from '@ontrails/core';\n\nexport const trailsOverlays = [surfaceOverlay({ cli: { ls: 'gear.list' } })];\n`,
|
|
11
|
+
},
|
|
12
|
+
name: 'App modules binding CLI through trailsOverlays are clean',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
expected: {
|
|
16
|
+
diagnostics: [
|
|
17
|
+
{
|
|
18
|
+
filePath: 'apps/example/src/app.ts',
|
|
19
|
+
fix: {
|
|
20
|
+
class: 'export-restructure',
|
|
21
|
+
reason:
|
|
22
|
+
"Legacy CLI alias export 'trailsCliAliases' must be rewritten into a surfaceOverlay({ cli: { ... } }) entry inside the module's trailsOverlays array export; run the Regrade class export-restructure:cli-aliases (TRL-1210) to automate this restructure.",
|
|
23
|
+
safety: 'review',
|
|
24
|
+
},
|
|
25
|
+
line: 1,
|
|
26
|
+
message:
|
|
27
|
+
"Legacy CLI alias export 'trailsCliAliases' was removed in the TRL-1207 surfaces-overlay cutover. Wrap the alias map into surfaceOverlay({ cli: { ... } }) from @ontrails/core inside the module's trailsOverlays array export.",
|
|
28
|
+
rule: 'no-legacy-cli-alias-export',
|
|
29
|
+
severity: 'error',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
input: {
|
|
34
|
+
filePath: 'apps/example/src/app.ts',
|
|
35
|
+
sourceCode: `export const trailsCliAliases = { 'gear.ls': [['gear', 'ls']] };\n`,
|
|
36
|
+
},
|
|
37
|
+
name: 'Legacy CLI alias exports produce migration diagnostics',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
rule: noLegacyCliAliasExport,
|
|
41
|
+
});
|
package/src/trails/schema.ts
CHANGED
|
@@ -85,13 +85,48 @@ export const publicWorkspaceSchema = z.object({
|
|
|
85
85
|
rootDir: z.string(),
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
export const exportedSymbolDefinitionSchema = z.object({
|
|
89
|
+
filePath: z.string(),
|
|
90
|
+
kind: z.enum([
|
|
91
|
+
'class',
|
|
92
|
+
'const',
|
|
93
|
+
'enum',
|
|
94
|
+
'export',
|
|
95
|
+
'function',
|
|
96
|
+
'interface',
|
|
97
|
+
'type',
|
|
98
|
+
]),
|
|
99
|
+
line: z.number(),
|
|
100
|
+
name: z.string(),
|
|
101
|
+
workspaceName: z.string(),
|
|
102
|
+
workspaceRoot: z.string(),
|
|
103
|
+
});
|
|
104
|
+
|
|
88
105
|
/**
|
|
89
106
|
* Extended input for project-aware warden rule trails.
|
|
90
107
|
*
|
|
91
108
|
* Adds `knownTrailIds` so the caller can supply compose-file context and avoid
|
|
92
109
|
* false positives for `@see` references or compose-file contour relationships.
|
|
93
110
|
*/
|
|
111
|
+
export const authoredMcpSurfaceBindingSetSchema = z.object({
|
|
112
|
+
appName: z.string().describe('App/topo label the bindings were authored for'),
|
|
113
|
+
bindings: z
|
|
114
|
+
.record(z.string(), z.union([z.string(), z.array(z.string()).readonly()]))
|
|
115
|
+
.describe('Surfaces overlay mcp bindings: binding name to selector(s)'),
|
|
116
|
+
trailIds: z
|
|
117
|
+
.array(z.string())
|
|
118
|
+
.readonly()
|
|
119
|
+
.describe('Trail ids registered in the owning app topo'),
|
|
120
|
+
});
|
|
121
|
+
|
|
94
122
|
export const projectAwareRuleInput = ruleInput.extend({
|
|
123
|
+
authoredMcpSurfaceBindingSets: z
|
|
124
|
+
.array(authoredMcpSurfaceBindingSetSchema)
|
|
125
|
+
.readonly()
|
|
126
|
+
.optional()
|
|
127
|
+
.describe(
|
|
128
|
+
'Per-app authored surfaces overlay mcp bindings with owning-app trail ids'
|
|
129
|
+
),
|
|
95
130
|
composeTargetTrailIds: z
|
|
96
131
|
.array(z.string())
|
|
97
132
|
.optional()
|
|
@@ -114,6 +149,10 @@ export const projectAwareRuleInput = ruleInput.extend({
|
|
|
114
149
|
.record(z.string(), z.array(importResolutionSchema))
|
|
115
150
|
.optional()
|
|
116
151
|
.describe('Resolved docs/specifier facts keyed by documentation file path'),
|
|
152
|
+
exportedSymbolDefinitionsByName: z
|
|
153
|
+
.record(z.string(), z.array(exportedSymbolDefinitionSchema))
|
|
154
|
+
.optional()
|
|
155
|
+
.describe('Public exported symbol definitions grouped by exported name'),
|
|
117
156
|
importResolutionsByFile: z
|
|
118
157
|
.record(z.string(), z.array(importResolutionSchema))
|
|
119
158
|
.optional()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Result, topo, trail } from '@ontrails/core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
import { surfaceOverlayCoherence } from '../rules/surface-overlay-coherence.js';
|
|
5
|
+
import { wrapTopoRule } from './wrap-rule.js';
|
|
6
|
+
|
|
7
|
+
const listTrail = trail('gear.list', {
|
|
8
|
+
blaze: () => Result.ok([]),
|
|
9
|
+
input: z.object({}),
|
|
10
|
+
output: z.array(z.string()),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const surfaceOverlayCoherenceTrail = wrapTopoRule({
|
|
14
|
+
examples: [
|
|
15
|
+
{
|
|
16
|
+
expected: { diagnostics: [] },
|
|
17
|
+
input: {
|
|
18
|
+
topo: topo('surface-overlay-coherence', { listTrail }),
|
|
19
|
+
},
|
|
20
|
+
name: 'Topo without a serialized surfaces overlay stays quiet',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
rule: surfaceOverlayCoherence,
|
|
24
|
+
});
|
package/src/trails/{surface-facet-coherence.trail.ts → surface-trailhead-coherence.trail.ts}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { surfaceTrailheadCoherence } from '../rules/surface-trailhead-coherence.js';
|
|
2
2
|
import { wrapRule } from './wrap-rule.js';
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const surfaceTrailheadCoherenceTrail = wrapRule({
|
|
5
5
|
examples: [
|
|
6
6
|
{
|
|
7
7
|
expected: { diagnostics: [] },
|
|
8
8
|
input: {
|
|
9
9
|
filePath: 'mcp-options.ts',
|
|
10
|
-
sourceCode: `export const
|
|
10
|
+
sourceCode: `export const trailheads = {
|
|
11
11
|
inspect: {
|
|
12
12
|
description: "Inspect topo state.",
|
|
13
13
|
trails: ["survey", "survey.brief"],
|
|
@@ -18,8 +18,8 @@ export const surfaceFacetCoherenceTrail = wrapRule({
|
|
|
18
18
|
},
|
|
19
19
|
};`,
|
|
20
20
|
},
|
|
21
|
-
name: 'Reviewable
|
|
21
|
+
name: 'Reviewable trailhead map',
|
|
22
22
|
},
|
|
23
23
|
],
|
|
24
|
-
rule:
|
|
24
|
+
rule: surfaceTrailheadCoherence,
|
|
25
25
|
});
|
|
@@ -10,7 +10,7 @@ export const trailForkCoachingTrail = wrapRule({
|
|
|
10
10
|
filePath: 'users.ts',
|
|
11
11
|
line: 9,
|
|
12
12
|
message:
|
|
13
|
-
'Trail "users.manage" branches on input.action ("create", "delete"). This may be a trail fork hidden as a surface accommodation. If branches change semantics (intent, permits, errors, outputs, lifecycle, or side effects) or structure (selected trail identity), split them into distinct trails, a composing trail, or a
|
|
13
|
+
'Trail "users.manage" branches on input.action ("create", "delete"). This may be a trail fork hidden as a surface accommodation. If branches change semantics (intent, permits, errors, outputs, lifecycle, or side effects) or structure (selected trail identity), split them into distinct trails, a composing trail, or a trailhead that preserves member identity.',
|
|
14
14
|
rule: 'trail-fork-coaching',
|
|
15
15
|
severity: 'warn',
|
|
16
16
|
},
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { trailheadOverrideDivergence } from '../rules/trailhead-override-divergence.js';
|
|
2
|
+
import { wrapRule } from './wrap-rule.js';
|
|
3
|
+
|
|
4
|
+
export const trailheadOverrideDivergenceTrail = wrapRule({
|
|
5
|
+
examples: [
|
|
6
|
+
{
|
|
7
|
+
expected: { diagnostics: [] },
|
|
8
|
+
input: {
|
|
9
|
+
authoredMcpSurfaceBindingSets: [
|
|
10
|
+
{
|
|
11
|
+
appName: 'demo',
|
|
12
|
+
bindings: { inspect: ['survey', 'survey.brief'] },
|
|
13
|
+
trailIds: ['survey', 'survey.brief'],
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
filePath: 'mcp-options.ts',
|
|
17
|
+
sourceCode: `export const trailheads = {
|
|
18
|
+
inspect: {
|
|
19
|
+
description: "Inspect topo state.",
|
|
20
|
+
trails: ["survey", "survey.brief"],
|
|
21
|
+
},
|
|
22
|
+
};`,
|
|
23
|
+
},
|
|
24
|
+
name: 'Aligned call-site override',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
input: {
|
|
28
|
+
authoredMcpSurfaceBindingSets: [
|
|
29
|
+
{
|
|
30
|
+
appName: 'demo',
|
|
31
|
+
bindings: { inspect: ['survey', 'survey.brief'] },
|
|
32
|
+
trailIds: ['survey', 'survey.brief'],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
filePath: 'mcp-options.ts',
|
|
36
|
+
sourceCode: `export const trailheads = {
|
|
37
|
+
inspect: {
|
|
38
|
+
description: "Inspect topo state.",
|
|
39
|
+
trails: ["survey"],
|
|
40
|
+
},
|
|
41
|
+
};`,
|
|
42
|
+
},
|
|
43
|
+
name: 'Diverging member selectors are flagged',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
rule: trailheadOverrideDivergence,
|
|
47
|
+
});
|
package/src/trails/wrap-rule.ts
CHANGED
|
@@ -51,6 +51,9 @@ const buildRuleMeta = (rule: WardenRule | TopoAwareWardenRule) => {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
const buildProjectContext = (input: ProjectAwareRuleInput): ProjectContext => ({
|
|
54
|
+
...(input.authoredMcpSurfaceBindingSets
|
|
55
|
+
? { authoredMcpSurfaceBindingSets: input.authoredMcpSurfaceBindingSets }
|
|
56
|
+
: {}),
|
|
54
57
|
...(input.contourReferencesByName
|
|
55
58
|
? {
|
|
56
59
|
contourReferencesByName: new Map(
|
|
@@ -88,6 +91,13 @@ const buildProjectContext = (input: ProjectAwareRuleInput): ProjectContext => ({
|
|
|
88
91
|
),
|
|
89
92
|
}
|
|
90
93
|
: {}),
|
|
94
|
+
...(input.exportedSymbolDefinitionsByName
|
|
95
|
+
? {
|
|
96
|
+
exportedSymbolDefinitionsByName: new Map(
|
|
97
|
+
Object.entries(input.exportedSymbolDefinitionsByName)
|
|
98
|
+
),
|
|
99
|
+
}
|
|
100
|
+
: {}),
|
|
91
101
|
...(input.publicWorkspaces
|
|
92
102
|
? { publicWorkspaces: new Map(Object.entries(input.publicWorkspaces)) }
|
|
93
103
|
: {}),
|
package/src/workspaces.ts
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Workspace-manifest discovery for Warden project-aware rules.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { realpathSync } from 'node:fs';
|
|
6
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
import { listWorkspacePackages, matchesAnyPathGlob } from '@ontrails/core';
|
|
7
9
|
|
|
8
10
|
export interface WardenPublicWorkspace {
|
|
9
11
|
readonly name: string;
|
|
@@ -15,8 +17,8 @@ export interface WardenPublicWorkspace {
|
|
|
15
17
|
readonly files?: readonly string[] | undefined;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
interface
|
|
19
|
-
readonly
|
|
20
|
+
export interface WardenWorkspaceCollectionOptions {
|
|
21
|
+
readonly exclude?: readonly string[];
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
interface PackageManifest {
|
|
@@ -37,55 +39,12 @@ const normalizeRealPath = (path: string): string => {
|
|
|
37
39
|
}
|
|
38
40
|
};
|
|
39
41
|
|
|
42
|
+
const rootRelativePath = (rootDir: string, path: string): string =>
|
|
43
|
+
normalizePath(relative(rootDir, path));
|
|
44
|
+
|
|
40
45
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
41
46
|
Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
42
47
|
|
|
43
|
-
const readJson = <T>(path: string): T | undefined => {
|
|
44
|
-
try {
|
|
45
|
-
return JSON.parse(readFileSync(path, 'utf8')) as T;
|
|
46
|
-
} catch {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const workspacePatternsFromManifest = (
|
|
52
|
-
manifest: RootManifest | undefined
|
|
53
|
-
): readonly string[] => {
|
|
54
|
-
const { workspaces } = manifest ?? {};
|
|
55
|
-
if (Array.isArray(workspaces)) {
|
|
56
|
-
return workspaces.filter(
|
|
57
|
-
(pattern): pattern is string => typeof pattern === 'string'
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const packages = isRecord(workspaces) ? workspaces['packages'] : undefined;
|
|
62
|
-
return Array.isArray(packages)
|
|
63
|
-
? packages.filter(
|
|
64
|
-
(pattern): pattern is string => typeof pattern === 'string'
|
|
65
|
-
)
|
|
66
|
-
: [];
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const workspaceDirsForPattern = (
|
|
70
|
-
rootDir: string,
|
|
71
|
-
pattern: string
|
|
72
|
-
): readonly string[] => {
|
|
73
|
-
if (!pattern.endsWith('/*')) {
|
|
74
|
-
const workspaceDir = join(rootDir, pattern);
|
|
75
|
-
return existsSync(workspaceDir) ? [workspaceDir] : [];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const groupDir = join(rootDir, pattern.slice(0, -2));
|
|
79
|
-
if (!existsSync(groupDir)) {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return readdirSync(groupDir, { withFileTypes: true })
|
|
84
|
-
.filter((entry) => entry.isDirectory())
|
|
85
|
-
.map((entry) => join(groupDir, entry.name))
|
|
86
|
-
.toSorted();
|
|
87
|
-
};
|
|
88
|
-
|
|
89
48
|
const packageLocalName = (name: string): string =>
|
|
90
49
|
name.split('/').at(-1) ?? name;
|
|
91
50
|
|
|
@@ -208,29 +167,31 @@ const publicWorkspaceFromManifest = (
|
|
|
208
167
|
};
|
|
209
168
|
|
|
210
169
|
export const collectPublicWorkspaces = (
|
|
211
|
-
rootDir: string
|
|
170
|
+
rootDir: string,
|
|
171
|
+
options: WardenWorkspaceCollectionOptions = {}
|
|
212
172
|
): ReadonlyMap<string, WardenPublicWorkspace> => {
|
|
213
173
|
const normalizedRoot = normalizeRealPath(rootDir);
|
|
214
|
-
const rootManifest = readJson<RootManifest>(
|
|
215
|
-
join(normalizedRoot, 'package.json')
|
|
216
|
-
);
|
|
217
174
|
const workspaces = new Map<string, WardenPublicWorkspace>();
|
|
218
175
|
|
|
219
|
-
for (const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
176
|
+
for (const workspacePackage of listWorkspacePackages<PackageManifest>(
|
|
177
|
+
normalizedRoot
|
|
178
|
+
)) {
|
|
179
|
+
const workspace = publicWorkspaceFromManifest(
|
|
180
|
+
workspacePackage.packageJsonPath,
|
|
181
|
+
workspacePackage.manifest
|
|
182
|
+
);
|
|
183
|
+
if (
|
|
184
|
+
workspace &&
|
|
185
|
+
!matchesAnyPathGlob(
|
|
186
|
+
rootRelativePath(normalizedRoot, workspace.rootDir),
|
|
187
|
+
options.exclude ?? []
|
|
188
|
+
) &&
|
|
189
|
+
!matchesAnyPathGlob(
|
|
190
|
+
rootRelativePath(normalizedRoot, workspace.packageJsonPath),
|
|
191
|
+
options.exclude ?? []
|
|
192
|
+
)
|
|
193
|
+
) {
|
|
194
|
+
workspaces.set(workspace.name, workspace);
|
|
234
195
|
}
|
|
235
196
|
}
|
|
236
197
|
|