@crossplatformai/dependency-graph 0.9.4 → 0.11.0-next.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/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/pr-preview.d.ts +5 -0
- package/dist/cli/pr-preview.d.ts.map +1 -0
- package/dist/cli/validate-workflows.d.ts +3 -0
- package/dist/cli/validate-workflows.d.ts.map +1 -0
- package/dist/graph/analysis.d.ts +6 -0
- package/dist/graph/analysis.d.ts.map +1 -0
- package/dist/graph/builder.d.ts +3 -0
- package/dist/graph/builder.d.ts.map +1 -0
- package/dist/graph/traversal.d.ts +5 -0
- package/dist/graph/traversal.d.ts.map +1 -0
- package/dist/graph/types.d.ts +47 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/index-cli.js +1172 -0
- package/dist/index-cli.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +791 -0
- package/dist/index.js.map +1 -0
- package/dist/types/clients.d.ts +15 -0
- package/dist/types/clients.d.ts.map +1 -0
- package/dist/workflow/discovery.d.ts +4 -0
- package/dist/workflow/discovery.d.ts.map +1 -0
- package/dist/workflow/expected-paths.d.ts +13 -0
- package/dist/workflow/expected-paths.d.ts.map +1 -0
- package/dist/workflow/impact.d.ts +5 -0
- package/dist/workflow/impact.d.ts.map +1 -0
- package/dist/workflow/parser.d.ts +3 -0
- package/dist/workflow/parser.d.ts.map +1 -0
- package/dist/workflow/policy.d.ts +3 -0
- package/dist/workflow/policy.d.ts.map +1 -0
- package/dist/workflow/types.d.ts +41 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/validator.d.ts +3 -0
- package/dist/workflow/validator.d.ts.map +1 -0
- package/dist/workspace/discovery.d.ts +12 -0
- package/dist/workspace/discovery.d.ts.map +1 -0
- package/dist/workspace/file-mapping.d.ts +4 -0
- package/dist/workspace/file-mapping.d.ts.map +1 -0
- package/dist/workspace/package-map.d.ts +12 -0
- package/dist/workspace/package-map.d.ts.map +1 -0
- package/package.json +33 -28
- package/src/cli/pr-preview.ts +0 -388
- package/src/cli/validate-workflows.ts +0 -287
- package/src/graph/analysis.ts +0 -147
- package/src/graph/builder.ts +0 -52
- package/src/graph/traversal.ts +0 -132
- package/src/graph/types.ts +0 -50
- package/src/index.test.ts +0 -94
- package/src/index.ts +0 -51
- package/src/types/clients.ts +0 -19
- package/src/workflow/discovery.ts +0 -58
- package/src/workflow/expected-paths.ts +0 -112
- package/src/workflow/parser.test.ts +0 -54
- package/src/workflow/parser.ts +0 -48
- package/src/workflow/policy.ts +0 -13
- package/src/workflow/types.ts +0 -42
- package/src/workflow/validator.test.ts +0 -214
- package/src/workflow/validator.ts +0 -230
- package/src/workspace/discovery.ts +0 -94
- package/src/workspace/file-mapping.ts +0 -35
- package/src/workspace/package-map.test.ts +0 -95
- package/src/workspace/package-map.ts +0 -74
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { join, resolve } from 'node:path';
|
|
2
|
-
import type { WorkspacePackage } from '../graph/types';
|
|
3
|
-
import type {
|
|
4
|
-
FileSystemClient,
|
|
5
|
-
GlobClient,
|
|
6
|
-
YamlClient,
|
|
7
|
-
} from '../types/clients';
|
|
8
|
-
|
|
9
|
-
export interface WorkspaceConfig {
|
|
10
|
-
packages: string[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface WorkspaceDiscoveryConfig {
|
|
14
|
-
fs: FileSystemClient;
|
|
15
|
-
glob: GlobClient;
|
|
16
|
-
yaml: YamlClient;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function discoverWorkspaces(
|
|
20
|
-
rootDir: string,
|
|
21
|
-
config: WorkspaceDiscoveryConfig,
|
|
22
|
-
): Promise<WorkspacePackage[]> {
|
|
23
|
-
const workspaceConfig = await loadWorkspaceConfig(rootDir, config);
|
|
24
|
-
const packages: WorkspacePackage[] = [];
|
|
25
|
-
|
|
26
|
-
for (const pattern of workspaceConfig.packages) {
|
|
27
|
-
if (pattern.startsWith('!')) continue;
|
|
28
|
-
|
|
29
|
-
const pkgDirs = await findPackageDirectories(rootDir, pattern, config);
|
|
30
|
-
|
|
31
|
-
for (const pkgDir of pkgDirs) {
|
|
32
|
-
const pkgJsonPath = join(pkgDir, 'package.json');
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const pkgJsonContent: string = await config.fs.readFile(
|
|
36
|
-
pkgJsonPath,
|
|
37
|
-
'utf-8',
|
|
38
|
-
);
|
|
39
|
-
const pkgJson = JSON.parse(pkgJsonContent) as {
|
|
40
|
-
name: string;
|
|
41
|
-
version?: string;
|
|
42
|
-
dependencies?: Record<string, string>;
|
|
43
|
-
devDependencies?: Record<string, string>;
|
|
44
|
-
[key: string]: unknown;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
packages.push({
|
|
48
|
-
name: pkgJson.name,
|
|
49
|
-
version: pkgJson.version || '0.0.0',
|
|
50
|
-
path: pkgDir,
|
|
51
|
-
packageJson: pkgJson,
|
|
52
|
-
dependencies: pkgJson.dependencies || {},
|
|
53
|
-
devDependencies: pkgJson.devDependencies || {},
|
|
54
|
-
});
|
|
55
|
-
} catch {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return packages;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function loadWorkspaceConfig(
|
|
65
|
-
rootDir: string,
|
|
66
|
-
config: WorkspaceDiscoveryConfig,
|
|
67
|
-
): Promise<WorkspaceConfig> {
|
|
68
|
-
const workspaceFilePath = join(rootDir, 'pnpm-workspace.yaml');
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const content: string = await config.fs.readFile(
|
|
72
|
-
workspaceFilePath,
|
|
73
|
-
'utf-8',
|
|
74
|
-
);
|
|
75
|
-
const parsed = config.yaml.parse(content) as WorkspaceConfig;
|
|
76
|
-
return parsed;
|
|
77
|
-
} catch {
|
|
78
|
-
return { packages: [] };
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function findPackageDirectories(
|
|
83
|
-
rootDir: string,
|
|
84
|
-
pattern: string,
|
|
85
|
-
config: WorkspaceDiscoveryConfig,
|
|
86
|
-
): Promise<string[]> {
|
|
87
|
-
const matches: string[] = await config.glob.glob(pattern, {
|
|
88
|
-
cwd: rootDir,
|
|
89
|
-
absolute: false,
|
|
90
|
-
ignore: ['**/node_modules/**', '**/.next/**', '**/dist/**'],
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return matches.map((match: string) => resolve(rootDir, match));
|
|
94
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { WorkspacePackage } from '../graph/types';
|
|
2
|
-
|
|
3
|
-
export function findPackageForFile(
|
|
4
|
-
filePath: string,
|
|
5
|
-
packages: WorkspacePackage[],
|
|
6
|
-
): WorkspacePackage | undefined {
|
|
7
|
-
const sorted = packages.sort((a, b) => b.path.length - a.path.length);
|
|
8
|
-
|
|
9
|
-
for (const pkg of sorted) {
|
|
10
|
-
if (filePath.startsWith(pkg.path + '/') || filePath === pkg.path) {
|
|
11
|
-
return pkg;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function mapFilesToPackages(
|
|
19
|
-
files: string[],
|
|
20
|
-
packages: WorkspacePackage[],
|
|
21
|
-
): Map<string, string[]> {
|
|
22
|
-
const fileMap = new Map<string, string[]>();
|
|
23
|
-
|
|
24
|
-
for (const file of files) {
|
|
25
|
-
const pkg = findPackageForFile(file, packages);
|
|
26
|
-
if (pkg) {
|
|
27
|
-
if (!fileMap.has(pkg.name)) {
|
|
28
|
-
fileMap.set(pkg.name, []);
|
|
29
|
-
}
|
|
30
|
-
fileMap.get(pkg.name)!.push(file);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return fileMap;
|
|
35
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import type { WorkspacePackage } from '../graph/types';
|
|
6
|
-
import { buildPackageMap } from './package-map';
|
|
7
|
-
|
|
8
|
-
const tempDirs: string[] = [];
|
|
9
|
-
|
|
10
|
-
function createTempRepo(): string {
|
|
11
|
-
const tempBaseDir = mkdtempSync(
|
|
12
|
-
join(tmpdir(), 'dependency-graph-package-map-'),
|
|
13
|
-
);
|
|
14
|
-
tempDirs.push(tempBaseDir);
|
|
15
|
-
const rootDir = join(tempBaseDir, 'repo');
|
|
16
|
-
mkdirSync(rootDir, { recursive: true });
|
|
17
|
-
return rootDir;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function createWorkspacePackage(path: string, name: string): WorkspacePackage {
|
|
21
|
-
return {
|
|
22
|
-
name,
|
|
23
|
-
version: '0.0.0',
|
|
24
|
-
path,
|
|
25
|
-
packageJson: { name },
|
|
26
|
-
dependencies: {},
|
|
27
|
-
devDependencies: {},
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
for (const dir of tempDirs.splice(0)) {
|
|
33
|
-
rmSync(dir, { recursive: true, force: true });
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe('buildPackageMap', () => {
|
|
38
|
-
it('keeps in-repo workspace paths as workflow paths', () => {
|
|
39
|
-
const rootDir = createTempRepo();
|
|
40
|
-
const packageDir = join(rootDir, 'apps/web');
|
|
41
|
-
mkdirSync(packageDir, { recursive: true });
|
|
42
|
-
|
|
43
|
-
const { packageMap, workspaceRoots } = buildPackageMap(
|
|
44
|
-
[createWorkspacePackage(packageDir, 'web')],
|
|
45
|
-
rootDir,
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
expect(packageMap.get('web')).toEqual({
|
|
49
|
-
filesystemPath: 'apps/web',
|
|
50
|
-
workflowPath: 'apps/web',
|
|
51
|
-
});
|
|
52
|
-
expect(Array.from(workspaceRoots)).toEqual(['apps']);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('rebases external workspace paths to in-repo mirrors', () => {
|
|
56
|
-
const rootDir = createTempRepo();
|
|
57
|
-
mkdirSync(join(rootDir, 'plugins/design-system'), { recursive: true });
|
|
58
|
-
const externalPackageDir = join(
|
|
59
|
-
rootDir,
|
|
60
|
-
'../crossplatform.ai/plugins/design-system',
|
|
61
|
-
);
|
|
62
|
-
mkdirSync(externalPackageDir, { recursive: true });
|
|
63
|
-
|
|
64
|
-
const { packageMap, workspaceRoots } = buildPackageMap(
|
|
65
|
-
[createWorkspacePackage(externalPackageDir, '@repo/design-system')],
|
|
66
|
-
rootDir,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
expect(packageMap.get('@repo/design-system')).toEqual({
|
|
70
|
-
filesystemPath: '../crossplatform.ai/plugins/design-system',
|
|
71
|
-
workflowPath: 'plugins/design-system',
|
|
72
|
-
});
|
|
73
|
-
expect(Array.from(workspaceRoots)).toEqual(['plugins']);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('skips workflow paths for external workspaces without local mirrors', () => {
|
|
77
|
-
const rootDir = createTempRepo();
|
|
78
|
-
const externalPackageDir = join(
|
|
79
|
-
rootDir,
|
|
80
|
-
'../crossplatform.ai/plugins/ghost',
|
|
81
|
-
);
|
|
82
|
-
mkdirSync(externalPackageDir, { recursive: true });
|
|
83
|
-
|
|
84
|
-
const { packageMap, workspaceRoots } = buildPackageMap(
|
|
85
|
-
[createWorkspacePackage(externalPackageDir, '@repo/ghost')],
|
|
86
|
-
rootDir,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
expect(packageMap.get('@repo/ghost')).toEqual({
|
|
90
|
-
filesystemPath: '../crossplatform.ai/plugins/ghost',
|
|
91
|
-
workflowPath: null,
|
|
92
|
-
});
|
|
93
|
-
expect(Array.from(workspaceRoots)).toEqual([]);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join, relative, sep } from 'node:path';
|
|
3
|
-
import type { WorkspacePackage } from '../graph/types';
|
|
4
|
-
|
|
5
|
-
export interface MappedWorkspacePath {
|
|
6
|
-
filesystemPath: string;
|
|
7
|
-
workflowPath: string | null;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface WorkspacePackageMap {
|
|
11
|
-
packageMap: Map<string, MappedWorkspacePath>;
|
|
12
|
-
workspaceRoots: Set<string>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function normalizeRelativePath(path: string): string {
|
|
16
|
-
return path.split(sep).join('/');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function resolveWorkflowPath(
|
|
20
|
-
relativePath: string,
|
|
21
|
-
rootDir: string,
|
|
22
|
-
): string | null {
|
|
23
|
-
if (!relativePath.startsWith('../')) {
|
|
24
|
-
return relativePath;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const segments = relativePath.split('/');
|
|
28
|
-
|
|
29
|
-
for (let index = 0; index < segments.length; index += 1) {
|
|
30
|
-
const candidateSegments = segments.slice(index);
|
|
31
|
-
if (candidateSegments.length === 0 || candidateSegments[0] === '..') {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const candidatePath = candidateSegments.join('/');
|
|
36
|
-
if (existsSync(join(rootDir, candidatePath))) {
|
|
37
|
-
return candidatePath;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function buildPackageMap(
|
|
45
|
-
packages: WorkspacePackage[],
|
|
46
|
-
rootDir: string,
|
|
47
|
-
): WorkspacePackageMap {
|
|
48
|
-
const packageMap = new Map<string, MappedWorkspacePath>();
|
|
49
|
-
const workspaceRoots = new Set<string>();
|
|
50
|
-
|
|
51
|
-
for (const pkg of packages) {
|
|
52
|
-
const relativePath = normalizeRelativePath(relative(rootDir, pkg.path));
|
|
53
|
-
const workflowPath = resolveWorkflowPath(relativePath, rootDir);
|
|
54
|
-
|
|
55
|
-
packageMap.set(pkg.name, {
|
|
56
|
-
filesystemPath: relativePath,
|
|
57
|
-
workflowPath,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (!workflowPath) {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const [workspaceRoot] = workflowPath.split('/');
|
|
65
|
-
if (workspaceRoot) {
|
|
66
|
-
workspaceRoots.add(workspaceRoot);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
packageMap,
|
|
72
|
-
workspaceRoots,
|
|
73
|
-
};
|
|
74
|
-
}
|