diff --git a/bin/cli.js b/bin/cli.js index 3fc666a..6061722 100644 --- a/bin/cli.js +++ b/bin/cli.js @@ -25,16 +25,15 @@ // Imports import { cliArgvUtil } from 'cli-argv-util'; import { replacer } from '../dist/replacer.js'; -import fs from 'fs'; -import path from 'path'; +import fs from 'fs'; +import path from 'path'; // Parameters and flags -const validFlags = ['cd', 'concat', 'content', 'exclude', 'ext', 'find', 'header', 'no-liquid' ,'no-source-map', - 'note', 'quiet', 'regex', 'rename', 'replacement', 'summary']; -validFlags.push('pkg'); //deprecated flag -const cli = cliArgvUtil.parse(validFlags); -const source = cli.params[0]; //origin file or folder -const target = cli.params[1]; //destination folder +const validFlags = ['cd', 'concat', 'content', 'exclude', 'ext', 'find', 'header', 'no-liquid', + 'no-source-map', 'note', 'quiet', 'regex', 'rename', 'replacement', 'summary']; +const cli = cliArgvUtil.parse(validFlags); +const source = cli.params[0]; //origin file or folder +const target = cli.params[1]; //destination folder // Escapers const escapers = [ @@ -61,9 +60,7 @@ const error = cli.paramsCount > 2 ? 'Extraneous parameter: ' + cli.params[2] : null; if (error) - throw Error('[replacer-util] ' + error); -if (cli.flagOn.pkg) - console.log('[replacer-util] The --pkg flag is deprecated as the package.json file is now always loaded.'); + throw new Error('[replacer-util] ' + error); const sourceFile = path.join(cli.flagMap.cd ?? '', source); const isFile = fs.existsSync(sourceFile) && fs.statSync(sourceFile).isFile(); const sourceFolder = isFile ? path.dirname(source) : source; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..76686d1 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,22 @@ +// @ts-check + +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default [ + eslint.configs.recommended, + ...tseslint.configs.strictTypeChecked, + { ignores: ['**/*.js'] }, + { + languageOptions: { parserOptions: { projectService: true } }, + rules: { + '@typescript-eslint/no-confusing-void-expression': 'off', //prefer minimal arrow functions + '@typescript-eslint/no-floating-promises': 'off', //annimations may be fire-and-forget + '@typescript-eslint/no-misused-promises': 'off', //annimations may be fire-and-forget + '@typescript-eslint/no-non-null-assertion': 'off', //ts cannot always know value exists + '@typescript-eslint/restrict-template-expressions': 'off', //numbers in templates are natural + '@typescript-eslint/unbound-method': 'off', //safer to not use 'this' + '@typescript-eslint/use-unknown-in-catch-callback-variable': 'off', //clarity over theoretical exceptions + }, + }, + ]; diff --git a/package.json b/package.json index 896fc14..39c8bd3 100644 --- a/package.json +++ b/package.json @@ -44,32 +44,13 @@ "node": true, "mocha": true }, - "eslintConfig": { - "ignorePatterns": [ - "build", - "dist", - "node_modules" - ], - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "@typescript-eslint/no-non-null-assertion": "off" - } - }, "runScriptsConfig": { "clean": [ "rimraf build dist spec/fixtures/target" ], "lint": [ "jshint . --exclude-path .gitignore", - "eslint --max-warnings 0 . --ext .ts" + "eslint --max-warnings 0" ], "build": [ "tsc", @@ -85,29 +66,29 @@ "chalk": "~5.3", "cli-argv-util": "~1.2", "fancy-log": "~2.0", - "glob": "~10.4", + "glob": "~11.0", "istextorbinary": "~9.5", - "liquidjs": "~10.13", + "liquidjs": "~10.16", "slash": "~5.1" }, "devDependencies": { - "@eslint/js": "~9.3", - "@fortawesome/fontawesome-free": "~6.5", + "@eslint/js": "~9.9", + "@fortawesome/fontawesome-free": "~6.6", "@types/fancy-log": "~2.0", - "@types/node": "~20.12", + "@types/node": "~22.2", "add-dist-header": "~1.4", "assert-deep-strict-equal": "~1.2", "copy-file-util": "~1.2", - "eslint": "8.57.0", + "eslint": "~9.9", "fetch-json": "~3.3", - "highlight.js": "~11.9", + "highlight.js": "~11.10", "jshint": "~2.13", - "mocha": "~10.4", + "mocha": "~10.7", "pretty-print-json": "~3.0", - "rimraf": "~5.0", - "run-scripts-util": "~1.2", - "typescript": "~5.4", - "typescript-eslint": "~7.11", + "rimraf": "~6.0", + "run-scripts-util": "~1.3", + "typescript": "~5.5", + "typescript-eslint": "~8.0", "w3c-html-validator": "~1.8" } } diff --git a/replacer.ts b/replacer.ts index 89f089f..217654a 100644 --- a/replacer.ts +++ b/replacer.ts @@ -37,6 +37,9 @@ export type ResultsFile = Results['files'][0]; export type ReporterSettings = { summaryOnly: boolean, //only print out the single line summary message }; +type PkgObj = { [subkey: string]: string }; +type Pkg = { [key: string]: PkgObj }; +type PageVars = { [name: string]: string }; const task = { normalizeFolder(folderPath: string): string { @@ -48,10 +51,10 @@ const task = { // Returns true if the file is not a binary file such as a .png or .jpg file. return fs.statSync(filename).isFile() && !isBinary(filename); }, - readPackageJson() { + readPackageJson(): Pkg { // Returns package.json as an object literal. - const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8')); - const fixHiddenKeys = (pkgObj: { [key: string]: string }) => { + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8')); + const fixHiddenKeys = (pkgObj: PkgObj) => { const unhide = (key: string) => { const newKey = key.replace(/[@./]/g, '-'); if (!pkgObj[newKey]) @@ -59,9 +62,9 @@ const task = { }; Object.keys(pkgObj).forEach(unhide); }; - if (pkg?.dependencies) + if (pkg.dependencies) fixHiddenKeys(pkg.dependencies); - if (pkg?.devDependencies) + if (pkg.devDependencies) fixHiddenKeys(pkg.devDependencies); return pkg; }, @@ -100,7 +103,7 @@ const replacer = { missingFind ? 'Must specify search text with --find or --regex' : null; if (errorMessage) - throw Error('[replacer-util] ' + errorMessage); + throw new Error('[replacer-util] ' + errorMessage); const globFiles = () => exts.map(ext => globSync(source + '/**/*' + ext)).flat().sort(); const keep = (file: string) => @@ -148,7 +151,7 @@ const replacer = { engine.registerFilter('major-version', versionFormatter(1)); return engine; }; - const extractPageVars = (engine: Liquid, file: string) => { + const extractPageVars = (engine: Liquid, file: string): PageVars => { // Exammple: // {% assign colorScheme = 'dark mode' %} ==> { colorScheme: 'dark mode' } type AssignTag = { //warning: this type accesses unsupported private fields @@ -159,12 +162,12 @@ const replacer = { const tags = engine.parseFileSync(file); const toPair = (tag: AssignTag) => [tag.key, tag.value.initial.postfix[0]?.content]; const tagPairs = tags.filter(tag => tag.name === 'assign').map(toPair); - return Object.fromEntries(tagPairs); + return Object.fromEntries(tagPairs); } const processFile = (file: ResultsFile, index: number) => { - const engine = createEngine(file); + const engine = createEngine(file); const pageVars = settings.content ? extractPageVars(engine, file.origin) : {}; - const render = (text: string) => engine.parseAndRenderSync(text, pageVars); + const render = (text: string) => engine.parseAndRenderSync(text, pageVars); const append = settings.concat && index > 0; const altText = settings.content ? render(settings.content) : null; const text = altText ?? fs.readFileSync(file.origin, 'utf-8'); diff --git a/spec/fixtures/target/mock1.html b/spec/fixtures/target/mock1.html index 042e8d4..94ee469 100644 --- a/spec/fixtures/target/mock1.html +++ b/spec/fixtures/target/mock1.html @@ -4,10 +4,10 @@ 🔍🔍🔍 replacer-util 🔍🔍🔍 - + - +
diff --git a/spec/fixtures/target/web/index.html b/spec/fixtures/target/web/index.html index 084813e..a7d17a6 100644 --- a/spec/fixtures/target/web/index.html +++ b/spec/fixtures/target/web/index.html @@ -4,10 +4,10 @@ 🔍🔍🔍 replacer-util 🔍🔍🔍 - + - +