ci: fix lint job — add @typescript-eslint parser/plugin devDeps, files pattern, typed linting

eslint.config.mjs imported @typescript-eslint/parser and @typescript-eslint/eslint-plugin
directly but neither was a direct devDependency. pnpm strict hoisting made them unreachable
on CI. Fix: add both as explicit ^8 devDependencies, add files pattern for *.ts to all config
objects, and enable parserOptions.project for typed rules. Also run prettier to fix formatting.
This commit is contained in:
Aric Camarata 2026-05-31 08:48:31 -04:00
parent 7a57010e7c
commit f8ab0772b9
5 changed files with 47 additions and 35 deletions

View file

@ -5,10 +5,14 @@ import { typescript } from '@acamarata/eslint-config';
export default [ export default [
{ {
files: ['**/*.ts', '**/*.tsx'],
plugins: { '@typescript-eslint': tsPlugin }, plugins: { '@typescript-eslint': tsPlugin },
languageOptions: { parser: tsParser }, languageOptions: {
parser: tsParser,
parserOptions: { project: true, tsconfigRootDir: import.meta.dirname },
}, },
...typescript, },
...typescript.map((cfg) => ({ ...cfg, files: ['**/*.ts', '**/*.tsx'] })),
eslintConfigPrettier, eslintConfigPrettier,
{ {
ignores: ['dist/', 'node_modules/', 'test.mjs', 'test-cjs.cjs'], ignores: ['dist/', 'node_modules/', 'test.mjs', 'test-cjs.cjs'],

View file

@ -60,11 +60,13 @@
}, },
"devDependencies": { "devDependencies": {
"@acamarata/eslint-config": "^0.1.0", "@acamarata/eslint-config": "^0.1.0",
"c8": "^10.1.3",
"@acamarata/prettier-config": "^0.1.0", "@acamarata/prettier-config": "^0.1.0",
"@acamarata/tsconfig": "^0.1.0", "@acamarata/tsconfig": "^0.1.0",
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@types/node": "^25.3.5", "@types/node": "^25.3.5",
"@typescript-eslint/eslint-plugin": "^8.56.1",
"@typescript-eslint/parser": "^8.56.1",
"c8": "^10.1.3",
"dayjs": "^1.11.0", "dayjs": "^1.11.0",
"eslint": "^10.0.3", "eslint": "^10.0.3",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",

View file

@ -23,6 +23,12 @@ importers:
'@types/node': '@types/node':
specifier: ^25.3.5 specifier: ^25.3.5
version: 25.3.5 version: 25.3.5
'@typescript-eslint/eslint-plugin':
specifier: ^8.56.1
version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)
'@typescript-eslint/parser':
specifier: ^8.56.1
version: 8.56.1(eslint@10.0.3)(typescript@5.9.3)
c8: c8:
specifier: ^10.1.3 specifier: ^10.1.3
version: 10.1.3 version: 10.1.3

View file

@ -1,9 +1,9 @@
import type { PluginFunc } from 'dayjs'; import type { PluginFunc } from "dayjs";
import { toHijri, toGregorian, hmLong, hmMedium, hwLong, hwShort, hwNumeric } from 'hijri-core'; import { toHijri, toGregorian, hmLong, hmMedium, hwLong, hwShort, hwNumeric } from "hijri-core";
import type { ConversionOptions, HijriDate } from './types'; import type { ConversionOptions, HijriDate } from "./types";
// Augment Day.js to expose plugin methods on the instance type. // Augment Day.js to expose plugin methods on the instance type.
declare module 'dayjs' { declare module "dayjs" {
interface Dayjs { interface Dayjs {
/** /**
* Convert the Day.js date to a Hijri date. * Convert the Day.js date to a Hijri date.
@ -91,7 +91,7 @@ declare module 'dayjs' {
// Using the function declaration form (same pattern as dayjs timezone plugin) // Using the function declaration form (same pattern as dayjs timezone plugin)
// because dayjs does not export an IStatic interface for module augmentation. // because dayjs does not export an IStatic interface for module augmentation.
// import('dayjs').Dayjs is used explicitly to satisfy the tsup DTS emitter. // import('dayjs').Dayjs is used explicitly to satisfy the tsup DTS emitter.
declare module 'dayjs' { declare module "dayjs" {
/** /**
* Construct a Day.js instance from a Hijri date. * Construct a Day.js instance from a Hijri date.
* *
@ -117,7 +117,7 @@ declare module 'dayjs' {
hm: number, hm: number,
hd: number, hd: number,
opts?: ConversionOptions, opts?: ConversionOptions,
): import('dayjs').Dayjs; ): import("dayjs").Dayjs;
} }
// Hijri-specific format tokens, ordered longest-first to prevent partial matches. // Hijri-specific format tokens, ordered longest-first to prevent partial matches.
@ -138,7 +138,7 @@ const HIJRI_TOKEN_RE = /iYYYY|iYY|iMMMM|iMMM|iMM|iM|iDD|iD|iEEEE|iEEE|iE|ioooo|i
* @returns The bracket-escaped string. * @returns The bracket-escaped string.
*/ */
function lit(value: string): string { function lit(value: string): string {
return '[' + value.split(']').join(']][') + ']'; return "[" + value.split("]").join("]][") + "]";
} }
/** /**
@ -191,7 +191,7 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
opts?: ConversionOptions, opts?: ConversionOptions,
): string { ): string {
const hijri = this.toHijri(opts); const hijri = this.toHijri(opts);
if (!hijri) return ''; if (!hijri) return "";
// Day.js .day() returns 0 (Sunday) ... 6 (Saturday), matching the index // Day.js .day() returns 0 (Sunday) ... 6 (Saturday), matching the index
// layout of hwLong, hwShort, and hwNumeric from hijri-core. // layout of hwLong, hwShort, and hwNumeric from hijri-core.
@ -199,38 +199,38 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
const replaced = formatStr.replace(HIJRI_TOKEN_RE, (token) => { const replaced = formatStr.replace(HIJRI_TOKEN_RE, (token) => {
switch (token) { switch (token) {
case 'iYYYY': case "iYYYY":
return lit(String(hijri.hy).padStart(4, '0')); return lit(String(hijri.hy).padStart(4, "0"));
case 'iYY': case "iYY":
return lit(String(hijri.hy % 100).padStart(2, '0')); return lit(String(hijri.hy % 100).padStart(2, "0"));
case 'iMMMM': case "iMMMM":
// Non-null: hijri.hm is a valid Hijri month 1-12; hm-1 is always within hmLong bounds. // Non-null: hijri.hm is a valid Hijri month 1-12; hm-1 is always within hmLong bounds.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lit(hmLong[hijri.hm - 1]!); return lit(hmLong[hijri.hm - 1]!);
case 'iMMM': case "iMMM":
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lit(hmMedium[hijri.hm - 1]!); return lit(hmMedium[hijri.hm - 1]!);
case 'iMM': case "iMM":
return lit(String(hijri.hm).padStart(2, '0')); return lit(String(hijri.hm).padStart(2, "0"));
case 'iM': case "iM":
return lit(String(hijri.hm)); return lit(String(hijri.hm));
case 'iDD': case "iDD":
return lit(String(hijri.hd).padStart(2, '0')); return lit(String(hijri.hd).padStart(2, "0"));
case 'iD': case "iD":
return lit(String(hijri.hd)); return lit(String(hijri.hd));
case 'iEEEE': case "iEEEE":
// Non-null: dow is always 0-6 (day of week), within hwLong bounds. // Non-null: dow is always 0-6 (day of week), within hwLong bounds.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lit(hwLong[dow]!); return lit(hwLong[dow]!);
case 'iEEE': case "iEEE":
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lit(hwShort[dow]!); return lit(hwShort[dow]!);
case 'iE': case "iE":
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return lit(String(hwNumeric[dow]!)); return lit(String(hwNumeric[dow]!));
case 'ioooo': case "ioooo":
case 'iooo': case "iooo":
return lit('AH'); return lit("AH");
default: default:
return token; return token;
} }
@ -266,8 +266,8 @@ const plugin: PluginFunc = (_option, dayjsClass, dayjsFactory) => {
// dayjsFactory(Date) interprets the Date in local time; a UTC-midnight Date // dayjsFactory(Date) interprets the Date in local time; a UTC-midnight Date
// in western timezones would resolve to the previous local day. // in western timezones would resolve to the previous local day.
const y = greg.getUTCFullYear(); const y = greg.getUTCFullYear();
const mo = String(greg.getUTCMonth() + 1).padStart(2, '0'); const mo = String(greg.getUTCMonth() + 1).padStart(2, "0");
const dy = String(greg.getUTCDate()).padStart(2, '0'); const dy = String(greg.getUTCDate()).padStart(2, "0");
return dayjsFactory(`${y}-${mo}-${dy}`); return dayjsFactory(`${y}-${mo}-${dy}`);
}; };
}; };
@ -278,13 +278,13 @@ export default plugin;
* Re-exported from hijri-core for consumers who import from dayjs-hijri-plus. * Re-exported from hijri-core for consumers who import from dayjs-hijri-plus.
* Avoids requiring hijri-core as a direct dependency just to use these types. * Avoids requiring hijri-core as a direct dependency just to use these types.
*/ */
export type { HijriDate, ConversionOptions } from './types'; export type { HijriDate, ConversionOptions } from "./types";
/** /**
* Re-exported CalendarEngine interface from hijri-core. * Re-exported CalendarEngine interface from hijri-core.
* Use this type to implement custom calendar engines for `registerCalendar`. * Use this type to implement custom calendar engines for `registerCalendar`.
*/ */
export type { CalendarEngine } from 'hijri-core'; export type { CalendarEngine } from "hijri-core";
/** /**
* Re-exported registry API from hijri-core. * Re-exported registry API from hijri-core.
@ -296,4 +296,4 @@ export type { CalendarEngine } from 'hijri-core';
* registerCalendar('my-cal', myEngine); * registerCalendar('my-cal', myEngine);
* listCalendars(); // ['uaq', 'fcna', 'my-cal'] * listCalendars(); // ['uaq', 'fcna', 'my-cal']
*/ */
export { registerCalendar, getCalendar, listCalendars } from 'hijri-core'; export { registerCalendar, getCalendar, listCalendars } from "hijri-core";

View file

@ -1,2 +1,2 @@
import type { HijriDate, ConversionOptions } from 'hijri-core'; import type { HijriDate, ConversionOptions } from "hijri-core";
export type { HijriDate, ConversionOptions }; export type { HijriDate, ConversionOptions };