Skip to content

Commit ceeb7ec

Browse files
feat(vscode): implemented nearestChildDartFrogProjects (#1015)
Co-authored-by: Renan <[email protected]>
1 parent 4a79284 commit ceeb7ec

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed

extensions/vscode/src/test/suite/utils/dart-frog-structure.test.ts

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,190 @@ suite("nearestParentDartFrogProject", () => {
202202
});
203203
});
204204

205+
suite("nearestChildDartFrogProjects", () => {
206+
let fsStub: any;
207+
let nearestChildDartFrogProjects: any;
208+
209+
beforeEach(() => {
210+
fsStub = {
211+
existsSync: sinon.stub(),
212+
readFileSync: sinon.stub(),
213+
statSync: sinon.stub(),
214+
readdirSync: sinon.stub(),
215+
};
216+
217+
nearestChildDartFrogProjects = proxyquire(
218+
"../../../utils/dart-frog-structure",
219+
{
220+
fs: fsStub,
221+
}
222+
).nearestChildDartFrogProjects;
223+
});
224+
225+
afterEach(() => {
226+
sinon.restore();
227+
});
228+
229+
test("returns a single path when the file path is a Dart Frog project", () => {
230+
const filePath = "/home/project";
231+
232+
const dartFrogPubspecRoutesPath = path.join(filePath, "routes");
233+
const dartFrogPubspecPath = path.join(filePath, "pubspec.yaml");
234+
fsStub.existsSync.withArgs(filePath).returns(true);
235+
fsStub.statSync.withArgs(filePath).returns({
236+
isDirectory: () => true,
237+
});
238+
fsStub.readdirSync.withArgs(filePath).returns([]);
239+
fsStub.existsSync.withArgs(dartFrogPubspecRoutesPath).returns(true);
240+
fsStub.existsSync.withArgs(dartFrogPubspecPath).returns(true);
241+
fsStub.readFileSync
242+
.withArgs(dartFrogPubspecPath, "utf-8")
243+
.returns(validPubspecYaml);
244+
245+
const dartFrogProjects = nearestChildDartFrogProjects(filePath);
246+
247+
assert.deepEqual(dartFrogProjects, [filePath]);
248+
});
249+
250+
test("returns the path to all the child Dart Frog projects", () => {
251+
fsStub.existsSync.returns(false);
252+
253+
const filePath = "/home/project";
254+
fsStub.existsSync.withArgs(filePath).returns(true);
255+
fsStub.statSync.withArgs(filePath).returns({
256+
isDirectory: () => true,
257+
});
258+
fsStub.readdirSync
259+
.withArgs(filePath)
260+
.returns(["file.dart", "frog1", "frog2", "subdirectory", "flutter"]);
261+
262+
const fileDartPath = "/home/project/file.dart";
263+
fsStub.existsSync.withArgs(fileDartPath).returns(true);
264+
fsStub.statSync.withArgs(fileDartPath).returns({
265+
isDirectory: () => false,
266+
});
267+
268+
const dartFrogPath1 = "/home/project/frog1";
269+
const dartFrogPubspecRoutesPath1 = path.join(dartFrogPath1, "routes");
270+
const dartFrogPubspecPath1 = path.join(dartFrogPath1, "pubspec.yaml");
271+
fsStub.existsSync.withArgs(dartFrogPath1).returns(true);
272+
fsStub.statSync.withArgs(dartFrogPath1).returns({
273+
isDirectory: () => true,
274+
});
275+
fsStub.readdirSync.withArgs(dartFrogPath1).returns([]);
276+
fsStub.existsSync.withArgs(dartFrogPubspecRoutesPath1).returns(true);
277+
fsStub.existsSync.withArgs(dartFrogPubspecPath1).returns(true);
278+
fsStub.readFileSync
279+
.withArgs(dartFrogPubspecPath1, "utf-8")
280+
.returns(validPubspecYaml);
281+
282+
const dartFrogPath2 = "/home/project/frog2";
283+
const dartFrogPubspecRoutesPath2 = path.join(dartFrogPath2, "routes");
284+
const dartFrogPubspecPath2 = path.join(dartFrogPath2, "pubspec.yaml");
285+
fsStub.existsSync.withArgs(dartFrogPath2).returns(true);
286+
fsStub.statSync.withArgs(dartFrogPath2).returns({
287+
isDirectory: () => true,
288+
});
289+
fsStub.readdirSync.withArgs(dartFrogPath2).returns([]);
290+
fsStub.existsSync.withArgs(dartFrogPubspecRoutesPath2).returns(true);
291+
fsStub.existsSync.withArgs(dartFrogPubspecPath2).returns(true);
292+
fsStub.readFileSync
293+
.withArgs(dartFrogPubspecPath2, "utf-8")
294+
.returns(validPubspecYaml);
295+
296+
const subdirectory = "/home/project/subdirectory";
297+
fsStub.existsSync.withArgs(subdirectory).returns(true);
298+
fsStub.statSync.withArgs(subdirectory).returns({
299+
isDirectory: () => true,
300+
});
301+
fsStub.readdirSync.withArgs(subdirectory).returns(["frog3"]);
302+
303+
const dartFrogPath3 = "/home/project/subdirectory/frog3";
304+
const dartFrogPubspecRoutesPath3 = path.join(dartFrogPath3, "routes");
305+
const dartFrogPubspecPath3 = path.join(dartFrogPath3, "pubspec.yaml");
306+
fsStub.existsSync.withArgs(dartFrogPath3).returns(true);
307+
fsStub.statSync.withArgs(dartFrogPath3).returns({
308+
isDirectory: () => true,
309+
});
310+
fsStub.readdirSync.withArgs(dartFrogPath3).returns([]);
311+
fsStub.existsSync.withArgs(dartFrogPubspecRoutesPath3).returns(true);
312+
fsStub.existsSync.withArgs(dartFrogPubspecPath3).returns(true);
313+
fsStub.readFileSync
314+
.withArgs(dartFrogPubspecPath3, "utf-8")
315+
.returns(validPubspecYaml);
316+
317+
const flutterPath = "/home/project/flutter";
318+
const flutterPubspecPath = path.join(flutterPath, "pubspec.yaml");
319+
fsStub.existsSync.withArgs(flutterPath).returns(true);
320+
fsStub.statSync.withArgs(flutterPath).returns({
321+
isDirectory: () => true,
322+
});
323+
fsStub.readdirSync.withArgs(flutterPath).returns([]);
324+
fsStub.existsSync.withArgs(flutterPubspecPath).returns(true);
325+
fsStub.readFileSync
326+
.withArgs(flutterPubspecPath, "utf-8")
327+
.returns(invalidPubspecYaml);
328+
329+
const dartFrogProjects = nearestChildDartFrogProjects(filePath);
330+
331+
assert.deepEqual(dartFrogProjects, [
332+
dartFrogPath1,
333+
dartFrogPath2,
334+
dartFrogPath3,
335+
]);
336+
});
337+
338+
suite("returns undefined", () => {
339+
test("when path does not exist", () => {
340+
const filePath = "/home/project/routes/animals/frog.dart";
341+
fsStub.existsSync.withArgs(filePath).returns(false);
342+
343+
const result = nearestChildDartFrogProjects(filePath);
344+
345+
assert.equal(result, undefined);
346+
});
347+
348+
test("when path is not a directory", () => {
349+
const filePath = "/home/project/routes/animals/frog.dart";
350+
fsStub.existsSync.withArgs(filePath).returns(true);
351+
fsStub.statSync.withArgs(filePath).returns({
352+
isDirectory: () => false,
353+
});
354+
355+
const result = nearestChildDartFrogProjects(filePath);
356+
357+
assert.equal(result, undefined);
358+
});
359+
360+
test("when subdirectory is not a Dart Frog project", () => {
361+
const filePath = "/home/project";
362+
fsStub.existsSync.withArgs(filePath).returns(true);
363+
fsStub.statSync.withArgs(filePath).returns({
364+
isDirectory: () => true,
365+
});
366+
fsStub.readdirSync.withArgs(filePath).returns(["frog"]);
367+
368+
const dartFrogPath = "/home/project/frog";
369+
const dartFrogPubspecRoutesPath = path.join(dartFrogPath, "routes");
370+
const dartFrogPubspecPath = path.join(dartFrogPath, "pubspec.yaml");
371+
fsStub.existsSync.withArgs(dartFrogPath).returns(true);
372+
fsStub.statSync.withArgs(dartFrogPath).returns({
373+
isDirectory: () => true,
374+
});
375+
fsStub.readdirSync.withArgs(dartFrogPath).returns([]);
376+
fsStub.existsSync.withArgs(dartFrogPubspecRoutesPath).returns(true);
377+
fsStub.existsSync.withArgs(dartFrogPubspecPath).returns(true);
378+
fsStub.readFileSync
379+
.withArgs(dartFrogPubspecPath, "utf-8")
380+
.returns(invalidPubspecYaml);
381+
382+
const result = nearestChildDartFrogProjects(filePath);
383+
384+
assert.equal(result, undefined);
385+
});
386+
});
387+
});
388+
205389
suite("isDartFrogProject", () => {
206390
let fsStub: any;
207391
let isDartFrogProject: any;

extensions/vscode/src/utils/dart-frog-structure.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,66 @@ export function nearestParentDartFrogProject(
7777
return undefined;
7878
}
7979

80+
/**
81+
* Finds all Dart Frog projects that are children of a directory.
82+
*
83+
* Nested Dart Frog projects are not considered. Therefore, if the
84+
* {@link filePath} is a Dart Frog project, then only that project is reported.
85+
* The same logic applies to subdirectories. If a subdirectory is also a Dart
86+
* Frog project, then all of its subdirectories are ignored and only the
87+
* shallowest Dart Frog project is reported.
88+
*
89+
* @param filePath The path to the directory to check for.
90+
* @returns {Array<string> | undefined} A set of paths to Dart Frog projects
91+
* that are children of the {@link filePath}, or `undefined` if there are no
92+
* Dart Frog projects in the {@link filePath}.
93+
*/
94+
export function nearestChildDartFrogProjects(
95+
filePath: string
96+
): Array<string> | undefined {
97+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isDirectory()) {
98+
return undefined;
99+
}
100+
101+
if (isDartFrogProject(filePath)) {
102+
return [filePath];
103+
}
104+
105+
const dartFrogProjects = new Set<string>();
106+
107+
let currentSubdirectories = fs
108+
.readdirSync(filePath)
109+
.map((file: string) => path.join(filePath, file))
110+
.filter((file: string) => fs.statSync(file).isDirectory());
111+
112+
while (currentSubdirectories.length > 0) {
113+
for (let i = 0; i < currentSubdirectories.length; i++) {
114+
const subdirectory = currentSubdirectories[i];
115+
if (isDartFrogProject(subdirectory)) {
116+
dartFrogProjects.add(subdirectory);
117+
currentSubdirectories.splice(i, 1);
118+
i--;
119+
}
120+
}
121+
122+
const nextSubdirectories: string[] = [];
123+
for (const subdirectory of currentSubdirectories) {
124+
const subdirectorySubdirectories = fs
125+
.readdirSync(subdirectory)
126+
.map((file: string) => path.join(subdirectory, file))
127+
.filter((file: string) => fs.statSync(file).isDirectory());
128+
nextSubdirectories.push(...subdirectorySubdirectories);
129+
}
130+
currentSubdirectories = nextSubdirectories;
131+
}
132+
133+
if (dartFrogProjects.size === 0) {
134+
return undefined;
135+
}
136+
137+
return Array.from(dartFrogProjects);
138+
}
139+
80140
/**
81141
* Determines if a {@link filePath} is a Dart Frog project.
82142
*

0 commit comments

Comments
 (0)