import fs from 'fs' ; import path from 'path' ; import { cosmiconfigSync } from 'cosmiconfig' ; import remarkMdx from 'remark-mdx' ; import remarkParse from 'remark-parse' ; import remarkStringify from 'remark-stringify' ; import type { FrozenProcessor } from 'unified' ; import unified from 'unified' ; import { arrayify } from './helpers' ; import type { RemarkConfig , RemarkPlugin } from './types' ; export const requirePkg = < T > ( plugin , prefix , filePath ? ) : T => { if ( filePath && /^\.\.?([/\\]|$)/ . test ( plugin ) ) { plugin = path . resolve ( path . dirname ( filePath ) , plugin ) ; } prefix = prefix . endsWith ( '-' ) ? prefix : prefix + '-' ; const packages = [ plugin , plugin . startsWith ( '@' ) ? plugin . replace ( '/' , '/' + prefix ) : prefix + plugin , ] ; let error ; for ( const pkg of packages ) { try { return require ( pkg ) as T ; } catch ( err ) { if ( ! error ) { error = err as Error ; } } } throw error ; } ; /**
 * Given a filepath, get the nearest path that is a regular file.
 * The filepath provided by eslint may be a virtual filepath rather than a file
 * on disk. This attempts to transform a virtual path into an on-disk path
 */ export const getPhysicalFilename = ( filename ) : string => { try { if ( fs . statSync ( filename ) . isFile ( ) ) { return filename ; } } catch ( err ) { if ( ( err as { code : string ; } ) . code === 'ENOTDIR' ) { return getPhysicalFilename ( path . dirname ( filename ) ) ; } } return filename ; } ; export const remarkProcessor = unified ( ) . use ( remarkParse ) . freeze ( ) ; const explorer = cosmiconfigSync ( 'remark' , { packageProp : 'remarkConfig' , } ) ; export const processorCache = new Map < string , FrozenProcessor > ( ) ; export const getRemarkProcessor = ( searchFrom , isMdx ) => { const initCacheKey = `${ String ( isMdx ) }-${ searchFrom }` ; let cachedProcessor = processorCache . get ( initCacheKey ) ; if ( cachedProcessor ) { return cachedProcessor ; } const result = explorer . search ( searchFrom ) ; const cacheKey = result ? `${ String ( isMdx ) }-${ result . filepath }` : '' ; cachedProcessor = processorCache . get ( cacheKey ) ; if ( cachedProcessor ) { return cachedProcessor ; } if ( result ) { const { plugins = [ ] , settings } = ( result . config || { } ) as Partial < RemarkConfig > ; if ( plugins . length > 0 ) { try { plugins . push ( [ require . resolve ( 'remark-lint-file-extension' ) , false ] ) ; } catch { } } const initProcessor = remarkProcessor ( ) . use ( { settings } ) . use ( remarkStringify ) ; if ( isMdx ) { initProcessor . use ( remarkMdx ) ; } cachedProcessor = plugins . reduce ( ( processor , pluginWithSettings ) => { const [ plugin , ... pluginSettings ] = arrayify ( pluginWithSettings ) as [ RemarkPlugin , ... unknown [ ] ] ; return processor . use ( typeof plugin === 'string' ? requirePkg ( plugin , 'remark' , result . filepath ) : plugin , ... pluginSettings ) ; } , initProcessor ) . freeze ( ) ; } else { const initProcessor = remarkProcessor ( ) . use ( remarkStringify ) ; if ( isMdx ) { initProcessor . use ( remarkMdx ) ; } cachedProcessor = initProcessor . freeze ( ) ; } processorCache . set ( initCacheKey , cachedProcessor ) . set ( cacheKey , cachedProcessor ) ; return cachedProcessor ; } ;