diff --git a/eslint.config.mjs b/eslint.config.mjs index a50bf35..1bbf67a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,5 +2,11 @@ import tseslint from 'typescript-eslint'; import configs from './configs/eslint.mjs'; export default tseslint.config( - ...configs + ...configs, + { + rules: { + 'no-console': 'off', + '@typescript-eslint/no-require-imports': 'off', + } + } ) \ No newline at end of file diff --git a/src/build/banner.ts b/src/build/banner.ts index 0b82710..ba99497 100644 --- a/src/build/banner.ts +++ b/src/build/banner.ts @@ -8,11 +8,11 @@ export function getBanner(pkg: Pkg) { license } = pkg const text = [ - `/*!`, + '/*!', `* ${name} v${version}`, `* (c) ${new Date().getFullYear()} ${author}`, `* Released under the ${license} license.`, - `* */` + '* */' ].join('\n') return text diff --git a/src/build/config.ts b/src/build/config.ts index 565bfd1..89210f8 100644 --- a/src/build/config.ts +++ b/src/build/config.ts @@ -23,7 +23,7 @@ export interface OutputOptions { export type RollupConfig = RollupOptions & { output: RollupOutputOptions[] } export function getRollupConfig(options: ReteConfig, outputs: OutputOptions[], pkg: Pkg, outputDirectories: string[]): ({ - options: ReteOptions, + options: ReteOptions config: RollupConfig }[]) { if (Array.isArray(options)) { @@ -42,7 +42,7 @@ export function getRollupConfig(options: ReteConfig, outputs: OutputOptions[], p } = options const localOutputDirectories = outputDirectories.map(path => join(path, outputPath)) const extensions = ['.js', '.ts', '.jsx', '.tsx'] - const babelPresets = babelOptions?.presets || [ + const babelPresets = babelOptions?.presets ?? [ [require('@babel/preset-env')], require('@babel/preset-typescript') ] @@ -63,7 +63,9 @@ export function getRollupConfig(options: ReteConfig, outputs: OutputOptions[], p banner: getBanner(pkg), globals, exports: 'named' as const, - plugins: minify ? [terser()] : [] + plugins: minify + ? [terser()] + : [] }) as RollupOutputOptions)).flat(), watch: { include: `${SOURCE_FOLDER}/**` @@ -73,40 +75,52 @@ export function getRollupConfig(options: ReteConfig, outputs: OutputOptions[], p /^@babel\/runtime.*$/ ], plugins: [ - ...(head ? [ - copy({ - targets: [ - { src: 'README.md', dest: localOutputDirectories } - ] - }), - ...outputDirectories.map(output => { - const bundlesPath = join(output, outputPath) + ...head + ? [ + copy({ + targets: [ + { src: 'README.md', dest: localOutputDirectories } + ] + }), + ...outputDirectories.map(output => { + const bundlesPath = join(output, outputPath) - return preparePackageJson(pkg, bundlesPath, (config) => { - for (const { suffix, entries } of outputs) { - for (const entry of entries) { - config[entry] = getBundleName(suffix) + return preparePackageJson(pkg, bundlesPath, config => { + for (const { suffix, entries } of outputs) { + for (const entry of entries) { + config[entry] = getBundleName(suffix) + } } - } - config.types = getDTSPath(input, output, bundlesPath) - config.typings = config.types + config.types = getDTSPath(input, output, bundlesPath) + config.typings = config.types + }) }) - }) - ] : []), - ...(nodeResolveOptions === false ? [] : [nodeResolve({ - extensions, - ...(nodeResolveOptions || {}) - })]), + ] + : [], + ...nodeResolveOptions === false + ? [] + : [ + nodeResolve({ + extensions, + ...nodeResolveOptions ?? {} + }) + ], babel({ exclude: 'node_modules/**', babelrc: false, presets: babelPresets, - plugins: bundled ? babelOptions?.plugins : [ - require('@babel/plugin-transform-runtime'), - ...(babelOptions?.plugins ? babelOptions.plugins : []) - ], - babelHelpers: bundled ? 'bundled' : 'runtime', + plugins: bundled + ? babelOptions?.plugins + : [ + require('@babel/plugin-transform-runtime'), + ...babelOptions?.plugins + ? babelOptions.plugins + : [] + ], + babelHelpers: bundled + ? 'bundled' + : 'runtime', extensions }), ...plugins diff --git a/src/build/dev.ts b/src/build/dev.ts index 305f5c6..cb26a6f 100644 --- a/src/build/dev.ts +++ b/src/build/dev.ts @@ -13,7 +13,9 @@ function getIndex(config: RollupOptions | RollupOptions[], output: readonly stri return config.findIndex(configItem => { const configOutputs = !configItem.output ? [] - : Array.isArray(configItem.output) ? configItem.output : [configItem.output] + : Array.isArray(configItem.output) + ? configItem.output + : [configItem.output] return configOutputs.map(({ file }) => file).find(out => out && output.includes(out)) }) @@ -22,26 +24,37 @@ function getIndex(config: RollupOptions | RollupOptions[], output: readonly stri export async function buildDev(name: string, config: RollupOptions | RollupOptions[], outputDirectories: string[]) { const watcher = watch(config) - // eslint-disable-next-line max-statements - watcher.on('event', async e => { - if (e.code === 'START') { - safeExec(() => lint(false, true), messages.lintingFail) - safeExec(() => generateTypes(outputDirectories), messages.typesFail) - } else if (e.code === 'BUNDLE_START') { - const index = getIndex(config, e.output) - - console.log(chalk.green(`Start building ${name}${index >= 0 ? `[${index}]` : ''} ...`)) - } else if (e.code === 'BUNDLE_END') { - const index = getIndex(config, e.output) - const duration = ms(e.duration, { secondsDecimalDigits: 1 }) - - console.log(chalk.green(`Build ${name}${index >= 0 ? `[${index}]` : ''} completed in ${duration}`)) - } else if (e.code === 'ERROR') { - const { id, loc /* , codeFrame*/ } = e.error - - console.log(chalk.red('Error', e.error.message)) - if (loc) console.log(chalk.green(id+':'+loc.line)) - // log(codeFrame) break - } + return new Promise((resolve, reject) => { + // eslint-disable-next-line max-statements + watcher.on('event', e => { + if (e.code === 'START') { + void safeExec(() => lint(false, true), messages.lintingFail) + void safeExec(() => generateTypes(outputDirectories), messages.typesFail) + } else if (e.code === 'BUNDLE_START') { + const index = getIndex(config, e.output) + const indexLabel = index >= 0 + ? `[${index}]` + : '' + + console.log(chalk.green(`Start building ${name}${indexLabel} ...`)) + } else if (e.code === 'BUNDLE_END') { + const index = getIndex(config, e.output) + const duration = ms(e.duration, { secondsDecimalDigits: 1 }) + const indexLabel = index >= 0 + ? `[${index}]` + : '' + + console.log(chalk.green(`Build ${name}${indexLabel} completed in ${duration}`)) + } else if (e.code === 'ERROR') { + const { id, loc /* , codeFrame*/ } = e.error + + console.log(chalk.red('Error', e.error.message)) + if (loc) console.log(chalk.green(`${id}:${loc.line}`)) + // log(codeFrame) break + reject(new Error(e.error.message)) + } else { + resolve() + } + }) }) } diff --git a/src/build/gen-types.ts b/src/build/gen-types.ts index 3bb599e..11e9c86 100644 --- a/src/build/gen-types.ts +++ b/src/build/gen-types.ts @@ -17,7 +17,7 @@ export function getDTSPath(srcScript: string, distPath: string, packageDirectory export async function generateTypes(outputDirectories: string[]) { const config = await readTSConfig(process.cwd()) - const target = config?.compilerOptions?.target || 'es5' + const target = config?.compilerOptions?.target ?? 'es5' for (let i = 0; i < outputDirectories.length; i++) { const outputDirectory = outputDirectories[i] @@ -31,6 +31,8 @@ export async function generateTypes(outputDirectories: string[]) { '--declarationMap', '--downlevelIteration', '--emitDeclarationOnly' - ], { stdio: i === 0 ? 'inherit' : 'ignore' }) + ], { stdio: i === 0 + ? 'inherit' + : 'ignore' }) } } diff --git a/src/build/index.ts b/src/build/index.ts index 061c8b8..df320c8 100644 --- a/src/build/index.ts +++ b/src/build/index.ts @@ -21,7 +21,9 @@ const outputs: OutputOptions[] = [ async function buildForDev(config: ReteConfig, pkg: Pkg, outputDirectories: string[]) { const targetConfig = getRollupConfig(config, outputs, pkg, outputDirectories) - const name = Array.from(new Set(Array.isArray(config) ? config.map(c => c.name) : [config.name])).join(', ') + const name = Array.from(new Set(Array.isArray(config) + ? config.map(c => c.name) + : [config.name])).join(', ') return await buildDev(name, targetConfig.map(c => c.config), outputDirectories) } @@ -39,7 +41,7 @@ async function build(config: ReteConfig, pkg: Pkg, outputDirectories: string[]) for (const target of targets) { const bundle = await rollup(target.config) - const distDirectory = target.options.output || '' + const distDirectory = target.options.output ?? '' for (const output of target.config.output) { await bundle.generate(output) @@ -56,8 +58,8 @@ export default async (configPath: string, watch?: boolean, outputDirectories?: s const config = importReteConfig(fullPath) const packagePath = join(process.cwd(), 'package.json') - const pkg = require(packagePath) - const output = outputDirectories || [join(process.cwd(), 'dist')] + const pkg = require(packagePath) as Pkg + const output = outputDirectories ?? [join(process.cwd(), 'dist')] if (watch) { await buildForDev(config, pkg, output) diff --git a/src/build/package-json.ts b/src/build/package-json.ts index a196905..d532624 100644 --- a/src/build/package-json.ts +++ b/src/build/package-json.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-undefined */ import fs from 'fs' import { join } from 'path' import { Plugin } from 'rollup' diff --git a/src/build/types.ts b/src/build/types.ts index 115df30..b75471f 100644 --- a/src/build/types.ts +++ b/src/build/types.ts @@ -7,10 +7,10 @@ export interface ReteOptions { output?: string plugins?: RollupOptions['plugins'] babel?: { - presets?: any[]; - plugins?: any[]; + presets?: any[] + plugins?: any[] } - nodeResolve?: RollupNodeResolveOptions | false, + nodeResolve?: RollupNodeResolveOptions | false globals?: OutputOptions['globals'] } export type Pkg = { name: string, version: string, author: string, license: string, scripts?: Record } diff --git a/src/build/utils.ts b/src/build/utils.ts index 599c351..117274c 100644 --- a/src/build/utils.ts +++ b/src/build/utils.ts @@ -9,7 +9,7 @@ export function setVerbose(enabled: boolean) { verbose = enabled } -export async function safeExec(func: () => Promise, failMessage: string, exit?: number): Promise { +export async function safeExec(func: () => Promise, failMessage: string, exit?: number): Promise { try { await func() } catch (error) { @@ -28,7 +28,9 @@ interface TSConfig { export async function readTSConfig(cwd: string): Promise { const configPath = join(cwd, 'tsconfig.json') - const exists = await fs.promises.access(configPath).then(() => true).catch(() => false) + const exists = await fs.promises.access(configPath) + .then(() => true) + .catch(() => false) if (!exists) return null diff --git a/src/doc/doc.ts b/src/doc/doc.ts index ce16628..cac0cd6 100644 --- a/src/doc/doc.ts +++ b/src/doc/doc.ts @@ -6,7 +6,7 @@ import { SOURCE_FOLDER } from '../consts' export async function doc(entries?: string[]) { const root = process.cwd() const outputDir = join(root, 'docs') - const entryPoints = (entries || [join(SOURCE_FOLDER, 'index.ts')]).map(entry => join(root, entry)) + const entryPoints = (entries ?? [join(SOURCE_FOLDER, 'index.ts')]).map(entry => join(root, entry)) const app = await Application.bootstrap({ excludeNotDocumented: true, excludePrivate: true, diff --git a/src/index.ts b/src/index.ts index ef2367a..0e4b7d0 100755 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,7 @@ import test from './test' const program = createCommand() -program.version(require('../package.json').version) +program.version((require('../package.json') as { version: string }).version) program .command('build') @@ -19,17 +19,17 @@ program .option('-w --watch') .option('-o --output ') .option('-v --verbose') - .action((options: { config: string, watch?: boolean, output?: string, verbose?: boolean }) => { + .action(async (options: { config: string, watch?: boolean, output?: string, verbose?: boolean }) => { if (options.verbose) setVerbose(true) - build(options.config, options.watch, options.output?.split(',')) + await build(options.config, options.watch, options.output?.split(',')) }) program .command('lint') .description('Lint using ESLint and TS parser') .option('--fix') - .action((options: { fix?: boolean }) => { - lint(options.fix) + .action(async (options: { fix?: boolean }) => { + await lint(options.fix) }) program @@ -37,7 +37,9 @@ program .description('Generate API docs') .option('--entries ', 'Comma-separated list of entry points') .action(async (options: { entries?: string }) => { - await doc(options.entries ? options.entries.split(',') : void 0) + await doc(options.entries + ? options.entries.split(',') + : void 0) }) program @@ -45,8 +47,8 @@ program .description('Run tests') .description('Run tests using Jest') .option('-w --watch') - .action((options: { watch?: boolean }) => { - test(options.watch) + .action(async (options: { watch?: boolean }) => { + await test(options.watch) }) program.parse(process.argv) diff --git a/src/lint/eslint/index.ts b/src/lint/eslint/index.ts index 8af1f28..defe811 100644 --- a/src/lint/eslint/index.ts +++ b/src/lint/eslint/index.ts @@ -29,9 +29,9 @@ export class ESLint implements BaseLinter { const result: LintMessage = { column: message.column, line: message.line, - endColumn: message.endColumn || message.column, - endLine: message.endLine || message.line, - ruleId: message.ruleId || null, + endColumn: message.endColumn ?? message.column, + endLine: message.endLine ?? message.line, + ruleId: message.ruleId ?? null, message: message.message, severity: message.severity } diff --git a/src/lint/formatter.ts b/src/lint/formatter.ts index 91f952b..494738a 100644 --- a/src/lint/formatter.ts +++ b/src/lint/formatter.ts @@ -49,6 +49,7 @@ export class Formatter { messages } } + private normalizeMessages(result: LintResult) { const newLineRegex = /[\s\n]{2,}/g @@ -68,14 +69,15 @@ export class Formatter { async format(results: LintResult[]) { const formatter = await this.eslint.loadFormatter('stylish') - return formatter.format(results - .map(this.normalizeMessages) - .map(this.sortMessages) - .map(this.toESLintResult), - { - cwd: process.cwd(), - rulesMeta: {} - } + return formatter.format( + results + .map(result => this.normalizeMessages(result)) + .map(result => this.sortMessages(result)) + .map(result => this.toESLintResult(result)), + { + cwd: process.cwd(), + rulesMeta: {} + } ) } } diff --git a/src/lint/linter.ts b/src/lint/linter.ts index a7e1c21..d6d74a4 100644 --- a/src/lint/linter.ts +++ b/src/lint/linter.ts @@ -25,7 +25,9 @@ export async function lint(fix?: boolean, quiet?: boolean) { } }) const formatter = new Formatter() - const resultText = await formatter.format(quiet ? errorResults : results) + const resultText = await formatter.format(quiet + ? errorResults + : results) console.log(resultText) } diff --git a/src/lint/results.ts b/src/lint/results.ts index af91a9a..a73bea4 100644 --- a/src/lint/results.ts +++ b/src/lint/results.ts @@ -25,7 +25,7 @@ export function makeRelativePath(result: T): T { } export function mergeResults(results: T[]): T[] { - return results.reduce((acc, result) => { + return results.reduce((acc, result) => { const existingResult = acc.find(r => r.filePath === result.filePath) if (existingResult) { @@ -35,5 +35,5 @@ export function mergeResults(results: T[]): T[] { } return acc - }, [] as T[]) + }, []) } diff --git a/src/lint/type-check/index.ts b/src/lint/type-check/index.ts index 0f0b98a..0295998 100644 --- a/src/lint/type-check/index.ts +++ b/src/lint/type-check/index.ts @@ -16,16 +16,18 @@ export class TypeCheck implements BaseLinter { return tsDiagnostics.map(diagnostic => { const data: LintResult = { - filePath: diagnostic.getSourceFile()?.getFilePath() || '', - messages: [{ - ruleId: 'typescript', - message: getMessage(diagnostic), - severity: 2, - line: diagnostic.getLineNumber() || 0, - endLine: diagnostic.getLineNumber() || 0, - column: diagnostic.getStart() || 0, - endColumn: (diagnostic.getStart() || 0) + (diagnostic.getLength() || 1) - }] + filePath: diagnostic.getSourceFile()?.getFilePath() ?? '', + messages: [ + { + ruleId: 'typescript', + message: getMessage(diagnostic), + severity: 2, + line: diagnostic.getLineNumber() ?? 0, + endLine: diagnostic.getLineNumber() ?? 0, + column: diagnostic.getStart() ?? 0, + endColumn: (diagnostic.getStart() ?? 0) + (diagnostic.getLength() ?? 1) + } + ] } return data diff --git a/src/lint/type-check/messages.ts b/src/lint/type-check/messages.ts index dcf97ce..a7a2b51 100644 --- a/src/lint/type-check/messages.ts +++ b/src/lint/type-check/messages.ts @@ -1,13 +1,13 @@ import ts from 'ts-morph' -export function getMessage(diagnostic: ts.Diagnostic) { +export function getMessage(diagnostic: ts.Diagnostic) { const messageText = diagnostic.getMessageText() if (typeof messageText === 'string') { return messageText } - const next = messageText.getNext() || [] + const next = messageText.getNext() ?? [] return `${messageText.getMessageText()} ${next.map(m => m.getMessageText()).join(' ')}`.trim() } diff --git a/src/lint/type-coverage/index.ts b/src/lint/type-coverage/index.ts index c06ec53..401048b 100644 --- a/src/lint/type-coverage/index.ts +++ b/src/lint/type-coverage/index.ts @@ -10,17 +10,13 @@ export class TypeCoverage implements BaseLinter { async run(): Promise { const result = await lint(this.options.src, { strict: true, notOnlyInCWD: true }) - const groups = result.anys.reduce((acc, any) => { - if (!acc[any.file]) { - acc[any.file] = [] - } - + const groups = result.anys.reduce>((acc, any) => { acc[any.file].push(any) return acc - }, {} as Record) + }, Object.fromEntries(result.anys.map(any => [any.file, []]))) return Object.entries(groups).map(([file, anys]) => { - return { + return { filePath: file, messages: anys.map(any => ({ ruleId: 'type-coverage-any', @@ -31,7 +27,7 @@ export class TypeCoverage implements BaseLinter { column: any.character + 1, endColumn: any.character + 1 + (any.text.length || 1) })) - } + } satisfies LintResult }) } } diff --git a/src/test/index.ts b/src/test/index.ts index 6fe2c5f..ddb7153 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -8,9 +8,11 @@ export default async function (watch?: boolean) { '--testEnvironment', 'node', '--collectCoverageFrom', 'src/**/*', '--testMatch', '**/*.test.ts', - ...(watch ? ['--watch'] : []) + ...watch + ? ['--watch'] + : [] ], { stdio: 'inherit' }) - } catch (e) { + } catch (_error) { process.exit(1) } }