diff --git a/.changeset/healthy-snails-heal.md b/.changeset/healthy-snails-heal.md new file mode 100644 index 000000000000..d48fc69e378a --- /dev/null +++ b/.changeset/healthy-snails-heal.md @@ -0,0 +1,7 @@ +--- +"@cloudflare/kv-asset-handler": patch +--- + +chore: pass lint/typechecks for kv-asset-handler + +Followup from https://github.com/cloudflare/workers-sdk/pull/6090, this enables typechecking and linting in kv-asset-handler, and fixes any failures. diff --git a/packages/kv-asset-handler/package.json b/packages/kv-asset-handler/package.json index 46cb9dc42027..cf0fbfac6843 100644 --- a/packages/kv-asset-handler/package.json +++ b/packages/kv-asset-handler/package.json @@ -9,7 +9,9 @@ "build": "tsc -d", "pretest": "npm run build", "test": "ava dist/test/*.js --verbose", - "test:ci": "npm run build && ava dist/test/*.js --verbose" + "test:ci": "npm run build && ava dist/test/*.js --verbose", + "check:lint": "eslint .", + "check:type": "tsc" }, "repository": { "type": "git", @@ -43,6 +45,7 @@ "@cloudflare/workers-types": "^4.20240605.0", "@types/mime": "^3.0.4", "@types/node": "20.8.3", + "@types/service-worker-mock": "^2.0.1", "ava": "^6.0.1", "service-worker-mock": "^2.0.5" }, diff --git a/packages/kv-asset-handler/src/index.ts b/packages/kv-asset-handler/src/index.ts index 1f46c5f7743d..6ad915634e75 100644 --- a/packages/kv-asset-handler/src/index.ts +++ b/packages/kv-asset-handler/src/index.ts @@ -9,7 +9,8 @@ import { import type { AssetManifestType } from "./types"; declare global { - const __STATIC_CONTENT: unknown, __STATIC_CONTENT_MANIFEST: string; + const __STATIC_CONTENT: KVNamespace | undefined, + __STATIC_CONTENT_MANIFEST: string; } const defaultCacheControl: CacheControl = { diff --git a/packages/kv-asset-handler/src/mocks.ts b/packages/kv-asset-handler/src/mocks.ts index f3943a90b056..fb8c0fa365f0 100644 --- a/packages/kv-asset-handler/src/mocks.ts +++ b/packages/kv-asset-handler/src/mocks.ts @@ -1,17 +1,19 @@ -const makeServiceWorkerEnv = require("service-worker-mock"); +import makeServiceWorkerEnv from "service-worker-mock"; const HASH = "123HASHBROWN"; -export const getEvent = (request: Request): any => { - const waitUntil = async (callback: any) => { - await callback; +export const getEvent = ( + request: Request +): Pick => { + const waitUntil = async (maybePromise: unknown) => { + await maybePromise; }; return { request, waitUntil, }; }; -const store: any = { +const store = { "key1.123HASHBROWN.txt": "val1", "key1.123HASHBROWN.png": "val1", "index.123HASHBROWN.html": "index.html", @@ -30,9 +32,9 @@ const store: any = { "image.123HASHBROWN.webp": "imagewebp", "你好/index.123HASHBROWN.html": "My path is non-ascii", }; -export const mockKV = (store: any) => { +export const mockKV = (kvStore: Record) => { return { - get: (path: string) => store[path] || null, + get: (path: string) => kvStore[path] || null, }; }; @@ -57,22 +59,22 @@ export const mockManifest = () => { }); }; -let cacheStore: any = new Map(); +const cacheStore = new Map(); interface CacheKey { - url: object; - headers: object; + url: string; + headers: HeadersInit; } export const mockCaches = () => { return { default: { - async match(key: any) { - let cacheKey: CacheKey = { + async match(key: Request) { + const cacheKey: CacheKey = { url: key.url, headers: {}, }; let response; if (key.headers.has("if-none-match")) { - let makeStrongEtag = key.headers + const makeStrongEtag = key.headers .get("if-none-match") .replace("W/", ""); Reflect.set(cacheKey.headers, "etag", makeStrongEtag); @@ -102,23 +104,25 @@ export const mockCaches = () => { } // ... which we are using in this repository to set status 206 if (response.headers.has("content-range")) { + // @ts-expect-error overridding status in this mock response.status = 206; } else { + // @ts-expect-error overridding status in this mock response.status = 200; } - let etag = response.headers.get("etag"); + const etag = response.headers.get("etag"); if (etag && !etag.includes("W/")) { response.headers.set("etag", `W/${etag}`); } } return response; }, - async put(key: any, val: Response) { - let headers = new Headers(val.headers); - let url = new URL(key.url); - let resWithBody = new Response(val.body, { headers, status: 200 }); - let resNoBody = new Response(null, { headers, status: 304 }); - let cacheKey: CacheKey = { + async put(key: Request, val: Response) { + const headers = new Headers(val.headers); + const url = new URL(key.url); + const resWithBody = new Response(val.body, { headers, status: 200 }); + const resNoBody = new Response(null, { headers, status: 304 }); + const cacheKey: CacheKey = { url: key.url, headers: { etag: `"${url.pathname.replace("/", "")}"`, @@ -135,16 +139,16 @@ export const mockCaches = () => { // mocks functionality used inside worker request export function mockRequestScope() { - Object.assign(global, makeServiceWorkerEnv()); - Object.assign(global, { __STATIC_CONTENT_MANIFEST: mockManifest() }); - Object.assign(global, { __STATIC_CONTENT: mockKV(store) }); - Object.assign(global, { caches: mockCaches() }); + Object.assign(globalThis, makeServiceWorkerEnv()); + Object.assign(globalThis, { __STATIC_CONTENT_MANIFEST: mockManifest() }); + Object.assign(globalThis, { __STATIC_CONTENT: mockKV(store) }); + Object.assign(globalThis, { caches: mockCaches() }); } // mocks functionality used on global isolate scope. such as the KV namespace bind export function mockGlobalScope() { - Object.assign(global, { __STATIC_CONTENT_MANIFEST: mockManifest() }); - Object.assign(global, { __STATIC_CONTENT: mockKV(store) }); + Object.assign(globalThis, { __STATIC_CONTENT_MANIFEST: mockManifest() }); + Object.assign(globalThis, { __STATIC_CONTENT: mockKV(store) }); } export const sleep = (milliseconds: number) => { diff --git a/packages/kv-asset-handler/src/test/getAssetFromKV-optional.ts b/packages/kv-asset-handler/src/test/getAssetFromKV-optional.ts index 383dde7fc6a6..1740bb9a565e 100644 --- a/packages/kv-asset-handler/src/test/getAssetFromKV-optional.ts +++ b/packages/kv-asset-handler/src/test/getAssetFromKV-optional.ts @@ -1,24 +1,18 @@ import test from "ava"; -import { - getEvent, - mockGlobalScope, - mockKV, - mockManifest, - mockRequestScope, - sleep, -} from "../mocks"; +import { getEvent, mockGlobalScope, mockRequestScope } from "../mocks"; mockGlobalScope(); -const { getAssetFromKV, mapRequestToAsset } = require("../index"); - +// @ts-expect-error we use a require for a mock +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { getAssetFromKV } = require("../index"); // manually reset manifest global, to test optional behaviour -Object.assign(global, { __STATIC_CONTENT_MANIFEST: undefined }); +Object.assign(globalThis, { __STATIC_CONTENT_MANIFEST: undefined }); test("getAssetFromKV return correct val from KV without manifest", async (t) => { mockRequestScope(); // manually reset manifest global, to test optional behaviour - Object.assign(global, { __STATIC_CONTENT_MANIFEST: undefined }); + Object.assign(globalThis, { __STATIC_CONTENT_MANIFEST: undefined }); const event = getEvent(new Request("https://blah.com/key1.123HASHBROWN.txt")); const res = await getAssetFromKV(event); diff --git a/packages/kv-asset-handler/src/test/getAssetFromKV.ts b/packages/kv-asset-handler/src/test/getAssetFromKV.ts index de9997fde4f2..8e163c7667b7 100644 --- a/packages/kv-asset-handler/src/test/getAssetFromKV.ts +++ b/packages/kv-asset-handler/src/test/getAssetFromKV.ts @@ -7,12 +7,13 @@ import { mockRequestScope, sleep, } from "../mocks"; -import { KVError } from "../types"; +import type { KVError } from "../types"; mockGlobalScope(); +// @ts-expect-error we use a require for a mock +// eslint-disable-next-line @typescript-eslint/no-var-requires const { getAssetFromKV, mapRequestToAsset } = require("../index"); - test("getAssetFromKV return correct val from KV and default caching", async (t) => { mockRequestScope(); const event = getEvent(new Request("https://blah.com/key1.txt")); @@ -163,9 +164,9 @@ test("getAssetFromKV custom key modifier", async (t) => { const event = getEvent(new Request("https://blah.com/docs/sub/blah.png")); const customRequestMapper = (request: Request) => { - let defaultModifiedRequest = mapRequestToAsset(request); + const defaultModifiedRequest = mapRequestToAsset(request); - let url = new URL(defaultModifiedRequest.url); + const url = new URL(defaultModifiedRequest.url); url.pathname = url.pathname.replace("/docs", ""); return new Request(url.toString(), request); }; @@ -187,9 +188,9 @@ test("getAssetFromKV request override with existing manifest file", async (t) => const event = getEvent(new Request("https://blah.com/image.png")); // real file in manifest const customRequestMapper = (request: Request) => { - let defaultModifiedRequest = mapRequestToAsset(request); + const defaultModifiedRequest = mapRequestToAsset(request); - let url = new URL(defaultModifiedRequest.url); + const url = new URL(defaultModifiedRequest.url); url.pathname = "/image.webp"; // other different file in manifest return new Request(url.toString(), request); }; @@ -223,15 +224,16 @@ test("getAssetFromKV when setting custom cache setting", async (t) => { const event1 = getEvent(new Request("https://blah.com/")); const event2 = getEvent(new Request("https://blah.com/key1.png?blah=34")); const cacheOnlyPngs = (req: Request) => { - if (new URL(req.url).pathname.endsWith(".png")) + if (new URL(req.url).pathname.endsWith(".png")) { return { browserTTL: 720, edgeTTL: 720, }; - else + } else { return { bypassCache: true, }; + } }; const res1 = await getAssetFromKV(event1, { cacheControl: cacheOnlyPngs }); @@ -367,10 +369,10 @@ test("getAssetFromKV TTls set to null should not cache on browser or edge", asyn }); test("getAssetFromKV passing in a custom NAMESPACE serves correct asset", async (t) => { mockRequestScope(); - let CUSTOM_NAMESPACE = mockKV({ + const CUSTOM_NAMESPACE = mockKV({ "key1.123HASHBROWN.txt": "val1", }); - Object.assign(global, { CUSTOM_NAMESPACE }); + Object.assign(globalThis, { CUSTOM_NAMESPACE }); const event = getEvent(new Request("https://blah.com/")); const res = await getAssetFromKV(event); if (res) { @@ -382,7 +384,7 @@ test("getAssetFromKV passing in a custom NAMESPACE serves correct asset", async }); test("getAssetFromKV when custom namespace without the asset should fail", async (t) => { mockRequestScope(); - let CUSTOM_NAMESPACE = mockKV({ + const CUSTOM_NAMESPACE = mockKV({ "key5.123HASHBROWN.txt": "customvalu", }); @@ -394,8 +396,8 @@ test("getAssetFromKV when custom namespace without the asset should fail", async }); test("getAssetFromKV when namespace not bound fails", async (t) => { mockRequestScope(); - var MY_CUSTOM_NAMESPACE = undefined; - Object.assign(global, { MY_CUSTOM_NAMESPACE }); + const MY_CUSTOM_NAMESPACE: unknown = undefined; + Object.assign(globalThis, { MY_CUSTOM_NAMESPACE }); const event = getEvent(new Request("https://blah.com/")); const error: KVError = await t.throwsAsync( diff --git a/packages/kv-asset-handler/src/test/mapRequestToAsset.ts b/packages/kv-asset-handler/src/test/mapRequestToAsset.ts index a7757fe709a1..93d0605a630c 100644 --- a/packages/kv-asset-handler/src/test/mapRequestToAsset.ts +++ b/packages/kv-asset-handler/src/test/mapRequestToAsset.ts @@ -6,33 +6,33 @@ mockGlobalScope(); test("mapRequestToAsset() correctly changes /about -> /about/index.html", async (t) => { mockRequestScope(); - let path = "/about"; - let request = new Request(`https://foo.com${path}`); - let newRequest = mapRequestToAsset(request); + const path = "/about"; + const request = new Request(`https://foo.com${path}`); + const newRequest = mapRequestToAsset(request); t.is(newRequest.url, request.url + "/index.html"); }); test("mapRequestToAsset() correctly changes /about/ -> /about/index.html", async (t) => { mockRequestScope(); - let path = "/about/"; - let request = new Request(`https://foo.com${path}`); - let newRequest = mapRequestToAsset(request); + const path = "/about/"; + const request = new Request(`https://foo.com${path}`); + const newRequest = mapRequestToAsset(request); t.is(newRequest.url, request.url + "index.html"); }); test("mapRequestToAsset() correctly changes /about.me/ -> /about.me/index.html", async (t) => { mockRequestScope(); - let path = "/about.me/"; - let request = new Request(`https://foo.com${path}`); - let newRequest = mapRequestToAsset(request); + const path = "/about.me/"; + const request = new Request(`https://foo.com${path}`); + const newRequest = mapRequestToAsset(request); t.is(newRequest.url, request.url + "index.html"); }); test("mapRequestToAsset() correctly changes /about -> /about/default.html", async (t) => { mockRequestScope(); - let path = "/about"; - let request = new Request(`https://foo.com${path}`); - let newRequest = mapRequestToAsset(request, { + const path = "/about"; + const request = new Request(`https://foo.com${path}`); + const newRequest = mapRequestToAsset(request, { defaultDocument: "default.html", }); t.is(newRequest.url, request.url + "/default.html"); diff --git a/packages/kv-asset-handler/src/test/serveSinglePageApp.ts b/packages/kv-asset-handler/src/test/serveSinglePageApp.ts index 5b018e649340..bc4f8946d9cc 100644 --- a/packages/kv-asset-handler/src/test/serveSinglePageApp.ts +++ b/packages/kv-asset-handler/src/test/serveSinglePageApp.ts @@ -6,39 +6,39 @@ mockGlobalScope(); function testRequest(path: string) { mockRequestScope(); - let url = new URL("https://example.com"); + const url = new URL("https://example.com"); url.pathname = path; - let request = new Request(url.toString()); + const request = new Request(url.toString()); return request; } test("serveSinglePageApp returns root asset path when request path ends in .html", async (t) => { - let path = "/foo/thing.html"; - let request = testRequest(path); + const path = "/foo/thing.html"; + const request = testRequest(path); - let expected_request = testRequest("/index.html"); - let actual_request = serveSinglePageApp(request); + const expected_request = testRequest("/index.html"); + const actual_request = serveSinglePageApp(request); t.deepEqual(expected_request, actual_request); }); test("serveSinglePageApp returns root asset path when request path does not have extension", async (t) => { - let path = "/foo/thing"; - let request = testRequest(path); + const path = "/foo/thing"; + const request = testRequest(path); - let expected_request = testRequest("/index.html"); - let actual_request = serveSinglePageApp(request); + const expected_request = testRequest("/index.html"); + const actual_request = serveSinglePageApp(request); t.deepEqual(expected_request, actual_request); }); test("serveSinglePageApp returns requested asset when request path has non-html extension", async (t) => { - let path = "/foo/thing.js"; - let request = testRequest(path); + const path = "/foo/thing.js"; + const request = testRequest(path); - let expected_request = request; - let actual_request = serveSinglePageApp(request); + const expected_request = request; + const actual_request = serveSinglePageApp(request); t.deepEqual(expected_request, actual_request); }); diff --git a/packages/kv-asset-handler/src/types.ts b/packages/kv-asset-handler/src/types.ts index 03ea856a3669..89767098aeab 100644 --- a/packages/kv-asset-handler/src/types.ts +++ b/packages/kv-asset-handler/src/types.ts @@ -10,7 +10,7 @@ export type Options = { cacheControl: | ((req: Request) => Partial) | Partial; - ASSET_NAMESPACE: any; + ASSET_NAMESPACE: KVNamespace; ASSET_MANIFEST: AssetManifestType | string; mapRequestToAsset?: (req: Request, options?: Partial) => Request; defaultMimeType: string; diff --git a/packages/kv-asset-handler/tsconfig.json b/packages/kv-asset-handler/tsconfig.json index fbac2f58bf28..fe1a3cb4ef21 100644 --- a/packages/kv-asset-handler/tsconfig.json +++ b/packages/kv-asset-handler/tsconfig.json @@ -2,11 +2,12 @@ "compilerOptions": { "outDir": "./dist", "noImplicitAny": true, - "target": "ES2017", + "target": "ES2022", "allowJs": false, - "lib": ["WebWorker", "ES5", "ScriptHost"], - "module": "commonjs", - "moduleResolution": "node" + "types": ["@cloudflare/workers-types"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "skipLibCheck": true }, "include": [ "./src/*.ts", diff --git a/packages/wrangler/.eslintrc.js b/packages/wrangler/.eslintrc.js index da55679ce7d9..4ff918304f97 100644 --- a/packages/wrangler/.eslintrc.js +++ b/packages/wrangler/.eslintrc.js @@ -7,6 +7,7 @@ module.exports = { "pages/functions/template-worker.ts", "templates", "emitted-types", + "kv-asset-handler.js", ], overrides: [ { diff --git a/packages/wrangler/tsconfig.json b/packages/wrangler/tsconfig.json index c8f40c110d8f..1a22e94e6195 100644 --- a/packages/wrangler/tsconfig.json +++ b/packages/wrangler/tsconfig.json @@ -13,6 +13,7 @@ "src/miniflare-cli", "templates", "**/__tests__", - "**/*.test.ts" + "**/*.test.ts", + "kv-asset-handler.js" ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddaa8490d8f5..3a31fb253919 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1036,6 +1036,9 @@ importers: '@types/node': specifier: 20.8.3 version: 20.8.3 + '@types/service-worker-mock': + specifier: ^2.0.1 + version: 2.0.4 ava: specifier: ^6.0.1 version: 6.1.1(@ava/typescript@4.1.0)(encoding@0.1.13) @@ -4523,6 +4526,9 @@ packages: '@types/serve-static@1.13.10': resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==} + '@types/service-worker-mock@2.0.4': + resolution: {integrity: sha512-MEBT2eiqYfhxjqYm/oAf2AvKLbPTPwJJAYrMdheKnGyz1yG9XBRfxCzi93h27qpSvI7jOYfXqFLVMLBXFDqo4A==} + '@types/shell-quote@1.7.2': resolution: {integrity: sha512-p3SZxGp6LXB6RPdMpJmquKjaxQlN/ijyBLTKGPg9IJK6J2g2sJsMmtXP9kNR+Axxi6MDKN2e/76HCOUmvkIpcw==} @@ -13242,8 +13248,8 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-jest-dom: 4.0.3(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.7.1(eslint@8.57.0) @@ -13764,6 +13770,8 @@ snapshots: '@types/mime': 1.3.2 '@types/node': 20.8.3 + '@types/service-worker-mock@2.0.4': {} + '@types/shell-quote@1.7.2': {} '@types/signal-exit@3.0.1': {} @@ -15827,13 +15835,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0): + eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.3.4(supports-color@9.2.2) enhanced-resolve: 5.14.1 eslint: 8.57.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) get-tsconfig: 4.6.0 globby: 13.1.4 is-core-module: 2.13.0 @@ -15845,14 +15853,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -15934,7 +15942,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5)(eslint@8.57.0): + eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: array-includes: 3.1.6 array.prototype.flat: 1.3.1 @@ -15943,7 +15951,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3