From d598c2b7f6c2b5e21588efcf3405a1c32bb5bc4a Mon Sep 17 00:00:00 2001 From: ImLunaHey <105922175+ImLunaHey@users.noreply.github.com> Date: Wed, 1 Mar 2023 12:01:16 +1030 Subject: [PATCH] feat: modernise repo --- .github/workflows/test.yaml | 53 +++++++++++++++++++++ .gitignore | 2 + .mocharc.js | 6 +++ .travis.yml | 15 ------ .vscode/settings.json | 13 ----- lib/index.ts | 30 ++++++++---- lib/lib.ts | 95 +++++++++++++++++++++---------------- package.json | 72 ++++++++++++++-------------- test/lib.spec.ts | 4 +- test/mocha.opts | 4 -- 10 files changed, 172 insertions(+), 122 deletions(-) create mode 100644 .github/workflows/test.yaml create mode 100644 .mocharc.js delete mode 100644 .travis.yml delete mode 100644 .vscode/settings.json delete mode 100644 test/mocha.opts diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..9f5727c --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,53 @@ +name: Node.js CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x, 18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.version }} + - run: npm ci + - run: npm run lint + + test: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x, 18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.version }} + - run: npm ci + - run: npm run test + + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x, 18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.version }} + - run: npm ci + - run: npm run build:next diff --git a/.gitignore b/.gitignore index c9d1bbd..b688bbd 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,5 @@ typings/ dist **/.rts* sample.js +.parcel-cache +.vscode \ No newline at end of file diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 0000000..658a245 --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,6 @@ +module.exports = { + "spec": "test/**/*.spec.ts", + "watch-extensions": "ts", + "require": "ts-node/register", + "exit": true, +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2d37413..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: node_js -node_js: - - "10" -cache: - directories: - - ~/.npm -notifications: - email: false -script: - - npm run test -after_success: - - npm run coverage -branches: - only: master - except: /^v\d+\.\d+\.\d+$/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b32dadb..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "editor.formatOnSave": true, - "[javascript]": { - "editor.formatOnSave": false - }, - "[javascriptreact]": { - "editor.formatOnSave": false - }, - "prettier.disableLanguages": ["javascript", "javascriptreact"], - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - } -} diff --git a/lib/index.ts b/lib/index.ts index 052f332..cea5d61 100755 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,8 +1,8 @@ #!/usr/bin/env node -import cp from "child_process"; -import meow from "meow"; -import { syncEnv } from "./lib"; +import cp from 'child_process'; +import meow from 'meow'; +import { syncEnv } from './lib'; const cli = meow( ` @@ -27,19 +27,29 @@ const cli = meow( `, { flags: { + env: { + type: 'string', + alias: 'e', + }, sample: { - type: "string" - } - } + type: 'string', + alias: 's', + }, + samples: { + type: 'string', + alias: 'S', + }, + }, } ); -const { sample, s, env, e, samples, S } = cli.flags; +const { sample, env, samples } = cli.flags; -syncEnv(sample || s, env || e, samples || S) - .then(sampleEnv => cp.exec(`git add ${sampleEnv}`)) +syncEnv(sample, env, samples) + .then((sampleEnv) => cp.exec(`git add ${sampleEnv}`)) .catch(({ message, code }) => { - console.log(message); + // eslint-disable-next-line no-console + console.error(message); process.exit(code); }); diff --git a/lib/lib.ts b/lib/lib.ts index f9aa5bc..04e59cd 100644 --- a/lib/lib.ts +++ b/lib/lib.ts @@ -1,12 +1,12 @@ -import { resolve, basename } from "path"; -import fs from "fs"; +import { resolve, basename } from 'path'; +import fs from 'fs'; import os from 'os'; -import parseEnv from "parse-dotenv"; -import globby from "globby"; -import pkgConf from "pkg-conf"; +import parseEnv from 'parse-dotenv'; +import globby from 'globby'; +import pkgConf from 'pkg-conf'; -const DEFAULT_ENV_PATH = resolve(process.cwd(), ".env"); -const DEFAULT_SAMPLE_ENV = resolve(process.cwd(), ".env.example"); +const DEFAULT_ENV_PATH = resolve(process.cwd(), '.env'); +const DEFAULT_SAMPLE_ENV = resolve(process.cwd(), '.env.example'); interface EnvObject { [key: string]: any; @@ -24,27 +24,29 @@ export const getObjKeys = (obj: object) => Object.keys(obj); export const envToString = (parsed: EnvObject) => getObjKeys(parsed) - .map(key => `${key}=${parsed[key] || ""}`) + .map((key) => `${key}=${parsed[key] || ''}`) .join(os.EOL) - .replace(/(__\w+_\d+__=)/g, ""); + .replace(/(__\w+_\d+__=)/g, ''); export const writeToSampleEnv = (path: string, parsedEnv: object) => { try { fs.writeFileSync(path, envToString(parsedEnv)); - } catch (e) { - throw new Error(`Sync failed. ${e.message}`); + } catch (error: unknown) { + throw new Error( + `Sync failed. ${error instanceof Error ? error.message : String(error)}` + ); } }; export const emptyObjProps = (obj: EnvObject) => { const objCopy = { ...obj }; - Object.keys(objCopy).forEach(key => { - if (objCopy[key].includes("#")) { + Object.keys(objCopy).forEach((key) => { + if (objCopy[key].includes('#')) { if (objCopy[key].match(/(".*"|'.*')/g)) { const objArr = objCopy[key].split(/(".*"|'.*')/); objCopy[key] = objArr.slice(-1)[0].trim(); } else { - const objArr = objCopy[key].split("#"); + const objArr = objCopy[key].split('#'); objCopy[key] = `#${objArr.slice(-1)[0]}`; } @@ -52,8 +54,8 @@ export const emptyObjProps = (obj: EnvObject) => { } /* istanbul ignore else */ - if (!key.startsWith("__COMMENT_")) { - objCopy[key] = ""; + if (!key.startsWith('__COMMENT_')) { + objCopy[key] = ''; } }); @@ -65,21 +67,22 @@ export const getUniqueVarsFromEnvs = async ( envExample: EnvObject, config: Config = {} ) => { - let ignoreKeys = config.preserve || []; + const ignoreKeys = config.preserve || []; const uniqueKeys = new Set(getObjKeys(env)); const uniqueKeysArray: Array = Array.from(uniqueKeys); - let uniqueFromSource = uniqueKeysArray.map((key: string) => { - if (key.startsWith("__COMMENT_")) return { [key]: env[key] }; - return { [key]: envExample[key] || "" }; + const uniqueFromSource = uniqueKeysArray.map((key: string) => { + if (key.startsWith('__COMMENT_')) return { [key]: env[key] }; + return { [key]: envExample[key] || '' }; }); - let presevedVars = getObjKeys(envExample) - .map(key => ({ [key]: envExample[key] })) - .filter(env => { - return ignoreKeys.length && ignoreKeys.includes(getObjKeys(env)[0]); - }); + const presevedVars = getObjKeys(envExample) + .map((key) => ({ [key]: envExample[key] })) + .filter( + // eslint-disable-next-line no-shadow + (env) => ignoreKeys.length && ignoreKeys.includes(getObjKeys(env)[0]) + ); return [...uniqueFromSource, ...presevedVars]; }; @@ -90,21 +93,27 @@ export const syncWithSampleEnv = async ( initialConfig?: Config ) => { // We do this so we can pass it via test as well - let config: Config = initialConfig || (await pkgConf("sync-dotenv")) as any; + const config: Config = + initialConfig || ((await pkgConf('sync-dotenv')) as any); // Set defaults - config.comments = typeof config.comments === 'undefined' ? true : config.comments; - config.emptyLines = typeof config.emptyLines === 'undefined' ? true : config.comments; - - let sourceEnv = emptyObjProps( - parseEnv(envPath, { emptyLines: !!config.emptyLines, comments: !!config.comments }) + config.comments = + typeof config.comments === 'undefined' ? true : config.comments; + config.emptyLines = + typeof config.emptyLines === 'undefined' ? true : config.comments; + + const sourceEnv = emptyObjProps( + parseEnv(envPath, { + emptyLines: !!config.emptyLines, + comments: !!config.comments, + }) ); - let targetEnv = parseEnv(envExamplePath); + const targetEnv = parseEnv(envExamplePath); const uniqueVars = await getUniqueVarsFromEnvs(sourceEnv, targetEnv, config); - let envCopy: EnvObject = {}; - uniqueVars.forEach(env => { - let [key] = getObjKeys(env); + const envCopy: EnvObject = {}; + uniqueVars.forEach((env) => { + const [key] = getObjKeys(env); envCopy[key] = env[key]; }); @@ -112,6 +121,7 @@ export const syncWithSampleEnv = async ( }; const exit = (message: string, code: number = 1) => + // eslint-disable-next-line prefer-promise-reject-errors Promise.reject({ message, code }); export const syncEnv = async ( @@ -119,16 +129,17 @@ export const syncEnv = async ( source?: string, samples?: string ): Promise<{ msg: string; code: number } | string> => { - if (sampleEnv && (sampleEnv === ".env" || basename(sampleEnv) === ".env")) - return exit("Cannot sync .env with .env"); + if (sampleEnv && (sampleEnv === '.env' || basename(sampleEnv) === '.env')) + return exit('Cannot sync .env with .env'); const SAMPLE_ENV_PATHS: string[] = !samples ? [resolve(process.cwd(), sampleEnv || DEFAULT_SAMPLE_ENV)] : globby - .sync(samples) - .map((sample: string) => resolve(process.cwd(), sample)); + .sync(samples) + .map((sample: string) => resolve(process.cwd(), sample)); - let envPath = source + // eslint-disable-next-line no-nested-ternary + const envPath = source ? fileExists(source) ? source : null @@ -146,9 +157,9 @@ export const syncEnv = async ( const sourcePath = envPath; - for (let samplePath of SAMPLE_ENV_PATHS) { + for (const samplePath of SAMPLE_ENV_PATHS) { await syncWithSampleEnv(sourcePath, samplePath); } - return Promise.resolve(SAMPLE_ENV_PATHS.join(" ")); + return Promise.resolve(SAMPLE_ENV_PATHS.join(' ')); }; diff --git a/package.json b/package.json index a7d0080..a3e85d6 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,7 @@ }, "scripts": { "add-contributor": "all-contributors add", - "build": "npm-run-all clean start", - "bundle": "npm-run-all clean parcel", + "build": "npm-run-all clean parcel", "clean": "rimraf dist", "coverage": "nyc report --reporter=text-lcov | coveralls", "parcel": "parcel build", @@ -48,50 +47,51 @@ "start": "node dist/index.js", "start:dev": "nodemon --watch lib -e ts --exec npm run build", "test": "nyc --reporter=html --reporter=text mocha", - "test:watch": "nodemon --watch test -e .ts --exec npm test" + "test:watch": "nodemon --watch test -e .ts --exec npm test", + "lint": "eslint lib --ext .ts" }, "devDependencies": { - "@parcel/packager-ts": "2.3.2", - "@parcel/transformer-typescript-types": "2.3.2", - "@types/chai": "4.1.7", + "@parcel/packager-ts": "2.8.3", + "@parcel/transformer-typescript-types": "2.8.3", + "@types/chai": "4.3.4", + "@types/eslint": "8.21.1", + "@types/eslint-plugin-prettier": "3.1.0", "@types/execa": "0.9.0", "@types/globby": "9.1.0", "@types/meow": "5.0.0", - "@types/mocha": "5.2.6", - "@types/sinon": "7.0.11", - "@types/sinon-chai": "3.2.2", - "all-contributors-cli": "6.2.0", + "@types/mocha": "10.0.1", + "@types/nodemon": "1.19.2", + "@types/prettier": "2.7.2", + "@types/sinon": "10.0.13", + "@types/sinon-chai": "3.2.9", + "all-contributors-cli": "6.24.0", "babel-eslint": "9.0.0", - "chai": "4.2.0", - "coveralls": "3.0.3", - "dotenv": "7.0.0", - "eslint": "5.16.0", - "eslint-config-airbnb": "17.1.0", - "eslint-config-prettier": "4.1.0", - "eslint-config-wesbos": "0.0.19", - "eslint-plugin-html": "5.0.3", - "eslint-plugin-import": "2.16.0", - "eslint-plugin-jsx-a11y": "6.2.1", - "eslint-plugin-prettier": "3.0.1", - "eslint-plugin-react": "7.12.4", - "eslint-plugin-react-hooks": "1.6.0", - "mocha": "6.1.4", - "nodemon": "1.18.11", - "np": "3.1.0", + "chai": "4.3.7", + "coveralls": "3.1.1", + "dotenv": "16.0.3", + "eslint": "8.35.0", + "eslint-config-airbnb": "19.0.4", + "eslint-config-prettier": "8.6.0", + "eslint-config-wesbos": "3.2.3", + "eslint-plugin-import": "2.27.5", + "eslint-plugin-prettier": "4.2.1", + "mocha": "10.2.0", + "nodemon": "2.0.20", + "np": "7.6.3", "npm-run-all": "4.1.5", - "nyc": "14.1.1", - "parcel": "^2.3.2", - "parcel-plugin-shebang": "^1.2.8", - "prettier": "1.16.4", - "rimraf": "2.6.3", - "sinon": "7.3.1", - "sinon-chai": "3.3.0", - "ts-node": "^8.10.2", - "typescript": "^3.9.7" + "nyc": "15.1.0", + "parcel": "^2.8.3", + "parcel-plugin-shebang": "^1.4.1", + "prettier": "2.8.4", + "rimraf": "4.1.2", + "sinon": "15.0.1", + "sinon-chai": "3.7.0", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" }, "dependencies": { "globby": "^11.1.0", - "meow": "5.0.0", + "meow": "^9.0.0", "parse-dotenv": "2.1.0", "pkg-conf": "^3.1.0" }, diff --git a/test/lib.spec.ts b/test/lib.spec.ts index dadbe0d..65582dc 100644 --- a/test/lib.spec.ts +++ b/test/lib.spec.ts @@ -91,8 +91,8 @@ describe("sync-dotenv lib", () => { sandbox.stub(fs, "writeFileSync").callsArgWith(2, { message }); try { lib.writeToSampleEnv(SAMPLE_ENV_PATH, parseEnv(ENV_PATH)); - } catch (error) { - expect(error.message).contains(message); + } catch (error: unknown) { + expect((error as Error).message).contains(message); } }); }); diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index bb6081a..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ -test/**/*.spec.ts ---watch-extensions ts ---require ts-node/register ---exit