Skip to content

Commit a01827d

Browse files
authored
style: enforce @vitest/eslint-plugin (#38)
* docs: use consistent variable names * style: remove unneeded template literal string * test: prefer toEqual for strings over toBe * test: enforce @vitest/eslint-plugin
1 parent 170f556 commit a01827d

14 files changed

+70
-36
lines changed

boundaries.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const ELEMENTS = [
1515
mode: "full",
1616
},
1717
{
18-
type: `lib:scope`,
18+
type: "lib:scope",
1919
pattern: [`src/*/*/${libDir}/*.*`, `src/*/*/${libDir}/*/**/*`],
2020
capture: ["scope", "elementName", "lib"],
2121
mode: "full",

eslint.config.js

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import eslintPluginJsdoc from "eslint-plugin-jsdoc";
1010
import eslintPluginTsdoc from "eslint-plugin-tsdoc";
1111
import { ELEMENTS, ELEMENT_TYPE_RULES, EXTERNAL_RULES } from "./boundaries.config.js";
1212
import eslintJs from "@eslint/js";
13+
import vitestEslintPlugin from "@vitest/eslint-plugin";
1314

1415
/** @type { import("eslint").Linter.Config[] } */
1516
export default [
@@ -75,6 +76,14 @@ export default [
7576
},
7677
},
7778

79+
{
80+
files: ["src/**/*.test.{ts,tsx}"],
81+
...vitestEslintPlugin.configs.recommended,
82+
rules: {
83+
"vitest/expect-expect": ["off", { assertFunctionNames: ["expect", "expectTypeOf"] }],
84+
},
85+
},
86+
7887
// Turns off all rules that are unnecessary or might conflict with Prettier.
7988
eslintConfigPrettier,
8089

package-lock.json

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@typescript-eslint/parser": "^8.26.0",
5050
"@typhonjs-typedoc/typedoc-theme-dmt": "^0.3.1",
5151
"@vitest/coverage-v8": "^3.0.7",
52+
"@vitest/eslint-plugin": "^1.1.36",
5253
"eslint": "^9.21.0",
5354
"eslint-config-preact": "github:brianrodri/eslint-config-preact#eslint-v9",
5455
"eslint-config-prettier": "^10.0.2",

src/model/collection/__tests__/periodic-notes.ts src/model/collection/__tests__/periodic-notes.test.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
33

44
import { PeriodicNotes } from "../periodic-notes";
55

6-
describe(PeriodicNotes.name, () => {
6+
describe(`${PeriodicNotes.name}`, () => {
77
describe("pre-conditions", () => {
88
it("should throw when folder is empty", () => {
99
expect(() => new PeriodicNotes("", "yyyy-MM-dd", { days: 1 })).toThrow();
@@ -34,6 +34,12 @@ describe(PeriodicNotes.name, () => {
3434
});
3535
});
3636

37+
describe("post-conditions", () => {
38+
it("should strip trailing slashes from the folder", () => {
39+
expect(new PeriodicNotes("/vault/", "yyyy-MM-dd", { days: 1 }).folder).toEqual("/vault");
40+
});
41+
});
42+
3743
describe('given daily log in folder: "/vault"', () => {
3844
const log = new PeriodicNotes("/vault", "yyyy-MM-dd", { days: 1 });
3945

src/model/collection/__tests__/schema.ts src/model/collection/__tests__/schema.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from "vitest";
33

44
import { DateBasedCollection } from "../schema";
55

6-
describe(DateBasedCollection.name, () => {
6+
describe(`${DateBasedCollection.name}`, () => {
77
const getIntervalOf = vi.fn();
88
class TestCollection extends DateBasedCollection {
99
public override getIntervalOf = getIntervalOf;

src/model/collection/periodic-notes.ts

+22-25
Original file line numberDiff line numberDiff line change
@@ -17,51 +17,48 @@ export class PeriodicNotes extends DateBasedCollection {
1717
/** The folder containing all of the notes. */
1818
public readonly folder: string;
1919

20-
/**
21-
* Luxon format used to parse dates from the file's name.
22-
* @see {@link https://moment.github.io/luxon/#/parsing?id=table-of-tokens}
23-
*/
20+
/** @see {@link https://moment.github.io/luxon/#/parsing?id=table-of-tokens} */
2421
public readonly dateFormat: string;
2522

26-
/**
27-
* Offset between the file's _parsed_ date and the corresponding {@link Interval}'s _start_ date. May be negative.
28-
* @example a periodic sprint log using ISO weeks, which start on Monday, as its {@link dateFormat} when sprints
29-
* _actually_ begin on Thursdays.
30-
*/
31-
public readonly dateOffset: Duration<true>;
23+
/** Luxon options used when parsing {@link DateTime}s from file names. */
24+
public readonly dateOptions: DateTimeOptions;
3225

3326
/**
3427
* The {@link Duration} of each file's corresponding {@link Interval}.
3528
* @example a daily log's duration would be `{ days: 1 }`.
3629
*/
3730
public readonly intervalDuration: Duration<true>;
3831

39-
/** Luxon options used when parsing {@link DateTime}s from file names. */
40-
public readonly dateOptions: DateTimeOptions;
32+
/**
33+
* Offset between the file's _parsed_ date and the corresponding {@link Interval}'s _start_ date. May be negative.
34+
* @example a periodic sprint log using ISO weeks, which start on Monday, as its {@link dateFormat} when sprints
35+
* _actually_ begin on Thursdays.
36+
*/
37+
public readonly intervalOffset: Duration<true>;
4138

4239
public constructor(
4340
folder: string,
4441
dateFormat: string,
4542
intervalDurationLike: DurationLike,
46-
dateOffsetLike: DurationLike = 0,
43+
intervalOffsetLike: DurationLike = 0,
4744
dateOptions: DateTimeOptions = {},
4845
) {
4946
super();
5047

51-
folder = folder.trim();
52-
const dateOffset = Duration.fromDurationLike(dateOffsetLike);
48+
folder = folder.trim().replace(/\/$/, ""); // Ensure trailing slashes are removed.
49+
const intervalOffset = Duration.fromDurationLike(intervalOffsetLike);
5350
const intervalDuration = Duration.fromDurationLike(intervalDurationLike);
5451

5552
assert(folder.length > 0, "folder must be non-empty");
5653
assert(dateFormat.length > 0, "dateFormat must be non-empty");
57-
assert(dateOffset.isValid, "dateOffset must be valid");
54+
assert(intervalOffset.isValid, "dateOffset must be valid");
5855
assert(intervalDuration.isValid && intervalDuration.valueOf() !== 0, "intervalDuration must be non-zero");
5956

6057
this.folder = folder;
6158
this.dateFormat = dateFormat;
62-
this.dateOffset = dateOffset;
63-
this.intervalDuration = intervalDuration;
6459
this.dateOptions = dateOptions;
60+
this.intervalDuration = intervalDuration;
61+
this.intervalOffset = intervalOffset;
6562
}
6663

6764
/**
@@ -70,14 +67,14 @@ export class PeriodicNotes extends DateBasedCollection {
7067
* @returns the {@link Interval} corresponding to the file, otherwise an invalid interval.
7168
*/
7269
public override getIntervalOf(filePath: string): IntervalMaybeValid {
73-
const path = parse(filePath);
74-
if (path.dir !== this.folder) {
75-
return Interval.invalid(`invalid interval folder`, `"${filePath}" is not in "${this.folder}"`);
70+
const parsedPath = parse(filePath);
71+
if (parsedPath.dir !== this.folder) {
72+
return Interval.invalid("invalid folder", `"${filePath}" is not in "${this.folder}"`);
7673
}
77-
const date = DateTime.fromFormat(path.name, this.dateFormat, this.dateOptions);
78-
if (!date.isValid) {
79-
return Interval.invalid(`invalid interval filename`, `${date.invalidReason} ${date.invalidExplanation}`);
74+
const parsedDate = DateTime.fromFormat(parsedPath.name, this.dateFormat, this.dateOptions);
75+
if (!parsedDate.isValid) {
76+
return Interval.invalid("invalid filename", `${parsedDate.invalidReason} ${parsedDate.invalidExplanation}`);
8077
}
81-
return Interval.after(date.plus(this.dateOffset), this.intervalDuration);
78+
return Interval.after(parsedDate.plus(this.intervalOffset), this.intervalDuration);
8279
}
8380
}

src/model/task/lib/__tests__/obsidian-dataview.ts src/model/task/lib/__tests__/obsidian-dataview.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
44
import { adaptDataviewMarkdownTask } from "../obsidian-dataview";
55
import { NULL_DATAVIEW_TASK } from "./obsidian-dataview.const";
66

7-
describe(adaptDataviewMarkdownTask.name, () => {
7+
describe(`${adaptDataviewMarkdownTask.name}`, () => {
88
afterEach(() => vi.resetAllMocks());
99

1010
it.each([

src/model/task/lib/__tests__/obsidian-tasks.ts src/model/task/lib/__tests__/obsidian-tasks.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
33

44
import { parseTaskEmojiFormat } from "../obsidian-tasks";
55

6-
describe(parseTaskEmojiFormat.name, () => {
6+
describe(`${parseTaskEmojiFormat.name}`, () => {
77
it.each([
88
[{ description: "task text" }, " \t task text \t "],
99
[{ priority: 0 }, "🔺"],

src/model/task/util/__tests__/merge.ts src/model/task/util/__tests__/merge.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
33

44
import { mergeTaskParts } from "../merge";
55

6-
describe(mergeTaskParts.name, () => {
6+
describe(`${mergeTaskParts.name}`, () => {
77
it("gives default values when called with nothing", () => {
88
const task = mergeTaskParts();
99

src/util/__tests__/luxon-utils.ts src/util/__tests__/luxon-utils.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest";
55
import { assertIntervalsDoNotIntersect, assertLuxonValidity } from "../luxon-utils";
66
import { WITH_OVERLAPPING_INTERVALS, WITHOUT_OVERLAPPING_INTERVALS } from "./luxon-utils.const";
77

8-
describe(assertLuxonValidity.name, () => {
8+
describe(`${assertLuxonValidity.name}`, () => {
99
const reason = "user-provided reason";
1010
const explanation = "user-provided explanation";
1111

@@ -32,7 +32,7 @@ describe(assertLuxonValidity.name, () => {
3232
});
3333
});
3434

35-
describe(assertIntervalsDoNotIntersect.name, () => {
35+
describe(`${assertIntervalsDoNotIntersect.name}`, () => {
3636
it.each(entriesIn(WITHOUT_OVERLAPPING_INTERVALS))("should accept %j", (_, intervals) => {
3737
expect(() => assertIntervalsDoNotIntersect(intervals)).not.toThrow();
3838
});
File renamed without changes.

vite.config.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ export default defineConfig(({ mode }) => ({
3535
},
3636
test: {
3737
environment: "jsdom",
38-
include: ["src/**/__tests__/*"],
39-
exclude: ["**/*.const.{ts,tsx}"],
38+
include: ["src/**/__tests__/**/*.test.{ts,tsx}"],
4039
coverage: {
4140
all: true,
4241
include: ["src/"],
43-
exclude: ["src/main.tsx", "src/lib/"],
42+
exclude: ["src/main.tsx", "src/lib"],
4443
thresholds: { 100: true },
4544
reporter: ["text", "html", "clover", "json", "lcov"],
4645
},

0 commit comments

Comments
 (0)