@@ -27,6 +27,101 @@ function hasPackageJson(dir: string): boolean {
2727 return existsSync ( join ( dir , 'package.json' ) )
2828}
2929
30+ function stripJsonCommentsAndTrailingCommas ( source : string ) : string {
31+ let result = ''
32+ let inString = false
33+ let escaped = false
34+
35+ for ( let index = 0 ; index < source . length ; index += 1 ) {
36+ const char = source [ index ] !
37+ const next = source [ index + 1 ]
38+
39+ if ( inString ) {
40+ result += char
41+ if ( escaped ) {
42+ escaped = false
43+ } else if ( char === '\\' ) {
44+ escaped = true
45+ } else if ( char === '"' ) {
46+ inString = false
47+ }
48+ continue
49+ }
50+
51+ if ( char === '"' ) {
52+ inString = true
53+ result += char
54+ continue
55+ }
56+
57+ if ( char === '/' && next === '/' ) {
58+ while ( index < source . length && source [ index ] !== '\n' ) {
59+ index += 1
60+ }
61+ if ( index < source . length ) {
62+ result += source [ index ] !
63+ }
64+ continue
65+ }
66+
67+ if ( char === '/' && next === '*' ) {
68+ const commentStart = index
69+ index += 2
70+ while (
71+ index < source . length &&
72+ ! ( source [ index ] === '*' && source [ index + 1 ] === '/' )
73+ ) {
74+ index += 1
75+ }
76+ if ( index >= source . length ) {
77+ throw new SyntaxError (
78+ `Unterminated block comment starting at position ${ commentStart } ` ,
79+ )
80+ }
81+ index += 1
82+ continue
83+ }
84+
85+ if ( char === ',' ) {
86+ let lookahead = index + 1
87+ while ( lookahead < source . length ) {
88+ const la = source [ lookahead ] !
89+ if ( / \s / . test ( la ) ) {
90+ lookahead += 1
91+ } else if ( la === '/' && source [ lookahead + 1 ] === '/' ) {
92+ lookahead += 2
93+ while ( lookahead < source . length && source [ lookahead ] !== '\n' ) {
94+ lookahead += 1
95+ }
96+ } else if ( la === '/' && source [ lookahead + 1 ] === '*' ) {
97+ lookahead += 2
98+ while (
99+ lookahead < source . length &&
100+ ! ( source [ lookahead ] === '*' && source [ lookahead + 1 ] === '/' )
101+ ) {
102+ lookahead += 1
103+ }
104+ lookahead += 2
105+ } else {
106+ break
107+ }
108+ }
109+ if ( source [ lookahead ] === '}' || source [ lookahead ] === ']' ) {
110+ continue
111+ }
112+ }
113+
114+ result += char
115+ }
116+
117+ return result
118+ }
119+
120+ function readJsonFile ( path : string , jsonc = false ) : unknown {
121+ const source = readFileSync ( path , 'utf8' )
122+ return JSON . parse ( jsonc ? stripJsonCommentsAndTrailingCommas ( source ) : source )
123+ }
124+
30125export function readWorkspacePatterns ( root : string ) : Array < string > | null {
31126 const pnpmWs = join ( root , 'pnpm-workspace.yaml' )
32127 if ( existsSync ( pnpmWs ) ) {
@@ -40,25 +135,51 @@ export function readWorkspacePatterns(root: string): Array<string> | null {
40135 return patterns
41136 }
42137 } catch ( err : unknown ) {
138+ const verb = err instanceof SyntaxError ? 'parse' : 'read'
43139 console . error (
44- `Warning: failed to parse ${ pnpmWs } : ${ err instanceof Error ? err . message : err } ` ,
140+ `Warning: failed to ${ verb } ${ pnpmWs } : ${ err instanceof Error ? err . message : err } ` ,
45141 )
46142 }
47143 }
48144
49145 const pkgPath = join ( root , 'package.json' )
50146 if ( existsSync ( pkgPath ) ) {
51147 try {
52- const pkg = JSON . parse ( readFileSync ( pkgPath , 'utf8' ) )
148+ const pkg = readJsonFile ( pkgPath ) as Record < string , unknown >
149+ const workspaces = pkg . workspaces as Record < string , unknown > | undefined
53150 const patterns =
54- parseWorkspacePatterns ( pkg . workspaces ) ??
55- parseWorkspacePatterns ( pkg . workspaces ?. packages )
151+ parseWorkspacePatterns ( workspaces ) ??
152+ parseWorkspacePatterns ( workspaces ?. packages )
153+ if ( patterns ) {
154+ return patterns
155+ }
156+ } catch ( err : unknown ) {
157+ const verb = err instanceof SyntaxError ? 'parse' : 'read'
158+ console . error (
159+ `Warning: failed to ${ verb } ${ pkgPath } : ${ err instanceof Error ? err . message : err } ` ,
160+ )
161+ }
162+ }
163+
164+ for ( const denoConfigName of [ 'deno.json' , 'deno.jsonc' ] ) {
165+ const denoConfigPath = join ( root , denoConfigName )
166+ if ( ! existsSync ( denoConfigPath ) ) {
167+ continue
168+ }
169+
170+ try {
171+ const denoConfig = readJsonFile ( denoConfigPath , true ) as Record <
172+ string ,
173+ unknown
174+ >
175+ const patterns = parseWorkspacePatterns ( denoConfig . workspace )
56176 if ( patterns ) {
57177 return patterns
58178 }
59179 } catch ( err : unknown ) {
180+ const verb = err instanceof SyntaxError ? 'parse' : 'read'
60181 console . error (
61- `Warning: failed to parse ${ pkgPath } : ${ err instanceof Error ? err . message : err } ` ,
182+ `Warning: failed to ${ verb } ${ denoConfigPath } : ${ err instanceof Error ? err . message : err } ` ,
62183 )
63184 }
64185 }
0 commit comments