import * as fs from './util/fs.js' ; import validateFile from './util/babel-validate-file.js' ; import * as path from 'path' ; import chalk from 'chalk' ; import minimist from 'minimist' ; import nodeFs from 'fs' ; import mkdirp from 'mkdirp' ; import babel from '@babel/core' ; import babelPluginDynamicImportSyntax from '@babel/plugin-syntax-dynamic-import' ; import babelPluginNullishCoalescingOperator from '@babel/plugin-syntax-nullish-coalescing-operator' ; import babelPluginOptionalChaining from '@babel/plugin-syntax-optional-chaining' ; import babelPluginBigint from '@babel/plugin-syntax-bigint' ; import babelPluginImportMetaSyntax from '@babel/plugin-syntax-import-meta' ; import babelPresetTypeScript from '@babel/preset-typescript' ; import babelPluginImportRewrite from '@pika/babel-plugin-esm-import-rewrite' ; function log ( fileName , errors ) { console . log ( chalk . bold ( fileName ) ) ; for ( const error of errors ) { console . log ( ' ' , error . level === 2 ? '⚠️ ' : '   ' , error . msg ) ; } } export class Lint { constructor ( dist , { ignoreExtensions } = { } ) { this . dist = dist ; this . errors = new Map ( ) ; this . totalNum = 0 ; this . ignoreExtensions = ignoreExtensions || false ; } dist : string ; totalNum : number ; errors : Map < string , { loc ? : string ; msg : string ; level : number ; } [ ] > ; ignoreExtensions : boolean ; private addError ( filename , msg , level = 2 ) { const errors = this . errors . get ( filename ) || [ ] ; errors . push ( { msg , level } ) ; this . errors . set ( filename , errors ) ; } async init ( ) { const { dist } = this ; const dir = path . join ( dist , '..' ) ; const files = await fs . glob ( `**/*` , { cwd : dist , absolute : true , nodir : true , } ) ; for ( const fileLoc of files ) { const relativePath = path . relative ( path . join ( dist , '..' ) , fileLoc ) ; const extName = path . extname ( fileLoc ) ; if ( extName === '.map' ) { continue ; } if ( fileLoc . includes ( 'README' ) ) { continue ; } if ( extName !== '.js' ) { this . addError ( relativePath , 'Only JavaScript files are expected in your dist-src/ distribution.' ) ; this . totalNum ++ ; continue ; } const fileContents = await fs . readFile ( fileLoc ) ; const validateErrors = validateFile ( fileContents , fileLoc , dir , dist , this . ignoreExtensions ) ; for ( const errMsg of validateErrors ) { this . addError ( relativePath , errMsg ) ; } this . totalNum += validateErrors . size ; } } summary ( ) { if ( this . totalNum === 0 ) { return ; } console . log ( `` ) ; for ( const [ filename , errors ] of this . errors . entries ( ) ) { log ( filename , errors ) ; } console . log ( `` ) ; console . log ( chalk . red ( '✘' ) , `${ this . totalNum } issues found.` ) ; } exitCode ( ) { return this . totalNum === 0 ? 0 : 1 ; } } export class Build { constructor ( dir , options = { } ) { this . dir = dir ; this . options = options ; this . result = new Map ( ) ; } dir : string ; options : any ; result : Map < string , string > ; async init ( ) { const { dir , options } = this ; const files = ( await fs . glob ( `**/*` , { cwd : dir , nodir : true , absolute : false , ignore : options . exclude || [ ] , } ) ) . filter ( filepath => ! filepath . endsWith ( '.d.ts' ) && ! filepath . includes ( 'README' ) ) ; for ( const sourcePath of files ) { const sourcePathAbs = path . join ( dir , sourcePath ) ; const transformedPath = sourcePath . replace ( '.ts' , '.js' ) . replace ( '.tsx' , '.js' ) . replace ( '.jsx' , '.js' ) . replace ( '.mjs' , '.js' ) ; const resultSrc = await babel . transformFileAsync ( sourcePathAbs , { presets : [ [ babelPresetTypeScript ] ] , plugins : [ [ babelPluginImportRewrite , { addExtensions : true } ] , babelPluginDynamicImportSyntax , babelPluginImportMetaSyntax , babelPluginNullishCoalescingOperator , babelPluginOptionalChaining , babelPluginBigint , ] , } ) ; this . result . set ( transformedPath , resultSrc . code ) ; } return this . result ; } async write ( out , result = this . result ) { for ( const [ filepath , contents ] of result . entries ( ) ) { const transformedPathAbs = path . join ( out , filepath ) ; mkdirp . sync ( path . dirname ( transformedPathAbs ) ) ; nodeFs . writeFileSync ( transformedPathAbs , contents ) ; } } } export async function run ( argv ) { var args = minimist ( argv . slice ( 2 ) ) ; const srcDir = path . resolve ( process . cwd ( ) , typeof args . src === 'string' ? args . src : 'src' ) ; const distDir = path . resolve ( process . cwd ( ) , typeof args . dist === 'string' ? args . dist : 'lib' ) ; if ( args . src ) { console . log ( chalk . bold . dim ( `»` ) , chalk ( `Building ${ path . relative ( process . cwd ( ) , srcDir ) }${ path . sep } → ${ path . relative ( process . cwd ( ) , distDir ) }${ path . sep }...` ) ) ; const builder = new Build ( srcDir ) ; await builder . init ( ) ; await builder . write ( distDir ) ; } console . log ( chalk . bold . dim ( `»` ) , chalk ( `Linting ${ path . relative ( process . cwd ( ) , distDir ) }${ path . sep }...` ) ) ; const linter = new Lint ( distDir ) ; await linter . init ( ) ; if ( linter . totalNum === 0 ) { console . log ( chalk . bold . green ( `✓` ) , '0 issues found.' ) ; } else { linter . summary ( ) ; } process . exit ( linter . exitCode ( ) ) ; }