@eslint-config-snapshot/api 1.0.0 → 1.1.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 +6 -0
- package/dist/index.cjs +104 -14
- package/dist/index.js +101 -11
- package/package.json +1 -1
- package/src/workspace.ts +112 -5
- package/test/workspace.test.ts +47 -1
package/CHANGELOG.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -104,27 +104,117 @@ function normalizeSeverity(value) {
|
|
|
104
104
|
|
|
105
105
|
// src/workspace.ts
|
|
106
106
|
var import_get_packages = require("@manypkg/get-packages");
|
|
107
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
108
|
+
var import_promises = require("fs/promises");
|
|
107
109
|
var import_node_path = __toESM(require("path"), 1);
|
|
108
110
|
var import_picomatch = __toESM(require("picomatch"), 1);
|
|
109
111
|
async function discoverWorkspaces(options) {
|
|
110
112
|
const cwd = options?.cwd ? import_node_path.default.resolve(options.cwd) : process.cwd();
|
|
111
113
|
const workspaceInput = options?.workspaceInput ?? { mode: "discover" };
|
|
112
114
|
if (workspaceInput.mode === "manual") {
|
|
113
|
-
const
|
|
115
|
+
const rootAbs = import_node_path.default.resolve(workspaceInput.rootAbs ?? cwd);
|
|
114
116
|
return {
|
|
115
|
-
rootAbs
|
|
117
|
+
rootAbs,
|
|
116
118
|
workspacesRel: sortUnique(workspaceInput.workspaces)
|
|
117
119
|
};
|
|
118
120
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
try {
|
|
122
|
+
const { rootDir, packages } = await (0, import_get_packages.getPackages)(cwd);
|
|
123
|
+
const workspacesAbs = packages.map((pkg) => pkg.dir);
|
|
124
|
+
const rootAbs = rootDir ? import_node_path.default.resolve(rootDir) : lowestCommonAncestor(workspacesAbs);
|
|
125
|
+
const workspacesRel = sortUnique(workspacesAbs.map((entry) => normalizePath(import_node_path.default.relative(rootAbs, entry))));
|
|
126
|
+
if (workspacesRel.length > 1 || workspacesRel.length === 1 && workspacesRel[0] !== ".") {
|
|
127
|
+
return {
|
|
128
|
+
rootAbs,
|
|
129
|
+
workspacesRel
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const packageJsonFallback2 = await discoverWorkspacesFromPackageJson(cwd);
|
|
133
|
+
if (packageJsonFallback2 && packageJsonFallback2.workspacesRel.length > 0) {
|
|
134
|
+
return packageJsonFallback2;
|
|
135
|
+
}
|
|
136
|
+
if (workspacesRel.length > 0) {
|
|
137
|
+
return {
|
|
138
|
+
rootAbs,
|
|
139
|
+
workspacesRel
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
const packageJsonFallback = await discoverWorkspacesFromPackageJson(cwd);
|
|
145
|
+
if (packageJsonFallback) {
|
|
146
|
+
return packageJsonFallback;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
rootAbs: cwd,
|
|
150
|
+
workspacesRel: ["."]
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function discoverWorkspacesFromPackageJson(cwd) {
|
|
154
|
+
const packageJsonPath = import_node_path.default.join(cwd, "package.json");
|
|
155
|
+
const packageJsonRaw = await safeReadFile(packageJsonPath);
|
|
156
|
+
if (!packageJsonRaw) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const parsed = safeJsonParse(packageJsonRaw);
|
|
160
|
+
if (!isObjectRecord(parsed) || Array.isArray(parsed)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const workspaceGlobs = extractWorkspaceGlobs(parsed);
|
|
164
|
+
if (workspaceGlobs.length === 0) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const workspacePackageJsonGlobs = workspaceGlobs.map((entry) => normalizePath(import_node_path.default.posix.join(entry, "package.json")));
|
|
168
|
+
const foundPackageJsonFiles = await (0, import_fast_glob.default)(workspacePackageJsonGlobs, {
|
|
169
|
+
cwd,
|
|
170
|
+
onlyFiles: true,
|
|
171
|
+
dot: true,
|
|
172
|
+
unique: true,
|
|
173
|
+
ignore: ["**/node_modules/**"]
|
|
174
|
+
});
|
|
175
|
+
const workspacesRel = sortUnique(foundPackageJsonFiles.map((entry) => normalizePath(import_node_path.default.posix.dirname(entry))));
|
|
176
|
+
if (workspacesRel.length === 0) {
|
|
177
|
+
return {
|
|
178
|
+
rootAbs: cwd,
|
|
179
|
+
workspacesRel: ["."]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
123
182
|
return {
|
|
124
|
-
rootAbs,
|
|
183
|
+
rootAbs: cwd,
|
|
125
184
|
workspacesRel
|
|
126
185
|
};
|
|
127
186
|
}
|
|
187
|
+
async function safeReadFile(filePath) {
|
|
188
|
+
try {
|
|
189
|
+
return await (0, import_promises.readFile)(filePath, "utf8");
|
|
190
|
+
} catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function safeJsonParse(raw) {
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(raw);
|
|
197
|
+
} catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function isObjectRecord(value) {
|
|
202
|
+
return value !== null && typeof value === "object";
|
|
203
|
+
}
|
|
204
|
+
function extractWorkspaceGlobs(packageJson) {
|
|
205
|
+
const workspaces = packageJson.workspaces;
|
|
206
|
+
if (Array.isArray(workspaces)) {
|
|
207
|
+
return workspaces.filter((entry) => typeof entry === "string");
|
|
208
|
+
}
|
|
209
|
+
if (!workspaces || typeof workspaces !== "object" || Array.isArray(workspaces)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
const packages = workspaces.packages;
|
|
213
|
+
if (Array.isArray(packages)) {
|
|
214
|
+
return packages.filter((entry) => typeof entry === "string");
|
|
215
|
+
}
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
128
218
|
function assignGroupsByMatch(workspacesRel, groups) {
|
|
129
219
|
const sortedWorkspaces = sortUnique([...workspacesRel]);
|
|
130
220
|
const assignments = /* @__PURE__ */ new Map();
|
|
@@ -186,11 +276,11 @@ function lowestCommonAncestor(paths) {
|
|
|
186
276
|
|
|
187
277
|
// src/sampling.ts
|
|
188
278
|
var import_debug = __toESM(require("debug"), 1);
|
|
189
|
-
var
|
|
279
|
+
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
190
280
|
var debugSampling = (0, import_debug.default)("eslint-config-snapshot:sampling");
|
|
191
281
|
async function sampleWorkspaceFiles(workspaceAbs, config) {
|
|
192
282
|
const startedAt = Date.now();
|
|
193
|
-
const all = await (0,
|
|
283
|
+
const all = await (0, import_fast_glob2.default)(config.includeGlobs, {
|
|
194
284
|
cwd: workspaceAbs,
|
|
195
285
|
ignore: config.excludeGlobs,
|
|
196
286
|
onlyFiles: true,
|
|
@@ -727,7 +817,7 @@ function normalizeRuleEntry(raw) {
|
|
|
727
817
|
}
|
|
728
818
|
|
|
729
819
|
// src/snapshot.ts
|
|
730
|
-
var
|
|
820
|
+
var import_promises2 = require("fs/promises");
|
|
731
821
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
732
822
|
function aggregateRules(ruleMaps) {
|
|
733
823
|
const aggregated = /* @__PURE__ */ new Map();
|
|
@@ -763,16 +853,16 @@ function buildSnapshot(groupId, workspaces, rules) {
|
|
|
763
853
|
};
|
|
764
854
|
}
|
|
765
855
|
async function writeSnapshotFile(snapshotDirAbs, snapshot) {
|
|
766
|
-
await (0,
|
|
856
|
+
await (0, import_promises2.mkdir)(snapshotDirAbs, { recursive: true });
|
|
767
857
|
const filePath = import_node_path3.default.join(snapshotDirAbs, `${snapshot.groupId}.json`);
|
|
768
|
-
await (0,
|
|
858
|
+
await (0, import_promises2.mkdir)(import_node_path3.default.dirname(filePath), { recursive: true });
|
|
769
859
|
const payload = JSON.stringify(snapshot, null, 2);
|
|
770
|
-
await (0,
|
|
860
|
+
await (0, import_promises2.writeFile)(filePath, `${payload}
|
|
771
861
|
`, "utf8");
|
|
772
862
|
return filePath;
|
|
773
863
|
}
|
|
774
864
|
async function readSnapshotFile(fileAbs) {
|
|
775
|
-
const raw = await (0,
|
|
865
|
+
const raw = await (0, import_promises2.readFile)(fileAbs, "utf8");
|
|
776
866
|
return JSON.parse(raw);
|
|
777
867
|
}
|
|
778
868
|
function toVariantKey(entry) {
|
package/dist/index.js
CHANGED
|
@@ -47,27 +47,117 @@ function normalizeSeverity(value) {
|
|
|
47
47
|
|
|
48
48
|
// src/workspace.ts
|
|
49
49
|
import { getPackages } from "@manypkg/get-packages";
|
|
50
|
+
import fg from "fast-glob";
|
|
51
|
+
import { readFile } from "fs/promises";
|
|
50
52
|
import path from "path";
|
|
51
53
|
import picomatch from "picomatch";
|
|
52
54
|
async function discoverWorkspaces(options) {
|
|
53
55
|
const cwd = options?.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
54
56
|
const workspaceInput = options?.workspaceInput ?? { mode: "discover" };
|
|
55
57
|
if (workspaceInput.mode === "manual") {
|
|
56
|
-
const
|
|
58
|
+
const rootAbs = path.resolve(workspaceInput.rootAbs ?? cwd);
|
|
57
59
|
return {
|
|
58
|
-
rootAbs
|
|
60
|
+
rootAbs,
|
|
59
61
|
workspacesRel: sortUnique(workspaceInput.workspaces)
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
try {
|
|
65
|
+
const { rootDir, packages } = await getPackages(cwd);
|
|
66
|
+
const workspacesAbs = packages.map((pkg) => pkg.dir);
|
|
67
|
+
const rootAbs = rootDir ? path.resolve(rootDir) : lowestCommonAncestor(workspacesAbs);
|
|
68
|
+
const workspacesRel = sortUnique(workspacesAbs.map((entry) => normalizePath(path.relative(rootAbs, entry))));
|
|
69
|
+
if (workspacesRel.length > 1 || workspacesRel.length === 1 && workspacesRel[0] !== ".") {
|
|
70
|
+
return {
|
|
71
|
+
rootAbs,
|
|
72
|
+
workspacesRel
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const packageJsonFallback2 = await discoverWorkspacesFromPackageJson(cwd);
|
|
76
|
+
if (packageJsonFallback2 && packageJsonFallback2.workspacesRel.length > 0) {
|
|
77
|
+
return packageJsonFallback2;
|
|
78
|
+
}
|
|
79
|
+
if (workspacesRel.length > 0) {
|
|
80
|
+
return {
|
|
81
|
+
rootAbs,
|
|
82
|
+
workspacesRel
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
const packageJsonFallback = await discoverWorkspacesFromPackageJson(cwd);
|
|
88
|
+
if (packageJsonFallback) {
|
|
89
|
+
return packageJsonFallback;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
rootAbs: cwd,
|
|
93
|
+
workspacesRel: ["."]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function discoverWorkspacesFromPackageJson(cwd) {
|
|
97
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
98
|
+
const packageJsonRaw = await safeReadFile(packageJsonPath);
|
|
99
|
+
if (!packageJsonRaw) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const parsed = safeJsonParse(packageJsonRaw);
|
|
103
|
+
if (!isObjectRecord(parsed) || Array.isArray(parsed)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const workspaceGlobs = extractWorkspaceGlobs(parsed);
|
|
107
|
+
if (workspaceGlobs.length === 0) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const workspacePackageJsonGlobs = workspaceGlobs.map((entry) => normalizePath(path.posix.join(entry, "package.json")));
|
|
111
|
+
const foundPackageJsonFiles = await fg(workspacePackageJsonGlobs, {
|
|
112
|
+
cwd,
|
|
113
|
+
onlyFiles: true,
|
|
114
|
+
dot: true,
|
|
115
|
+
unique: true,
|
|
116
|
+
ignore: ["**/node_modules/**"]
|
|
117
|
+
});
|
|
118
|
+
const workspacesRel = sortUnique(foundPackageJsonFiles.map((entry) => normalizePath(path.posix.dirname(entry))));
|
|
119
|
+
if (workspacesRel.length === 0) {
|
|
120
|
+
return {
|
|
121
|
+
rootAbs: cwd,
|
|
122
|
+
workspacesRel: ["."]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
66
125
|
return {
|
|
67
|
-
rootAbs,
|
|
126
|
+
rootAbs: cwd,
|
|
68
127
|
workspacesRel
|
|
69
128
|
};
|
|
70
129
|
}
|
|
130
|
+
async function safeReadFile(filePath) {
|
|
131
|
+
try {
|
|
132
|
+
return await readFile(filePath, "utf8");
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function safeJsonParse(raw) {
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(raw);
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function isObjectRecord(value) {
|
|
145
|
+
return value !== null && typeof value === "object";
|
|
146
|
+
}
|
|
147
|
+
function extractWorkspaceGlobs(packageJson) {
|
|
148
|
+
const workspaces = packageJson.workspaces;
|
|
149
|
+
if (Array.isArray(workspaces)) {
|
|
150
|
+
return workspaces.filter((entry) => typeof entry === "string");
|
|
151
|
+
}
|
|
152
|
+
if (!workspaces || typeof workspaces !== "object" || Array.isArray(workspaces)) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
const packages = workspaces.packages;
|
|
156
|
+
if (Array.isArray(packages)) {
|
|
157
|
+
return packages.filter((entry) => typeof entry === "string");
|
|
158
|
+
}
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
71
161
|
function assignGroupsByMatch(workspacesRel, groups) {
|
|
72
162
|
const sortedWorkspaces = sortUnique([...workspacesRel]);
|
|
73
163
|
const assignments = /* @__PURE__ */ new Map();
|
|
@@ -129,11 +219,11 @@ function lowestCommonAncestor(paths) {
|
|
|
129
219
|
|
|
130
220
|
// src/sampling.ts
|
|
131
221
|
import createDebug from "debug";
|
|
132
|
-
import
|
|
222
|
+
import fg2 from "fast-glob";
|
|
133
223
|
var debugSampling = createDebug("eslint-config-snapshot:sampling");
|
|
134
224
|
async function sampleWorkspaceFiles(workspaceAbs, config) {
|
|
135
225
|
const startedAt = Date.now();
|
|
136
|
-
const all = await
|
|
226
|
+
const all = await fg2(config.includeGlobs, {
|
|
137
227
|
cwd: workspaceAbs,
|
|
138
228
|
ignore: config.excludeGlobs,
|
|
139
229
|
onlyFiles: true,
|
|
@@ -670,7 +760,7 @@ function normalizeRuleEntry(raw) {
|
|
|
670
760
|
}
|
|
671
761
|
|
|
672
762
|
// src/snapshot.ts
|
|
673
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
763
|
+
import { mkdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
674
764
|
import path3 from "path";
|
|
675
765
|
function aggregateRules(ruleMaps) {
|
|
676
766
|
const aggregated = /* @__PURE__ */ new Map();
|
|
@@ -715,7 +805,7 @@ async function writeSnapshotFile(snapshotDirAbs, snapshot) {
|
|
|
715
805
|
return filePath;
|
|
716
806
|
}
|
|
717
807
|
async function readSnapshotFile(fileAbs) {
|
|
718
|
-
const raw = await
|
|
808
|
+
const raw = await readFile2(fileAbs, "utf8");
|
|
719
809
|
return JSON.parse(raw);
|
|
720
810
|
}
|
|
721
811
|
function toVariantKey(entry) {
|
package/package.json
CHANGED
package/src/workspace.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getPackages } from '@manypkg/get-packages'
|
|
2
|
+
import fg from 'fast-glob'
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
2
4
|
import path from 'node:path'
|
|
3
5
|
import picomatch from 'picomatch'
|
|
4
6
|
|
|
@@ -44,17 +46,122 @@ export async function discoverWorkspaces(options?: {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
try {
|
|
50
|
+
const { rootDir, packages } = await getPackages(cwd)
|
|
51
|
+
const workspacesAbs = packages.map((pkg) => pkg.dir)
|
|
52
|
+
const rootAbs = rootDir ? path.resolve(rootDir) : lowestCommonAncestor(workspacesAbs)
|
|
53
|
+
const workspacesRel = sortUnique(workspacesAbs.map((entry) => normalizePath(path.relative(rootAbs, entry))))
|
|
54
|
+
if (workspacesRel.length > 1 || (workspacesRel.length === 1 && workspacesRel[0] !== '.')) {
|
|
55
|
+
return {
|
|
56
|
+
rootAbs,
|
|
57
|
+
workspacesRel
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const packageJsonFallback = await discoverWorkspacesFromPackageJson(cwd)
|
|
62
|
+
if (packageJsonFallback && packageJsonFallback.workspacesRel.length > 0) {
|
|
63
|
+
return packageJsonFallback
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (workspacesRel.length > 0) {
|
|
67
|
+
return {
|
|
68
|
+
rootAbs,
|
|
69
|
+
workspacesRel
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// Fallback to package.json workspace patterns when package manager metadata is unavailable.
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const packageJsonFallback = await discoverWorkspacesFromPackageJson(cwd)
|
|
77
|
+
if (packageJsonFallback) {
|
|
78
|
+
return packageJsonFallback
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
rootAbs: cwd,
|
|
83
|
+
workspacesRel: ['.']
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function discoverWorkspacesFromPackageJson(cwd: string): Promise<WorkspaceDiscovery | null> {
|
|
88
|
+
const packageJsonPath = path.join(cwd, 'package.json')
|
|
89
|
+
const packageJsonRaw = await safeReadFile(packageJsonPath)
|
|
90
|
+
if (!packageJsonRaw) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const parsed = safeJsonParse(packageJsonRaw)
|
|
95
|
+
if (!isObjectRecord(parsed) || Array.isArray(parsed)) {
|
|
96
|
+
return null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const workspaceGlobs = extractWorkspaceGlobs(parsed)
|
|
100
|
+
if (workspaceGlobs.length === 0) {
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const workspacePackageJsonGlobs = workspaceGlobs.map((entry) => normalizePath(path.posix.join(entry, 'package.json')))
|
|
105
|
+
const foundPackageJsonFiles = await fg(workspacePackageJsonGlobs, {
|
|
106
|
+
cwd,
|
|
107
|
+
onlyFiles: true,
|
|
108
|
+
dot: true,
|
|
109
|
+
unique: true,
|
|
110
|
+
ignore: ['**/node_modules/**']
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const workspacesRel = sortUnique(foundPackageJsonFiles.map((entry) => normalizePath(path.posix.dirname(entry))))
|
|
114
|
+
if (workspacesRel.length === 0) {
|
|
115
|
+
return {
|
|
116
|
+
rootAbs: cwd,
|
|
117
|
+
workspacesRel: ['.']
|
|
118
|
+
}
|
|
119
|
+
}
|
|
51
120
|
|
|
52
121
|
return {
|
|
53
|
-
rootAbs,
|
|
122
|
+
rootAbs: cwd,
|
|
54
123
|
workspacesRel
|
|
55
124
|
}
|
|
56
125
|
}
|
|
57
126
|
|
|
127
|
+
async function safeReadFile(filePath: string): Promise<string | null> {
|
|
128
|
+
try {
|
|
129
|
+
return await readFile(filePath, 'utf8')
|
|
130
|
+
} catch {
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function safeJsonParse(raw: string): unknown {
|
|
136
|
+
try {
|
|
137
|
+
return JSON.parse(raw)
|
|
138
|
+
} catch {
|
|
139
|
+
return null
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
|
144
|
+
return value !== null && typeof value === 'object'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function extractWorkspaceGlobs(packageJson: Record<string, unknown>): string[] {
|
|
148
|
+
const workspaces = packageJson.workspaces
|
|
149
|
+
if (Array.isArray(workspaces)) {
|
|
150
|
+
return workspaces.filter((entry): entry is string => typeof entry === 'string')
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!workspaces || typeof workspaces !== 'object' || Array.isArray(workspaces)) {
|
|
154
|
+
return []
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const packages = (workspaces as { packages?: unknown }).packages
|
|
158
|
+
if (Array.isArray(packages)) {
|
|
159
|
+
return packages.filter((entry): entry is string => typeof entry === 'string')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return []
|
|
163
|
+
}
|
|
164
|
+
|
|
58
165
|
export function assignGroupsByMatch(workspacesRel: readonly string[], groups: readonly GroupDefinition[]): GroupAssignment[] {
|
|
59
166
|
const sortedWorkspaces = sortUnique([...workspacesRel])
|
|
60
167
|
const assignments = new Map<string, string[]>()
|
package/test/workspace.test.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
1
4
|
import { describe, expect, it } from 'vitest'
|
|
2
5
|
|
|
3
|
-
import { assignGroupsByMatch } from '../src/index.js'
|
|
6
|
+
import { assignGroupsByMatch, discoverWorkspaces } from '../src/index.js'
|
|
4
7
|
|
|
5
8
|
describe('assignGroupsByMatch', () => {
|
|
6
9
|
it('assigns by first matching group and supports negatives', () => {
|
|
@@ -23,3 +26,46 @@ describe('assignGroupsByMatch', () => {
|
|
|
23
26
|
)
|
|
24
27
|
})
|
|
25
28
|
})
|
|
29
|
+
|
|
30
|
+
describe('discoverWorkspaces', () => {
|
|
31
|
+
it('falls back to package.json workspaces when package manager metadata is unavailable', async () => {
|
|
32
|
+
const root = await mkdtemp(path.join(tmpdir(), 'snapshot-workspaces-'))
|
|
33
|
+
await writeFile(
|
|
34
|
+
path.join(root, 'package.json'),
|
|
35
|
+
JSON.stringify(
|
|
36
|
+
{
|
|
37
|
+
name: 'fixture',
|
|
38
|
+
private: true,
|
|
39
|
+
workspaces: ['packages/*']
|
|
40
|
+
},
|
|
41
|
+
null,
|
|
42
|
+
2
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
await mkdir(path.join(root, 'packages/a'), { recursive: true })
|
|
46
|
+
await mkdir(path.join(root, 'packages/b'), { recursive: true })
|
|
47
|
+
await writeFile(path.join(root, 'packages/a/package.json'), JSON.stringify({ name: 'a', version: '1.0.0' }, null, 2))
|
|
48
|
+
await writeFile(path.join(root, 'packages/b/package.json'), JSON.stringify({ name: 'b', version: '1.0.0' }, null, 2))
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const discovery = await discoverWorkspaces({ cwd: root })
|
|
52
|
+
expect(discovery.rootAbs).toBe(root)
|
|
53
|
+
expect(discovery.workspacesRel).toEqual(['packages/a', 'packages/b'])
|
|
54
|
+
} finally {
|
|
55
|
+
await rm(root, { recursive: true, force: true })
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('falls back to current directory when workspace discovery cannot find matches', async () => {
|
|
60
|
+
const root = await mkdtemp(path.join(tmpdir(), 'snapshot-workspaces-empty-'))
|
|
61
|
+
await writeFile(path.join(root, 'package.json'), JSON.stringify({ name: 'fixture', private: true, workspaces: ['packages/*'] }, null, 2))
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const discovery = await discoverWorkspaces({ cwd: root })
|
|
65
|
+
expect(discovery.rootAbs).toBe(root)
|
|
66
|
+
expect(discovery.workspacesRel).toEqual(['.'])
|
|
67
|
+
} finally {
|
|
68
|
+
await rm(root, { recursive: true, force: true })
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
})
|