Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update devDependencies and fix newly reported linting errors #31

Merged
merged 2 commits into from
Nov 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
module.exports = {
extends: ["@kachkaev/eslint-config-base"],
rules: {
/* eslint-disable @typescript-eslint/naming-convention */
"unicorn/prefer-json-parse-buffer": "off",
"unicorn/prefer-module": "off",
"unicorn/prefer-node-protocol": "off",
/* eslint-enable @typescript-eslint/naming-convention */
},
};
2 changes: 0 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use strict";

const testResultsAndCoverage = !!process.env.REPORT_TEST_RESULTS_AND_COVERAGE;

module.exports = {
Expand Down
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,25 @@
"temp-dir": "^2.0.0"
},
"devDependencies": {
"@kachkaev/eslint-config-base": "^0.2.3",
"@kachkaev/markdownlint-config": "^0.2.0",
"@types/jest": "^27.0.1",
"@types/object-hash": "^2.1.1",
"@types/prettier": "^2.3.2",
"@kachkaev/eslint-config-base": "^0.4.3",
"@kachkaev/markdownlint-config": "^0.3.0",
"@types/jest": "^29.2.2",
"@types/object-hash": "^2.2.1",
"@types/prettier": "^2.7.1",
"@types/rimraf": "^3.0.2",
"eslint": "^7.32.0",
"husky": "^7.0.1",
"jest": "^27.0.6",
"jest-junit": "^13.0.0",
"lint-staged": "^11.1.2",
"markdownlint-cli": "^0.28.1",
"eslint": "^8.26.0",
"husky": "^8.0.1",
"jest": "^29.2.2",
"jest-junit": "^14.0.1",
"lint-staged": "^13.0.3",
"markdownlint-cli": "^0.32.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.3.2",
"prettier-plugin-packagejson": "^2.2.11",
"prettier": "^2.7.1",
"prettier-plugin-packagejson": "^2.3.0",
"rimraf": "^3.0.2",
"sleep-promise": "^9.1.0",
"typescript": "^4.3.5",
"yarn-deduplicate": "^3.1.0"
"typescript": "^4.8.4",
"yarn-deduplicate": "^6.0.0"
},
"engines": {
"node": ">=12.13.0"
Expand Down
20 changes: 10 additions & 10 deletions src/cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import fs from "fs";
import { resolve } from "path";
import path from "path";
import prettier from "prettier";
import rimraf from "rimraf";
import sleep from "sleep-promise";

import * as util from "./util";

const fixturesDir = resolve(__dirname, "../fixtures");
const cacheDir = resolve(__dirname, "../cache");
const fixturesDir = path.resolve(__dirname, "../fixtures");
const cacheDir = path.resolve(__dirname, "../cache");
const cacheMax = 21; // number of blocks in multiple-blocks.md fixture
const cacheGcInterval = 1000;

Expand All @@ -23,19 +23,19 @@ test(`correctly deals with cache`, async () => {
);

const sourceText = fs.readFileSync(
resolve(fixturesDir, "multiple-blocks.md"),
path.resolve(fixturesDir, "multiple-blocks.md"),
"utf8",
);
const expectedFormattedText = fs.readFileSync(
resolve(fixturesDir, "multiple-blocks.prettified.md"),
path.resolve(fixturesDir, "multiple-blocks.prettified.md"),
"utf8",
);

// multiple-blocks.md, first run – no cache
expect(
prettier.format(sourceText, {
parser: "markdown",
plugins: [resolve(__dirname, "..")],
plugins: [path.resolve(__dirname, "..")],
}),
).toEqual(expectedFormattedText);
const numberOfFormatCallsInFirstRun =
Expand All @@ -46,7 +46,7 @@ test(`correctly deals with cache`, async () => {
expect(
prettier.format(sourceText, {
parser: "markdown",
plugins: [resolve(__dirname, "..")],
plugins: [path.resolve(__dirname, "..")],
}),
).toEqual(expectedFormattedText);
expect(spyForFormatTextWithElmFormat.mock.calls.length).toBe(
Expand All @@ -58,14 +58,14 @@ test(`correctly deals with cache`, async () => {
// a call to formatTextWithElmFormat() that triggers garbage collection
prettier.format("{- -}", {
parser: "elm",
plugins: [resolve(__dirname, "..")],
plugins: [path.resolve(__dirname, "..")],
});

// multiple-blocks.md, third run – with cache except for one block that was previously garbage collected
expect(
prettier.format(sourceText, {
parser: "markdown",
plugins: [resolve(__dirname, "..")],
plugins: [path.resolve(__dirname, "..")],
}),
).toEqual(expectedFormattedText);

Expand All @@ -74,4 +74,4 @@ test(`correctly deals with cache`, async () => {
).toBeGreaterThanOrEqual(
numberOfFormatCallsInFirstRun + 1 /* for "" */ + 1 /* for GC-d block */,
);
}, 10000);
}, 10_000);
119 changes: 60 additions & 59 deletions src/cache.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,84 @@
import fs from "fs";
import makeDir from "make-dir";
import objectHash from "object-hash";
import { resolve } from "path";
import path from "path";
import { ErrorObject, serializeError } from "serialize-error";
import tempDir from "temp-dir";

const cacheDir = process.env.PRETTIER_PLUGIN_ELM_CACHE_DIR
? resolve(process.env.PRETTIER_PLUGIN_ELM_CACHE_DIR)
: resolve(tempDir, "prettier-plugin-elm");
? path.resolve(process.env.PRETTIER_PLUGIN_ELM_CACHE_DIR)
: path.resolve(tempDir, "prettier-plugin-elm");

const cacheMax = process.env.PRETTIER_PLUGIN_ELM_CACHE_MAX
? parseInt(process.env.PRETTIER_PLUGIN_ELM_CACHE_MAX, 10)
? Number.parseInt(process.env.PRETTIER_PLUGIN_ELM_CACHE_MAX, 10)
: 1000;

const cacheGcInterval = process.env.PRETTIER_PLUGIN_ELM_CACHE_GC_INTERVAL
? parseInt(process.env.PRETTIER_PLUGIN_ELM_CACHE_GC_INTERVAL, 10)
? Number.parseInt(process.env.PRETTIER_PLUGIN_ELM_CACHE_GC_INTERVAL, 10)
: 1000 * 60;

/* istanbul ignore next */
const noop = () => {
//
};

const collectGarbageIfNeeded = () => {
const pathToGcTouchfile = path.resolve(cacheDir, `gc.touchfile`);
try {
const lastGcTime = fs.statSync(pathToGcTouchfile).mtimeMs;
if (lastGcTime + cacheGcInterval > Date.now()) {
// no need to collect garbage
return;
}
} catch {
// a failure to read modification time for the GC touchfile
// means that GC needs to be done for the first time
}

fs.writeFileSync(pathToGcTouchfile, "");
const recordInfos: RecordInfo[] = [];
fs.readdirSync(cacheDir).map((recordFileName) => {
if (!recordFileName.endsWith(".json")) {
return;
}
const recordFilePath = path.resolve(cacheDir, recordFileName);
const recordInfo = {
path: recordFilePath,
touchedAt: 0,
};
try {
recordInfo.touchedAt = fs.statSync(`${recordFilePath}.touchfile`).mtimeMs;
} catch (error) {
// fs.statSync may fail if another GC process has just deleted it;
// this is not critical

/* istanbul ignore next */
if (process.env.NODE_ENV === "test") {
throw error;
}
}
recordInfos.push(recordInfo);
});

recordInfos.sort((a, b) => {
return b.touchedAt - a.touchedAt;
});
const recordInfosToDelete = recordInfos.slice(cacheMax);

for (const recordInfo of recordInfosToDelete) {
// files are deleted asynchronously and possible errors are ignored
fs.unlink(recordInfo.path, noop);
fs.unlink(`${recordInfo.path}.touchfile`, noop);
}
};

export const getCachedValue = <Args extends any[], Result>(
fn: (...args: Args) => Result,
args: Args,
extraCacheKeyFactors?: any[],
): Result => {
const cacheKey = objectHash({ args, extraCacheKeyFactors });
const recordFilePath = resolve(cacheDir, `${cacheKey}.json`);
const recordFilePath = path.resolve(cacheDir, `${cacheKey}.json`);
let record:
| { value: Result; error?: undefined }
| { error: ErrorObject; value?: undefined };
Expand All @@ -38,7 +88,7 @@ export const getCachedValue = <Args extends any[], Result>(
try {
record = JSON.parse(fs.readFileSync(recordFilePath, "utf8"));
recordIsFromCache = true;
} catch (e) {
} catch {
// a failure to load from cache implies calling fn
try {
record = {
Expand All @@ -60,17 +110,18 @@ export const getCachedValue = <Args extends any[], Result>(
fs.writeFileSync(recordFilePath, JSON.stringify(record), "utf8");
}
collectGarbageIfNeeded();
} catch (e) {
} catch (error) {
// a failure to save record into cache or clean garbage
// should not affect the result of the function

/* istanbul ignore next */
if (process.env.NODE_ENV === "test") {
throw e;
throw error;
}
}

if ("error" in record) {
// eslint-disable-next-line unicorn/error-message
const errorToThrow = new Error();
for (const errorProperty in record.error) {
/* istanbul ignore else */
Expand All @@ -88,53 +139,3 @@ interface RecordInfo {
path: string;
touchedAt: number;
}

const collectGarbageIfNeeded = () => {
const pathToGcTouchfile = resolve(cacheDir, `gc.touchfile`);
try {
const lastGcTime = fs.statSync(pathToGcTouchfile).mtimeMs;
if (lastGcTime + cacheGcInterval > +new Date()) {
// no need to collect garbage
return;
}
} catch (e) {
// a failure to read modification time for the GC touchfile
// means that GC needs to be done for the first time
}

fs.writeFileSync(pathToGcTouchfile, "");
const recordInfos: RecordInfo[] = [];
fs.readdirSync(cacheDir).map((recordFileName) => {
if (!recordFileName.endsWith(".json")) {
return;
}
const recordFilePath = resolve(cacheDir, recordFileName);
const recordInfo = {
path: recordFilePath,
touchedAt: 0,
};
try {
recordInfo.touchedAt = fs.statSync(`${recordFilePath}.touchfile`).mtimeMs;
} catch (e) {
// fs.statSync may fail if another GC process has just deleted it;
// this is not critical

/* istanbul ignore next */
if (process.env.NODE_ENV === "test") {
throw e;
}
}
recordInfos.push(recordInfo);
});

recordInfos.sort((a, b) => {
return b.touchedAt - a.touchedAt;
});
const recordInfosToDelete = recordInfos.slice(cacheMax);

recordInfosToDelete.forEach((recordInfo) => {
// files are deleted asynchronously and possible errors are ignored
fs.unlink(recordInfo.path, noop);
fs.unlink(`${recordInfo.path}.touchfile`, noop);
});
};
12 changes: 6 additions & 6 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ beforeAll(() => {
rimraf.sync(path.resolve(tempDir, "prettier-plugin-elm"));
});

files.forEach((sourceFileName) => {
for (const sourceFileName of files) {
if (
!sourceFileName.match(/\.(md|elm)$/) ||
sourceFileName.match(/\.prettified\./)
!/\.(md|elm)$/.test(sourceFileName) ||
/\.prettified\./.test(sourceFileName)
) {
return;
continue;
}

test(`formats fixture ${sourceFileName}`, () => {
Expand All @@ -39,10 +39,10 @@ files.forEach((sourceFileName) => {
filepath: sourceFilePath,
plugins: [path.resolve(__dirname, "..")],
});
} catch (e) {
} catch {
actualResult = sourceText;
}

expect(actualResult).toBe(expectedFormattedText);
});
});
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const parsers = {
};

export const printers = {
// eslint-disable-next-line @typescript-eslint/naming-convention
"elm-format": {
print,
},
Expand Down
4 changes: 2 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ const pkg = require("../package.json");

const dummyComment = "\n{- DUMMY COMMENT BY PRETTIER-PLUGIN-ELM -}";
const dummyCommentRemovalRegExp =
/\n*\{- DUMMY COMMENT BY PRETTIER-PLUGIN-ELM -\}/;
/\n*{- DUMMY COMMENT BY PRETTIER-PLUGIN-ELM -}/;
const autogeneratedModuleDefinitionRegExp =
/[ \t]*module\s+Main\s+exposing\s+\([^\n]+\)\n*/;
/[\t ]*module\s+Main\s+exposing\s+\([^\n]+\)\n*/;

export const parse = (
text: string,
Expand Down
2 changes: 1 addition & 1 deletion src/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const print = (path: AstPath) => {
throw new Error(
`Unknown Elm node: ${JSON.stringify(
node,
null /* replacer */,
undefined /* replacer */,
4 /* space */,
)}`,
);
Expand Down
Loading