@@ -5,6 +5,7 @@ import deepmerge from "deepmerge";
55import { parse } from "jsonc-parser" ;
66import { addDevDependency , dlxCommand } from "nypm" ;
77import type { PackageManager , PackageManagerName } from "nypm" ;
8+ import YAML from "yaml" ;
89
910import { parsePackageJson } from "../schemas" ;
1011import { exists , isMonorepo } from "../utils" ;
@@ -33,88 +34,6 @@ const configFiles = [
3334 "./.lintstagedrc" ,
3435] ;
3536
36- // Helper function to process YAML lines
37- const processYamlLine = (
38- line : string ,
39- result : Record < string , unknown > ,
40- currentKey : string | null ,
41- currentArray : string [ ]
42- ) : { newCurrentKey : string | null ; newCurrentArray : string [ ] } => {
43- const trimmed = line . trim ( ) ;
44-
45- if ( trimmed . includes ( ":" ) && ! trimmed . startsWith ( "-" ) ) {
46- // Save previous array if exists
47- if ( currentKey && currentArray . length > 0 ) {
48- result [ currentKey ] = currentArray ;
49- }
50-
51- const [ key , ...valueParts ] = trimmed . split ( ":" ) ;
52- const value = valueParts . join ( ":" ) . trim ( ) ;
53- const newCurrentKey = key . trim ( ) . replaceAll ( / [ ' " ] / g, "" ) ;
54-
55- if ( value && value !== "" ) {
56- result [ newCurrentKey ] =
57- value . startsWith ( "[" ) && value . endsWith ( "]" )
58- ? value
59- . slice ( 1 , - 1 )
60- . split ( "," )
61- . map ( ( v ) => v . trim ( ) . replaceAll ( / [ ' " ] / g, "" ) )
62- : value . replaceAll ( / [ ' " ] / g, "" ) ;
63- return { newCurrentArray : [ ] , newCurrentKey : null } ;
64- }
65- return { newCurrentArray : [ ] , newCurrentKey } ;
66- }
67-
68- if ( trimmed . startsWith ( "-" ) && currentKey ) {
69- const newCurrentArray = [
70- ...currentArray ,
71- trimmed . slice ( 1 ) . trim ( ) . replaceAll ( / [ ' " ] / g, "" ) ,
72- ] ;
73- return { newCurrentArray, newCurrentKey : currentKey } ;
74- }
75-
76- return { newCurrentArray : currentArray , newCurrentKey : currentKey } ;
77- } ;
78-
79- // Simple YAML parser for basic objects (limited but functional)
80- const parseSimpleYaml = ( content : string ) : Record < string , unknown > => {
81- const lines = content
82- . split ( "\n" )
83- . filter ( ( line ) => line . trim ( ) && ! line . trim ( ) . startsWith ( "#" ) ) ;
84- const result : Record < string , unknown > = { } ;
85- let currentKey : string | null = null ;
86- let currentArray : string [ ] = [ ] ;
87-
88- for ( const line of lines ) {
89- const processed = processYamlLine ( line , result , currentKey , currentArray ) ;
90- currentKey = processed . newCurrentKey ;
91- currentArray = processed . newCurrentArray ;
92- }
93-
94- // Save final array if exists
95- if ( currentKey && currentArray . length > 0 ) {
96- result [ currentKey ] = currentArray ;
97- }
98-
99- return result ;
100- } ;
101-
102- // Convert object to simple YAML format
103- const stringifySimpleYaml = ( obj : Record < string , unknown > ) : string => {
104- let yaml = "" ;
105- for ( const [ key , value ] of Object . entries ( obj ) ) {
106- if ( Array . isArray ( value ) ) {
107- yaml += `${ key } :\n` ;
108- for ( const item of value ) {
109- yaml += ` - '${ item } '\n` ;
110- }
111- } else {
112- yaml += `${ key } : '${ value } '\n` ;
113- }
114- }
115- return yaml ;
116- } ;
117-
11837// Check if project uses ESM
11938const isProjectEsm = async ( ) : Promise < boolean > => {
12039 try {
@@ -171,17 +90,29 @@ const updateJsonConfig = async (
17190 await writeFile ( filename , `${ JSON . stringify ( mergedConfig , null , 2 ) } \n` ) ;
17291} ;
17392
93+ // Quote unquoted glob pattern keys that YAML would misinterpret as aliases or tags
94+ const quoteGlobKeys = ( content : string ) : string =>
95+ content . replaceAll (
96+ / ^ ( [ * ? { [ ] [ ^ \n : ] * ) : ( .* ) $ / gm,
97+ ( _match , key : string , rest : string ) => `'${ key } ':${ rest } `
98+ ) ;
99+
174100// Update YAML config files
175101const updateYamlConfig = async (
176102 filename : string ,
177103 packageManager : PackageManagerName
178104) : Promise < void > => {
179- const content = await readFile ( filename , "utf-8" ) ;
180- const existingConfig = parseSimpleYaml ( content ) as
181- | Record < string , unknown >
182- | undefined ;
105+ const raw = await readFile ( filename , "utf-8" ) ;
106+ const content = quoteGlobKeys ( raw ) ;
107+
108+ let existingConfig : Record < string , unknown > | undefined ;
109+ try {
110+ existingConfig = YAML . parse ( content ) as Record < string , unknown > | undefined ;
111+ } catch {
112+ // If parsing fails (invalid YAML), treat as empty config and proceed gracefully
113+ return ;
114+ }
183115
184- // If parsing fails (invalid YAML), treat as empty config and proceed gracefully
185116 if ( ! existingConfig ) {
186117 return ;
187118 }
@@ -190,7 +121,7 @@ const updateYamlConfig = async (
190121 existingConfig ,
191122 createLintStagedConfig ( packageManager )
192123 ) ;
193- await writeFile ( filename , stringifySimpleYaml ( mergedConfig ) ) ;
124+ await writeFile ( filename , YAML . stringify ( mergedConfig ) ) ;
194125} ;
195126
196127// Update ESM config files
0 commit comments