Skip to content

Commit 1155aa3

Browse files
authored
fix: handle recursive imports (iam-medvedev#125)
Added tracking handler for imported files to avoid infinite loops with recursive imports. Closes iam-medvedev#114
1 parent 1dd2534 commit 1155aa3

File tree

4 files changed

+41
-2
lines changed

4 files changed

+41
-2
lines changed

__tests__/less-utils.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ describe('less-utils', () => {
77
const filePath = path.resolve(__dirname, '../example/styles/style.less');
88
const imports = getLessImports(filePath);
99

10+
expect(imports).toHaveLength(5);
1011
expect(imports).toEqual(
1112
expect.arrayContaining([
1213
expect.stringContaining('styles/style-2.less'),
@@ -22,6 +23,7 @@ describe('less-utils', () => {
2223
const filePath = path.resolve(__dirname, '../example/styles/style.less');
2324
const imports = getLessImports(filePath, ['../example', '../example/styles']);
2425

26+
expect(imports).toHaveLength(5);
2527
expect(imports).toEqual(
2628
expect.arrayContaining([
2729
expect.stringContaining('styles/style-2.less'),
@@ -33,6 +35,28 @@ describe('less-utils', () => {
3335
);
3436
});
3537

38+
it('works with recursive imports', () => {
39+
const filePath = path.resolve(__dirname, '../example/styles/recursive/a.less');
40+
const imports = getLessImports(filePath);
41+
42+
expect(imports).toHaveLength(2);
43+
expect(imports).toEqual(
44+
expect.arrayContaining([
45+
expect.stringContaining('styles/recursive/a.less'),
46+
expect.stringContaining('styles/recursive/b.less'),
47+
]),
48+
);
49+
});
50+
51+
it('do not process a file if it has already been processed', () => {
52+
const filePath = path.resolve(__dirname, '../example/styles/recursive/a.less');
53+
const visited = new Set<string>();
54+
visited.add(filePath);
55+
56+
const imports = getLessImports(filePath, [], visited);
57+
expect(imports).toHaveLength(0);
58+
});
59+
3660
it('get imports paths fail', () => {
3761
const filePath = path.resolve(__dirname, '../example/styles/unknown-file.less');
3862
const imports = getLessImports(filePath);

example/styles/recursive/a.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import 'b.less';
2+
3+
body {
4+
color: red;
5+
}

example/styles/recursive/b.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import 'a.less';
2+
3+
body {
4+
background-color: blue;
5+
}

src/less-utils.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ const importCommentRegex = /(?:\/\*(?:[\s\S]*?)\*\/)|(\/\/(?:.*)$)/gm;
99
const extWhitelist = ['.css', '.less'];
1010

1111
/** Recursively get .less/.css imports from file */
12-
export function getLessImports(filePath: string, paths: string[] = []): string[] {
12+
export function getLessImports(filePath: string, paths: string[] = [], visited: Set<string> = new Set()): string[] {
1313
try {
14+
if (visited.has(filePath)) {
15+
return [];
16+
}
17+
visited.add(filePath);
18+
1419
const dir = path.dirname(filePath);
1520
const content = fs.readFileSync(filePath).toString('utf8');
1621

@@ -45,7 +50,7 @@ export function getLessImports(filePath: string, paths: string[] = []): string[]
4550
});
4651

4752
const recursiveImports = fileImports.reduce((result, el) => {
48-
return [...result, ...getLessImports(el, paths)];
53+
return [...result, ...getLessImports(el, paths, visited)];
4954
}, fileImports);
5055

5156
const result = recursiveImports.filter((el) => extWhitelist.includes(path.extname(el).toLowerCase()));

0 commit comments

Comments
 (0)