diff --git a/.eslintrc.js b/.eslintrc.js index 131c0da..096318d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,9 @@ /** @type{import("eslint").Linter.Config} */ module.exports = { - extends: ["@kachkaev/eslint-config-base"], + extends: [ + "@kachkaev/eslint-config-base", + "@kachkaev/eslint-config-base/extra-type-checking", + ], reportUnusedDisableDirectives: true, rules: { /* eslint-disable @typescript-eslint/naming-convention */ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ccc7bf..23abefc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Run build run: yarn build - lint: + linting: name: Linting runs-on: ubuntu-latest @@ -66,23 +66,22 @@ jobs: if: ${{ success() || failure() }} run: yarn lint:yarn-dedupe - unit-tests: - name: Unit tests + tests: + name: Tests runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [macos-12, ubuntu-22.04, windows-2022] + os: [macos-12, windows-2022, ubuntu-22.04] node: [14, 16, 18, 19] exclude: - - os: macos-12 - node: 14 - - os: macos-12 - node: 19 - - os: windows-2022 - node: 14 - - os: windows-2022 - node: 19 + - os: ubuntu-22.04 + node: 18 + include: + - os: ubuntu-22.04 + node: 18 + extra: coverage + - os: ubuntu-22.04 steps: - name: Check out repository @@ -100,10 +99,10 @@ jobs: - name: Run unit tests run: yarn test env: - TEST_COVERAGE: ${{ matrix.os == 'ubuntu-22.04' && matrix.node == 18 }} + COVERAGE: ${{ matrix.extra == 'coverage' }} - name: Report code coverage to codecov.io uses: codecov/codecov-action@v3 - if: matrix.os == 'ubuntu-22.04' && matrix.node == 18 + if: matrix.extra == 'coverage' with: files: coverage/lcov.info diff --git a/.npmignore b/.npmignore index 6e4ca70..d84a018 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,5 @@ * -!dist/**/* +!dist/** dist/**/*.test.* !package.json !README.md diff --git a/jest.config.mjs b/jest.config.mjs index bc6d7e8..b036ba7 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -1,7 +1,7 @@ /* eslint-disable import/no-anonymous-default-export */ /** @type {import("jest").Config} */ export default { - collectCoverage: !!process.env.TEST_COVERAGE, + collectCoverage: process.env.COVERAGE === "true", collectCoverageFrom: ["dist/**/*.js", "!dist/**/*.test.js"], testRegex: ".test.js$", }; diff --git a/package.json b/package.json index 504e529..0c67984 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "scripts": { "build": "tsc", "clean": "rimraf cache coverage dist", - "fix": "npm-run-all --continue-on-error fix:*", + "fix": "npm-run-all --continue-on-error \"fix:*\"", "fix:eslint": "eslint --fix .", "fix:markdownlint": "markdownlint --fix .", "fix:prettier": "prettier --write .", "fix:yarn-dedupe": "yarn dedupe", - "lint": "npm-run-all --continue-on-error lint:*", + "lint": "npm-run-all --continue-on-error \"lint:*\"", "lint:markdownlint": "markdownlint .", "lint:prettier": "prettier --check .", "lint:tsc": "tsc --noEmit", diff --git a/src/cache.test.ts b/src/cache.test.ts index c6230c7..46c33e4 100644 --- a/src/cache.test.ts +++ b/src/cache.test.ts @@ -4,7 +4,7 @@ import prettier from "prettier"; import rimraf from "rimraf"; import sleep from "sleep-promise"; -import * as util from "./util"; +import * as helpers from "./helpers"; const fixturesDir = path.resolve(__dirname, "../fixtures"); const cacheDir = path.resolve(__dirname, "../cache"); @@ -18,7 +18,7 @@ test(`correctly deals with cache`, async () => { process.env.PRETTIER_PLUGIN_ELM_CACHE_GC_INTERVAL = `${cacheGcInterval}`; const spyForFormatTextWithElmFormat = jest.spyOn( - util, + helpers, "formatTextWithElmFormat", ); diff --git a/src/cache.ts b/src/cache.ts index 09309cd..8e0fbdf 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -86,7 +86,10 @@ export const getCachedValue = ( // load value or error from cache try { - record = JSON.parse(fs.readFileSync(recordFilePath, "utf8")); + record = JSON.parse(fs.readFileSync(recordFilePath, "utf8")) as { + value: Result; + error?: undefined; + }; recordIsFromCache = true; } catch { // a failure to load from cache implies calling fn @@ -122,11 +125,11 @@ export const getCachedValue = ( if ("error" in record) { // eslint-disable-next-line unicorn/error-message - const errorToThrow = new Error(); + const errorToThrow = new Error() as Error & Record; for (const errorProperty in record.error) { /* istanbul ignore else */ if (Object.prototype.hasOwnProperty.call(record.error, errorProperty)) { - (errorToThrow as any)[errorProperty] = record.error.property; + errorToThrow[errorProperty] = record.error.property; } } throw errorToThrow; diff --git a/src/util.ts b/src/helpers.ts similarity index 99% rename from src/util.ts rename to src/helpers.ts index 31cbb30..6b534e4 100644 --- a/src/util.ts +++ b/src/helpers.ts @@ -1,6 +1,7 @@ import execa from "execa"; let cachedElmFormatVersion: string; + export const getElmFormatVersion = () => { if (!cachedElmFormatVersion) { // a cleaner way of getting elm-format version diff --git a/src/index.ts b/src/index.ts index f12bf43..27ab101 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,8 @@ +import type { Parser, Printer } from "prettier"; + import { parse } from "./parser"; import { print } from "./printer"; +import type { ElmNode } from "./types"; export const defaultOptions = {}; @@ -16,21 +19,21 @@ export const languages = [ }, ]; -export const parsers = { +export const parsers: Record> = { elm: { parse, astFormat: "elm-format", // there's only a single node - locStart(node: any) { + locStart(node) { return node.start; }, - locEnd(node: any) { + locEnd(node) { return node.end; }, }, }; -export const printers = { +export const printers: Record> = { // eslint-disable-next-line @typescript-eslint/naming-convention "elm-format": { print, diff --git a/src/parser.ts b/src/parser.ts index a0b09dc..02167dc 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,10 +1,11 @@ -import { Parser, ParserOptions } from "prettier"; +import type { Parser, ParserOptions } from "prettier"; import { getCachedValue } from "./cache"; -import { formatTextWithElmFormat, getElmFormatVersion } from "./util"; +import { formatTextWithElmFormat, getElmFormatVersion } from "./helpers"; +import type { ElmNode } from "./types"; // eslint-disable-next-line @typescript-eslint/no-var-requires -const pkg = require("../package.json"); +const pkg = require("../package.json") as { version: string }; /* * Simply passing text to elm-format is not enough because of two problems: @@ -34,8 +35,8 @@ const autogeneratedModuleDefinitionRegExp = export const parse = ( text: string, parsers: { [parserName: string]: Parser }, - opts: ParserOptions & { parentParser?: string }, -) => { + options: ParserOptions, +): ElmNode => { // patch 1 step 1 const textToSend = `${text}${dummyComment}`; @@ -54,7 +55,7 @@ export const parse = ( // patch 2 if ( - opts.parentParser === "markdown" && + options.parentParser === "markdown" && autogeneratedModuleDefinitionRegExp.test(formattedText) && !autogeneratedModuleDefinitionRegExp.test(text) ) { diff --git a/src/printer.ts b/src/printer.ts index 54a1f12..1374cab 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -1,6 +1,8 @@ -import { AstPath } from "prettier"; +import type { AstPath, Doc } from "prettier"; -export const print = (path: AstPath) => { +import type { ElmNode } from "./types"; + +export const print = (path: AstPath): Doc => { const node = path.getValue(); switch (node.type) { diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..4a95efe --- /dev/null +++ b/src/types.ts @@ -0,0 +1,7 @@ +export interface ElmNode { + type: "elm-format"; + body: string; + source: string; + start: number; + end: number; +} diff --git a/tsconfig.json b/tsconfig.json index 0e6db69..be820fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "esModuleInterop": true, "inlineSourceMap": true, "lib": ["ES2019"], + "isolatedModules": true, "module": "commonjs", "checkJs": true, "outDir": "dist",