-
Notifications
You must be signed in to change notification settings - Fork 10
/
workspaces.js
134 lines (111 loc) · 3.67 KB
/
workspaces.js
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import path from 'path';
import yargs from 'yargs';
import glob from 'glob';
import micromatch from 'micromatch';
import appRoot from 'app-root-path';
import { Configuration, Project } from '@yarnpkg/core';
import { normalizePath } from './shared/utils.js';
const { argv } = yargs(process.argv.slice(2));
let PACKAGES;
const EXCLUDES = new Set();
const INCLUDES = new Set();
let PROJECTS;
let MAIN_PROJECT;
// defined private in typescript, not sure how to add workspace without it
// TODO extend class Project, can we use workspace cache from MAIN_PROJECT?
const addWorkspace = async (project, cwd) => project.addWorkspace(normalizePath(cwd));
export const getExcludes = () => [...EXCLUDES];
export const getIncludes = () => [...INCLUDES];
export async function setup() {
if (MAIN_PROJECT) return;
PACKAGES = (process.env.PACKAGES || '*').trim();
EXCLUDES.clear();
INCLUDES.clear();
if (PACKAGES) {
PACKAGES.split(/\s*(?:,|\n|\s)+\s*/).forEach(pattern => {
if (pattern.startsWith('!')) {
EXCLUDES.add(pattern.substring(1));
} else {
INCLUDES.add(pattern);
}
});
}
const configuration = await Configuration.find(normalizePath(appRoot), null);
const { projectCwd } = configuration;
const project = new Project(projectCwd, { configuration });
await addWorkspace(project, projectCwd);
MAIN_PROJECT = project;
}
async function fetchWorkspaces() {
if (!MAIN_PROJECT) return;
const children = new Set();
/* eslint-disable no-restricted-syntax */
async function recursive(pending) {
if (!pending.length) return;
const tasks = [];
// TODO: refactor
for (const { cwd, manifest: { workspaceDefinitions } } of pending) {
for (const { pattern } of workspaceDefinitions) {
for (const workspaceCwd of glob.sync(path.resolve(cwd, pattern))) {
tasks.push(addWorkspace(MAIN_PROJECT, workspaceCwd)
.then(workspace => children.add(workspace)));
}
}
}
await Promise.all(tasks);
await recursive(children);
}
/* eslint-enable no-restricted-syntax */
await recursive(MAIN_PROJECT.workspaces);
}
export async function getProjects() {
if (PROJECTS) return PROJECTS;
await fetchWorkspaces();
const tasks = [];
const includes = getIncludes();
const excludes = getExcludes();
PROJECTS = new Map();
MAIN_PROJECT.workspaces.forEach(workspace => {
const { cwd, manifest } = workspace;
const { name: { name } } = manifest;
if (manifest.private) {
return;
}
const strings = [name, cwd.replace(`${appRoot}/`, '')];
if (micromatch.some(strings, includes) && !micromatch.some(strings, excludes)) {
let project;
if (MAIN_PROJECT.cwd === cwd) {
PROJECTS.set(cwd, MAIN_PROJECT);
} else {
tasks.push(new Promise(resolve => {
Configuration.find(cwd, null).then(configuration => {
project = new Project(cwd, { configuration });
addWorkspace(project, cwd).then(resolve);
PROJECTS.set(cwd, project);
});
}));
}
}
});
await Promise.all(tasks);
return PROJECTS;
}
export async function getPackageName(cwd) {
const projects = await getProjects();
const project = projects.get(cwd);
if (project) {
const { manifest: { name: { name, scope } } } = project.workspacesByCwd.get(cwd);
return scope ? `@${scope}/${name}` : name;
}
return null;
}
if (argv.lsPublic) {
await (setup());
await (getProjects());
const workspaces = [];
PROJECTS.forEach((project, cwd) => workspaces.push({
name: project.workspacesByCwd.get(cwd).manifest.name.name,
path: cwd,
}));
console.log(JSON.stringify(workspaces)); // eslint-disable-line no-console
}