diff --git a/.eslintrc.json b/.eslintrc.json index ffeef24..203a549 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,8 +15,7 @@ "eslint-plugin-mocha", "eslint-plugin-no-null", "eslint-plugin-sonarjs", - "@typescript-eslint", - "@typescript-eslint/tslint" + "@typescript-eslint" ], "rules": { "@typescript-eslint/adjacent-overload-signatures": "error", @@ -291,72 +290,6 @@ "sonarjs/no-redundant-jump": "error", "sonarjs/no-same-line-conditional": "error", "sonarjs/no-useless-catch": "error", - "sonarjs/prefer-immediate-return": "error", - "@typescript-eslint/tslint/config": [ - "error", - { - "rules": { - "ban": [ - true, - { - "message": "use lodash isString", - "name": [ - "util", - "isString" - ] - }, - { - "message": "use lodash isNil", - "name": [ - "util", - "isNullOrUndefined" - ] - } - ], - "import-spacing": true, - "jsdoc-format": [ - true, - "check-multiline-start" - ], - "no-dynamic-delete": true, - "no-inferred-empty-object-type": true, - "no-reference-import": true, - "object-literal-sort-keys": true, - "one-line": [ - true, - "check-catch", - "check-else", - "check-finally", - "check-open-brace", - "check-whitespace" - ], - "prefer-switch": true, - "strict-type-predicates": true, - "trailing-comma": [ - true, - { - "esSpecCompliant": true, - "multiline": { - "arrays": "always", - "functions": "never", - "object": "always" - }, - "singleline": "never" - } - ], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-typecast", - "check-type-operator", - "check-rest-spread" - ] - } - } - ] + "sonarjs/prefer-immediate-return": "error" } } diff --git a/config/tsconfig.json b/config/tsconfig.json index 88624f9..420558a 100755 --- a/config/tsconfig.json +++ b/config/tsconfig.json @@ -13,7 +13,7 @@ "es2017", "esnext.asynciterable" ], - "module": "es6", + "module": "esnext", "moduleResolution": "node", "noImplicitAny": true, "noImplicitReturns": true, diff --git a/src/app.ts b/src/app.ts index ae3c197..57a86d1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,5 @@ import { createLogger } from 'bunyan'; import yargs from 'yargs'; -const { showCompletionScript } = yargs; import { loadConfig } from './config/index.js'; import { CONFIG_ARGS_NAME, CONFIG_ARGS_PATH, MODE, parseArgs } from './config/args.js'; @@ -19,7 +18,7 @@ export const STATUS_MAX = 255; export async function main(argv: Array): Promise { const { args, mode } = await parseArgs(argv.slice(ARGS_START)); if (mode === MODE.complete) { - showCompletionScript(); + yargs(argv).showCompletionScript(); return STATUS_SUCCESS; } diff --git a/src/config/args.ts b/src/config/args.ts index b17669b..a160d2b 100644 --- a/src/config/args.ts +++ b/src/config/args.ts @@ -1,5 +1,4 @@ import yargs, { Options } from 'yargs'; -const { usage } = yargs; import { RuleSelector, RuleSources } from '../rule/index.js'; import { VERSION_INFO } from '../version.js'; @@ -11,8 +10,6 @@ export enum MODE { list = 'list', } -/* eslint-disable @typescript-eslint/no-explicit-any */ - export const CONFIG_ARGS_NAME = 'config-name'; export const CONFIG_ARGS_PATH = 'config-path'; @@ -23,6 +20,7 @@ const RULE_OPTION: Options = { }; export interface Args { + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ args: any; mode: string; } @@ -50,15 +48,16 @@ export interface ParseResults { export async function parseArgs(argv: Array): Promise { let mode: MODE = MODE.check; - const parser = usage('Usage: salty-dog [options]') + const parser = yargs(argv).usage('Usage: salty-dog [options]') .command({ command: ['check', '*'], describe: 'validate the source documents', - handler: (argi: any) => { + handler: (argi: unknown) => { mode = MODE.check; }, }) .command({ + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ builder: (cmd: any) => cmd.options({ coerce: { default: false, @@ -75,21 +74,21 @@ export async function parseArgs(argv: Array): Promise { }), command: ['fix'], describe: 'validate the source document and insert defaults', - handler: (argi: any) => { + handler: (argi: unknown) => { mode = MODE.fix; }, }) .command({ command: ['list'], describe: 'list active rules', - handler: (argi: any) => { + handler: (argi: unknown) => { mode = MODE.list; }, }) .command({ command: ['complete'], describe: 'generate tab completion script for bash or zsh', - handler: (argi: any) => { + handler: (argi: unknown) => { mode = MODE.complete; }, }) @@ -165,6 +164,7 @@ export async function parseArgs(argv: Array): Promise { .alias('version', 'v'); // @TODO: this should not need a cast but the parser's type omits command options and doesn't expose camelCase + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const args = parser.parse(argv) as any; return { diff --git a/src/config/index.ts b/src/config/index.ts index 93f14cb..5c2b563 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,7 +1,8 @@ import { doesExist, NotFoundError } from '@apextoaster/js-utils'; import { Stream } from 'bunyan'; import { LogLevel } from 'noicejs'; -import { join } from 'path'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; import { YamlParser } from '../parser/YamlParser.js'; import { readSource } from '../source.js'; @@ -18,6 +19,10 @@ export interface ConfigData { }; } +export function dirName(): string { + return dirname(fileURLToPath(import.meta.url)); +} + /** * With the given name, generate all potential config paths in their complete, absolute form. * @@ -37,8 +42,9 @@ export function completePaths(name: string, extras: Array): Array): Promis if (doesExist(data)) { const parser = new YamlParser(); const [head] = parser.parse(data); - return head; + + /* eslint-disable-next-line sonarjs/prefer-immediate-return */ + return head as any; // TODO: validate config } } diff --git a/src/lib.ts b/src/lib.ts index 54ad09d..cd2ab2c 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -1,5 +1,5 @@ import { VERSION_INFO } from './version.js'; -export default { +export { VERSION_INFO, }; diff --git a/src/parser/YamlParser.ts b/src/parser/YamlParser.ts index 7f776aa..2dead4e 100644 --- a/src/parser/YamlParser.ts +++ b/src/parser/YamlParser.ts @@ -26,8 +26,8 @@ export class YamlParser implements Parser { include.setSchema(this.schema); } - public dump(...data: Array): string { - const docs: Array = []; + public dump(...data: Array): string { + const docs: Array = []; for (const doc of data) { const part = dump(doc, { schema: this.schema, @@ -37,9 +37,9 @@ export class YamlParser implements Parser { return docs.join('\n---\n\n'); } - public parse(body: string): Array { - const docs: Array = []; - loadAll(body, (doc: any) => docs.push(doc), { + public parse(body: string): Array { + const docs: Array = []; + loadAll(body, (doc: unknown) => docs.push(doc), { schema: this.schema, }); return docs; diff --git a/src/parser/index.ts b/src/parser/index.ts index f0a2bea..a8962ed 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -1,4 +1,4 @@ export interface Parser { - dump(...data: Array): string; - parse(body: string): Array; -} \ No newline at end of file + dump(...data: Array): string; + parse(body: string): Array; +} diff --git a/src/rule/SchemaRule.ts b/src/rule/SchemaRule.ts index 79cd69f..889ddb3 100644 --- a/src/rule/SchemaRule.ts +++ b/src/rule/SchemaRule.ts @@ -1,12 +1,12 @@ import { doesExist, hasItems } from '@apextoaster/js-utils'; import { ErrorObject, ValidateFunction } from 'ajv'; +import lodash from 'lodash'; import { LogLevel } from 'noicejs'; -import { Rule, RuleData } from './index.js'; import { Visitor, VisitorError, VisitorResult } from '../visitor/index.js'; import { VisitorContext } from '../visitor/VisitorContext.js'; +import { Rule, RuleData } from './index.js'; -import lodash from 'lodash'; const { cloneDeep, defaultTo } = lodash; diff --git a/src/rule/index.ts b/src/rule/index.ts index ab5cecd..6e2599e 100644 --- a/src/rule/index.ts +++ b/src/rule/index.ts @@ -162,13 +162,23 @@ export async function loadRulePaths(paths: Array, ctx: VisitorContext): return rules; } -export async function loadRuleModules(modules: Array, ctx: VisitorContext, r = require): Promise> { +type LoadBack = (path: string) => Promise; + +export async function loadRuleModules(modules: Array, ctx: VisitorContext, load?: LoadBack): Promise> { const rules = []; + function loadModule(path: string) { + if (doesExist(load)) { + return load(path); + } else { + return import(path); + } + } + for (const name of modules) { try { /* eslint-disable-next-line @typescript-eslint/no-var-requires */ - const data: RuleSourceModule = r(name); + const data: RuleSourceModule = await loadModule(name); if (!validateRules(ctx, data)) { ctx.logger.error({ module: name, @@ -218,7 +228,7 @@ export async function resolveRules(rules: Array, selector: RuleSelector): } export function validateRules(ctx: VisitorContext, root: any): boolean { - const { definitions, name } = {} as any; // ruleSchemaData as any; // TODO: fix this + const { definitions, name } = { definitions: { config: {} } } as any; // ruleSchemaData as any; const validCtx = new VisitorContext(ctx); validCtx.addSchema(name, definitions); @@ -233,7 +243,7 @@ export function validateRules(ctx: VisitorContext, root: any): boolean { } export function validateConfig(ctx: VisitorContext, root: any): boolean { - const { definitions, name } = {} as any; // ruleSchemaData as any; + const { definitions, name } = { definitions: { config: {} } } as any; // ruleSchemaData as any; const validCtx = new VisitorContext(ctx); validCtx.addSchema(name, definitions); diff --git a/src/visitor/index.ts b/src/visitor/index.ts index f58ba9b..93dce51 100644 --- a/src/visitor/index.ts +++ b/src/visitor/index.ts @@ -3,6 +3,8 @@ import { LogLevel } from 'noicejs'; import { VisitorContext } from './VisitorContext.js'; +/* eslint-disable @typescript-eslint/no-explicit-any */ + /** * This is a runtime error, not an exception. */ @@ -20,7 +22,7 @@ export interface VisitorResult { export interface Visitor { /** * Select nodes eligible to be visited. - **/ + */ pick(ctx: VisitorContext, root: any): Promise>; /** diff --git a/test/config/TestConfig.ts b/test/config/TestConfig.ts index 33656c5..663d935 100644 --- a/test/config/TestConfig.ts +++ b/test/config/TestConfig.ts @@ -2,7 +2,9 @@ import { NotFoundError } from '@apextoaster/js-utils'; import { expect } from 'chai'; import { join } from 'path'; -import { loadConfig, readConfig } from '../../src/config/index.js'; +import { dirName, loadConfig, readConfig } from '../../src/config/index.js'; + +const __dirname = dirName(); describe('load config helper', async () => { it('should load an existing config', async () => diff --git a/test/rule/TestLoadRule.ts b/test/rule/TestLoadRule.ts index cd0b382..dba37c1 100644 --- a/test/rule/TestLoadRule.ts +++ b/test/rule/TestLoadRule.ts @@ -3,11 +3,14 @@ import { vol } from 'memfs'; import { LogLevel, NullLogger } from 'noicejs'; import { spy, stub } from 'sinon'; +import { dirName } from '../../src/config/index.js'; import { loadRuleFiles, loadRuleModules, loadRulePaths, loadRuleSource } from '../../src/rule/index.js'; import { SchemaRule } from '../../src/rule/SchemaRule.js'; import { Filesystem, setFs } from '../../src/source.js'; import { VisitorContext } from '../../src/visitor/VisitorContext.js'; +const __dirname = dirName(); + const EXAMPLE_EMPTY = '{name: foo, definitions: {}, rules: []}'; const EXAMPLE_RULES = `{ name: foo, diff --git a/yarn.lock b/yarn.lock index 714258c..9278f41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -467,9 +467,9 @@ source-map "^0.6.0" "@types/yargs-parser@*": - version "13.1.0" - resolved "https://artifacts.apextoaster.com/repository/group-npm/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" - integrity sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg== + version "20.2.1" + resolved "https://artifacts.apextoaster.com/repository/group-npm/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== "@types/yargs@17.0.8": version "17.0.8"