|
1 | | -import { existsSync, globSync, readFileSync, statSync } from 'node:fs'; |
| 1 | +import { globSync, readFileSync, readdirSync, statSync } from 'node:fs'; |
2 | 2 | import path from 'node:path'; |
3 | 3 |
|
4 | 4 | import postcss, { AtRule, type ChildNode, type Declaration, type Node } from 'postcss'; |
@@ -34,6 +34,19 @@ function add(file: string, node: Node | undefined, message: string): void { |
34 | 34 | problems.push(`${file}:${node?.source?.start?.line ?? 1} ${message}. See ${pitfalls}.`); |
35 | 35 | } |
36 | 36 |
|
| 37 | +function existsWithExactCase(root: string, relativeTarget: string): boolean { |
| 38 | + let current = root; |
| 39 | + return relativeTarget.split(path.sep).every((segment) => { |
| 40 | + try { |
| 41 | + if (!readdirSync(current).includes(segment)) return false; |
| 42 | + } catch { |
| 43 | + return false; |
| 44 | + } |
| 45 | + current = path.join(current, segment); |
| 46 | + return true; |
| 47 | + }); |
| 48 | +} |
| 49 | + |
37 | 50 | function isPublicDefault(declaration: Declaration): boolean { |
38 | 51 | const rule = declaration.parent; |
39 | 52 | if ( |
@@ -107,7 +120,7 @@ for (const { path: directory, ownsLayerContract } of directories) { |
107 | 120 | const relativeTarget = path.relative(directory, target); |
108 | 121 | const outside = |
109 | 122 | relativeTarget === '..' || relativeTarget.startsWith(`..${path.sep}`) || path.isAbsolute(relativeTarget); |
110 | | - if (outside || !existsSync(target) || !statSync(target).isFile()) |
| 123 | + if (outside || !existsWithExactCase(directory, relativeTarget) || !statSync(target).isFile()) |
111 | 124 | add(file, declaration, 'Missing built URL target'); |
112 | 125 | } |
113 | 126 | }); |
|
0 commit comments