This repository was archived by the owner on Jul 29, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlist-exports.ts
118 lines (95 loc) · 3.72 KB
/
list-exports.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { existsSync, promises as fs } from 'fs';
import { forEach, groupBy, isUndefined, map, uniq } from 'lodash';
import * as path from 'path';
import { ExportSpecifier, Node, Project as TsProject } from 'ts-morph';
const basePath = path.resolve('../ngxp-demo/');
run();
async function run() {
const tsProject = new TsProject({
tsConfigFilePath: path.join(basePath, 'tsconfig.json')
});
const workspace = await readWorkspace(path.join(basePath, 'angular.json'));
getProjects(workspace)
.map(getTsConfigPath)
.filter(tsConfigPath => existsSync(tsConfigPath))
.forEach(tsConfigPath => tsProject.addSourceFilesFromTsConfig(tsConfigPath));
const symbols = getLibraryBarrelFilePaths(workspace)
.map(barrelFilePath => tsProject.getSourceFile(barrelFilePath)!)
.filter(file => !isUndefined(file))
.flatMap(file => file.getExportSymbols().map(symbol => ({
project: getProjectName(workspace, file.getFilePath()),
symbol: symbol.getName(),
referencingProjects: uniq(symbol.getDeclarations()
.flatMap(declaration => {
if (declaration instanceof ExportSpecifier) {
return declaration.getSymbol()!.getAliasedSymbol()!.getDeclarations()
} else {
return [declaration];
}
})
.flatMap(declaration => {
if (!Node.isReferenceFindableNode(declaration)) {
return [];
}
return declaration.findReferencesAsNodes()
.map(node => getProjectName(workspace, node.getSourceFile().getFilePath()))
}))
.filter(project => project !== getProjectName(workspace, file.getFilePath()))
})));
forEach(
groupBy(symbols, 'project'),
(symbols, project) => console.log(`${project}:\n${symbols.map(({ symbol, referencingProjects }) => ` ${symbol} (${referencingProjects.join(', ')})`).join('\n')}`)
)
}
interface Workspace {
projects: {
[key: string]: ProjectDeclaration
}
}
interface ProjectDeclaration {
root: string;
sourceRoot: string;
projectType: ProjectType;
}
interface Project extends ProjectDeclaration {
name: string;
}
enum ProjectType {
Application = 'application',
Library = 'library'
}
async function readWorkspace(path: string): Promise<Workspace> {
return JSON.parse(await fs.readFile(path, 'utf-8'));
}
function getProjectName(workspace: Workspace, filePath: string) {
const matchingProject = getProjects(workspace)
.find(project => toRelativePath(filePath).startsWith(project.sourceRoot))
if (isUndefined(matchingProject)) {
throw Error(`Cannot find library for file ${filePath}.`)
}
return matchingProject.name;
}
function getLibraryBarrelFilePaths(workspace: Workspace) {
return getLibraries(workspace)
.map(library => path.join(basePath, library.sourceRoot, 'index.ts'));
}
function getLibraries(workspace: Workspace): Project[] {
return getProjects(workspace)
.filter(project => project.projectType === ProjectType.Library)
}
function getProjects(workspace: Workspace): Project[] {
return map(workspace.projects, (project, name) => ({
name,
...project
}))
}
function getTsConfigPath({ projectType, root }: Project) {
const fileNameMapping = {
[ProjectType.Application]: 'tsconfig.app.json',
[ProjectType.Library]: 'tsconfig.lib.json'
}
return path.join(basePath, root, fileNameMapping[projectType])
}
function toRelativePath(filePath: string) {
return path.relative(basePath, filePath).replace(/\\/g, '/');
}