diff --git a/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.editorConfig.ts b/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.editorConfig.ts index b7bbccc7e9..3cdb497b87 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.editorConfig.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.editorConfig.ts @@ -1,5 +1,5 @@ -import { StructurePreviewProps } from "@mendix/widget-plugin-platform/preview/structure-preview-api"; import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools"; +import { StructurePreviewProps } from "@mendix/widget-plugin-platform/preview/structure-preview-api"; import { BarcodeGeneratorPreviewProps, CodeFormatEnum, CustomCodeFormatEnum } from "../typings/BarcodeGeneratorProps"; import { validateAddonValue, validateBarcodeValue } from "./config/validation"; diff --git a/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.tsx b/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.tsx index ef1a43a000..9304ef8979 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/BarcodeGenerator.tsx @@ -1,9 +1,9 @@ import classNames from "classnames"; import { ReactElement } from "react"; import { BarcodeGeneratorContainerProps } from "../typings/BarcodeGeneratorProps"; -import { barcodeConfig } from "./config/Barcode.config"; -import { QRCodeRenderer } from "./components/QRCode"; import { BarcodeRenderer } from "./components/Barcode"; +import { QRCodeRenderer } from "./components/QRCode"; +import { barcodeConfig } from "./config/Barcode.config"; import "./ui/BarcodeGenerator.scss"; diff --git a/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx b/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx index 21a194ac57..01b4ef0c56 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx @@ -1,8 +1,10 @@ import "@testing-library/jest-dom"; import { fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { EditableValueBuilder } from "@mendix/widget-plugin-test-utils"; +import { Big } from "big.js"; +import { WebImage } from "mendix"; import { forwardRef } from "react"; +import { dynamic } from "@mendix/widget-plugin-test-utils"; // Mock JsBarcode const mockJsBarcode = jest.fn(); @@ -31,22 +33,23 @@ jest.mock("../utils/download-code", () => ({ downloadCode: jest.fn() })); +import { + BarcodeGeneratorContainerProps, + CodeFormatEnum, + CustomCodeFormatEnum, + QrLevelEnum +} from "../../typings/BarcodeGeneratorProps"; import BarcodeGenerator from "../BarcodeGenerator"; -import { CodeFormatEnum, CustomCodeFormatEnum } from "typings/BarcodeGeneratorProps"; import { downloadCode } from "../utils/download-code"; // Test utilities -const createMockWebImage = (status: "available" | "loading" | "unavailable" = "unavailable"): any => { - if (status === "available") { - return { - status: "available" as const, - value: { uri: "data:image/png;base64,test123" } - } as any; - } - return { status } as any; -}; - -const createBarcodeProps = (overrides: any = {}): any => ({ +function createMockWebImage(): WebImage { + return { uri: "data:image/png;base64,test123" }; +} + +const createBarcodeProps = ( + overrides: Partial = {} +): BarcodeGeneratorContainerProps => ({ name: "barcodeGenerator1", class: "mx-barcode-generator", tabIndex: -1, @@ -57,8 +60,8 @@ const createBarcodeProps = (overrides: any = {}): any => ({ lastChar: "", enableMod43: false, allowDownload: false, - downloadButtonCaption: { status: "available" as const, value: "Download" } as any, - downloadButtonAriaLabel: { status: "available" as const, value: "Download barcode" } as any, + downloadButtonCaption: dynamic("Download"), + downloadButtonAriaLabel: dynamic("Download barcode"), displayValue: false, showAsCard: false, codeWidth: 2, @@ -66,23 +69,24 @@ const createBarcodeProps = (overrides: any = {}): any => ({ codeMargin: 4, qrSize: 128, qrMargin: 2, - qrTitle: "", - qrLevel: "L" as any, - showTitle: false, - qrImage: false, - qrImageSrc: createMockWebImage(), - qrImageCenter: true, - qrImageX: 0, - qrImageY: 0, - qrImageHeight: 24, - qrImageWidth: 24, - qrImageOpacity: { toNumber: () => 1 } as any, - qrImageExcavate: true, - addonFormat: "None" as any, - addonValue: { status: "unavailable" as const } as any, + qrTitle: dynamic(""), + qrLevel: "L", + qrOverlay: false, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayCenter: true, + qrOverlayX: 0, + qrOverlayY: 0, + qrOverlayHeight: 24, + qrOverlayWidth: 24, + qrOverlayOpacity: new Big(1), + qrOverlayExcavate: true, + addonFormat: "None", + addonValue: dynamic(), addonSpacing: 20, - buttonPosition: "bottom" as const, - codeValue: new EditableValueBuilder().withValue("test-barcode-value").build(), + buttonPosition: "bottom", + codeValue: dynamic("test-barcode-value"), + logLevel: "Info", + showTitle: false, ...overrides }); @@ -95,10 +99,7 @@ describe("BarcodeGenerator", () => { describe("core rendering", () => { it("renders QR code when codeValue is available", () => { const props = createBarcodeProps({ - codeValue: { - value: "Hello World", - status: "available" - } as any + codeValue: dynamic("Hello World") }); render(); @@ -110,7 +111,7 @@ describe("BarcodeGenerator", () => { it("shows fallback message when codeValue is loading", () => { const props = createBarcodeProps({ - codeValue: { value: "", status: "loading" } as any + codeValue: dynamic("", true) }); render(); @@ -121,7 +122,7 @@ describe("BarcodeGenerator", () => { it("shows fallback message when codeValue is unavailable", () => { const props = createBarcodeProps({ - codeValue: { value: "", status: "unavailable" } as any + codeValue: dynamic() }); render(); @@ -134,7 +135,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ class: "custom-class", tabIndex: 2, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); const { container } = render(); @@ -147,7 +148,7 @@ describe("BarcodeGenerator", () => { it("applies card styling when showAsCard is true", () => { const props = createBarcodeProps({ showAsCard: true, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); const { container } = render(); @@ -162,7 +163,7 @@ describe("BarcodeGenerator", () => { it("renders CODE128 barcode correctly", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "123456789", status: "available" } as any + codeValue: dynamic("123456789") }); render(); @@ -178,7 +179,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "CODE39" as CustomCodeFormatEnum, - codeValue: { value: "ABC-123", status: "available" } as any + codeValue: dynamic("ABC-123") }); render(); @@ -194,7 +195,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "CODE93" as CustomCodeFormatEnum, - codeValue: { value: "CODE93VALUE", status: "available" } as any + codeValue: dynamic("CODE93VALUE") }); render(); @@ -210,7 +211,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN13" as CustomCodeFormatEnum, - codeValue: { value: "1234567890128", status: "available" } as any + codeValue: dynamic("1234567890128") }); render(); @@ -226,7 +227,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN8" as CustomCodeFormatEnum, - codeValue: { value: "12345678", status: "available" } as any + codeValue: dynamic("12345678") }); render(); @@ -242,7 +243,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "UPC" as CustomCodeFormatEnum, - codeValue: { value: "123456789012", status: "available" } as any + codeValue: dynamic("123456789012") }); render(); @@ -258,7 +259,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "ITF14" as CustomCodeFormatEnum, - codeValue: { value: "12345678901234", status: "available" } as any + codeValue: dynamic("12345678901234") }); render(); @@ -274,7 +275,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "MSI" as CustomCodeFormatEnum, - codeValue: { value: "123456", status: "available" } as any + codeValue: dynamic("123456") }); render(); @@ -290,7 +291,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "pharmacode" as CustomCodeFormatEnum, - codeValue: { value: "1234567", status: "available" } as any + codeValue: dynamic("1234567") }); render(); @@ -306,7 +307,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "codabar" as CustomCodeFormatEnum, - codeValue: { value: "123-456", status: "available" } as any + codeValue: dynamic("123-456") }); render(); @@ -324,7 +325,7 @@ describe("BarcodeGenerator", () => { it("renders QR code with custom size", () => { const props = createBarcodeProps({ qrSize: 256, - codeValue: { value: "Custom Size QR", status: "available" } as any + codeValue: dynamic("Custom Size QR") }); render(); @@ -335,7 +336,7 @@ describe("BarcodeGenerator", () => { it("renders QR code with custom margin", () => { const props = createBarcodeProps({ qrMargin: 5, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -344,12 +345,12 @@ describe("BarcodeGenerator", () => { }); it("renders QR code with all error correction levels", () => { - const levels: any[] = ["L", "M", "Q", "H"]; + const levels: QrLevelEnum[] = ["L", "M", "Q", "H"]; levels.forEach(level => { const props = createBarcodeProps({ qrLevel: level, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); const { unmount } = render(); @@ -361,9 +362,9 @@ describe("BarcodeGenerator", () => { it("renders QR code with title", () => { const props = createBarcodeProps({ - qrTitle: { value: "QR Code Title", status: "available" } as any, + qrTitle: dynamic("QR Code Title"), showTitle: true, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -374,11 +375,12 @@ describe("BarcodeGenerator", () => { // ============= QR Image Overlay Tests ============= describe("QR image overlay functionality", () => { - it("renders QR code with image overlay when qrImage is true", () => { + it("renders QR code with image overlay when qrOverlay is true", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayCenter: true, + codeValue: dynamic("test") }); render(); @@ -388,10 +390,12 @@ describe("BarcodeGenerator", () => { it("renders QR code with centered image overlay", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - qrImageCenter: true, - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayCenter: true, + qrOverlayX: 10, + qrOverlayY: 20, + codeValue: dynamic("test") }); render(); @@ -401,12 +405,12 @@ describe("BarcodeGenerator", () => { it("renders QR code with positioned image overlay", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - qrImageCenter: false, - qrImageX: 10, - qrImageY: 20, - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayCenter: false, + qrOverlayX: 10, + qrOverlayY: 20, + codeValue: dynamic("test") }); render(); @@ -416,11 +420,11 @@ describe("BarcodeGenerator", () => { it("renders QR code with image overlay custom dimensions", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - qrImageWidth: 50, - qrImageHeight: 50, - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayWidth: 50, + qrOverlayHeight: 50, + codeValue: dynamic("test") }); render(); @@ -430,10 +434,10 @@ describe("BarcodeGenerator", () => { it("renders QR code with image overlay opacity", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - qrImageOpacity: { toNumber: () => 0.75 } as any, - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayOpacity: Big(0.75), + codeValue: dynamic("test") }); render(); @@ -443,10 +447,10 @@ describe("BarcodeGenerator", () => { it("renders QR code with image excavation enabled", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("available"), - qrImageExcavate: true, - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + qrOverlayExcavate: true, + codeValue: dynamic("test") }); render(); @@ -454,11 +458,11 @@ describe("BarcodeGenerator", () => { expect(screen.getByTestId("qr-code")).toBeInTheDocument(); }); - it("does not render image overlay when qrImageSrc is unavailable", () => { + it("does not render image overlay when qrOverlaySrc is unavailable", () => { const props = createBarcodeProps({ - qrImage: true, - qrImageSrc: createMockWebImage("unavailable"), - codeValue: { value: "test", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(), + codeValue: dynamic("test") }); render(); @@ -473,7 +477,7 @@ describe("BarcodeGenerator", () => { it("does not render download button when allowDownload is false", () => { const props = createBarcodeProps({ allowDownload: false, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -484,8 +488,8 @@ describe("BarcodeGenerator", () => { it("renders download button with custom caption", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Export Code" } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Export Code"), + codeValue: dynamic("test") }); render(); @@ -496,9 +500,9 @@ describe("BarcodeGenerator", () => { it("renders download button with correct aria-label for QR code", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonAriaLabel: { status: "available" as const, value: "Download QR code" } as any, + downloadButtonAriaLabel: dynamic("Download QR code"), codeFormat: "QRCode" as CodeFormatEnum, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -510,8 +514,8 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ allowDownload: true, buttonPosition: "top" as const, - downloadButtonCaption: { status: "available" as const, value: "Download" } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Download"), + codeValue: dynamic("test") }); const { container } = render(); @@ -529,8 +533,8 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ allowDownload: true, buttonPosition: "bottom" as const, - downloadButtonCaption: { status: "available" as const, value: "Download" } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Download"), + codeValue: dynamic("test") }); render(); @@ -544,9 +548,9 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Download" } as any, + downloadButtonCaption: dynamic("Download"), codeFormat: "QRCode" as CodeFormatEnum, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -560,8 +564,8 @@ describe("BarcodeGenerator", () => { it("renders download button with icon and caption", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Save" } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Save"), + codeValue: dynamic("test") }); render(); @@ -577,7 +581,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, displayValue: true, - codeValue: { value: "DISPLAY123", status: "available" } as any + codeValue: dynamic("DISPLAY123") }); render(); @@ -593,7 +597,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, displayValue: false, - codeValue: { value: "NODISPLAY", status: "available" } as any + codeValue: dynamic("NODISPLAY") }); render(); @@ -609,7 +613,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, codeWidth: 3, - codeValue: { value: "WIDTH_TEST", status: "available" } as any + codeValue: dynamic("WIDTH_TEST") }); render(); @@ -625,7 +629,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, codeHeight: 300, - codeValue: { value: "HEIGHT_TEST", status: "available" } as any + codeValue: dynamic("HEIGHT_TEST") }); render(); @@ -641,7 +645,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, codeMargin: 8, - codeValue: { value: "MARGIN_TEST", status: "available" } as any + codeValue: dynamic("MARGIN_TEST") }); render(); @@ -660,7 +664,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, enableEan128: true, - codeValue: { value: "EAN128TEST", status: "available" } as any + codeValue: dynamic("EAN128TEST") }); render(); @@ -676,7 +680,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, enableFlat: true, - codeValue: { value: "FLATTEST", status: "available" } as any + codeValue: dynamic("FLATTEST") }); render(); @@ -692,7 +696,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, enableMod43: true, - codeValue: { value: "MOD43TEST", status: "available" } as any + codeValue: dynamic("MOD43TEST") }); render(); @@ -708,7 +712,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, lastChar: "X", - codeValue: { value: "LASTCHARTEST", status: "available" } as any + codeValue: dynamic("LASTCHARTEST") }); render(); @@ -736,10 +740,10 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN13" as CustomCodeFormatEnum, - addonValue: { value: "12345", status: "available" } as any, - addonFormat: "EAN5" as any, + addonValue: dynamic("12345"), + addonFormat: "EAN5", addonSpacing: 25, - codeValue: { value: "1234567890128", status: "available" } as any + codeValue: dynamic("1234567890128") }); render(); @@ -764,9 +768,9 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN13" as CustomCodeFormatEnum, - addonValue: { value: "12", status: "available" } as any, - addonFormat: "EAN2" as any, - codeValue: { value: "1234567890128", status: "available" } as any + addonValue: dynamic("12"), + addonFormat: "EAN2", + codeValue: dynamic("1234567890128") }); render(); @@ -780,9 +784,9 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN13" as CustomCodeFormatEnum, - addonValue: { value: "12345", status: "available" } as any, - addonFormat: "None" as any, - codeValue: { value: "1234567890128", status: "available" } as any + addonValue: dynamic("12345"), + addonFormat: "None", + codeValue: dynamic("1234567890128") }); render(); @@ -803,10 +807,10 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "Custom" as CodeFormatEnum, customCodeFormat: "EAN13" as CustomCodeFormatEnum, - addonValue: { value: "12345", status: "available" } as any, - addonFormat: "EAN5" as any, + addonValue: dynamic("12345"), + addonFormat: "EAN5", addonSpacing: 40, - codeValue: { value: "1234567890128", status: "available" } as any + codeValue: dynamic("1234567890128") }); render(); @@ -824,7 +828,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "INVALID", status: "available" } as any + codeValue: dynamic("INVALID") }); render(); @@ -840,7 +844,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "TEST", status: "available" } as any + codeValue: dynamic("TEST") }); render(); @@ -857,7 +861,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "BAD", status: "available" } as any + codeValue: dynamic("BAD") }); const { unmount } = render(); @@ -872,7 +876,7 @@ describe("BarcodeGenerator", () => { const goodProps = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "GOOD", status: "available" } as any + codeValue: dynamic("GOOD") }); render(); @@ -885,9 +889,9 @@ describe("BarcodeGenerator", () => { describe("accessibility", () => { it("renders QR code title as semantic element when provided", () => { const props = createBarcodeProps({ - qrTitle: { value: "Invoice QR Code", status: "available" } as any, + qrTitle: dynamic("Invoice QR Code"), showTitle: true, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -897,11 +901,11 @@ describe("BarcodeGenerator", () => { expect(title.tagName).toBe("H3"); }); - it("does not render title when qrTitle is empty", () => { + it("does not render title when showTitle is false", () => { const props = createBarcodeProps({ - qrTitle: { value: "", status: "available" } as any, + qrTitle: dynamic("title"), showTitle: false, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); render(); @@ -912,12 +916,9 @@ describe("BarcodeGenerator", () => { it("download button has proper semantics", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Download Barcode" } as any, - downloadButtonAriaLabel: { - status: "available" as const, - value: "Download current barcode as PNG" - } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Download Barcode"), + downloadButtonAriaLabel: dynamic("Download current barcode as PNG"), + codeValue: dynamic("test") }); render(); @@ -932,8 +933,8 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Download" } as any, - codeValue: { value: "test", status: "available" } as any + downloadButtonCaption: dynamic("Download"), + codeValue: dynamic("test") }); render(); @@ -953,7 +954,7 @@ describe("BarcodeGenerator", () => { const props = createBarcodeProps({ codeFormat: "CODE128" as CodeFormatEnum, - codeValue: { value: "TEST", status: "available" } as any + codeValue: dynamic("TEST") }); render(); @@ -964,7 +965,7 @@ describe("BarcodeGenerator", () => { it("barcode widget container is focusable when tabIndex is set", () => { const props = createBarcodeProps({ tabIndex: 0, - codeValue: { value: "test", status: "available" } as any + codeValue: dynamic("test") }); const { container } = render(); @@ -979,12 +980,12 @@ describe("BarcodeGenerator", () => { it("renders QR code with download, title, and image overlay", () => { const props = createBarcodeProps({ allowDownload: true, - qrTitle: { value: "Secure QR", status: "available" } as any, + qrTitle: dynamic("Secure QR"), showTitle: true, - qrImage: true, - qrImageSrc: createMockWebImage("available"), - downloadButtonCaption: { status: "available" as const, value: "Save QR" } as any, - codeValue: { value: "secure-data", status: "available" } as any + qrOverlay: true, + qrOverlaySrc: dynamic(createMockWebImage()), + downloadButtonCaption: dynamic("Save QR"), + codeValue: dynamic("secure-data") }); render(); @@ -1008,12 +1009,12 @@ describe("BarcodeGenerator", () => { enableFlat: true, enableMod43: true, allowDownload: true, - downloadButtonCaption: { status: "available" as const, value: "Export" } as any, + downloadButtonCaption: dynamic("Export"), codeWidth: 3, codeHeight: 250, codeMargin: 5, lastChar: "Z", - codeValue: { value: "FULL_TEST", status: "available" } as any + codeValue: dynamic("FULL_TEST") }); render(); diff --git a/packages/pluggableWidgets/barcode-generator-web/src/assets/barcodePreview.assets.ts b/packages/pluggableWidgets/barcode-generator-web/src/assets/barcodePreview.assets.ts index e62f30435a..12d25ce641 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/assets/barcodePreview.assets.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/assets/barcodePreview.assets.ts @@ -1,22 +1,22 @@ // Import all barcode SVG files +import codabarSvg from "./barcodes/codabar.svg"; import code128Svg from "./barcodes/code128.svg"; -import ean13Svg from "./barcodes/ean13.svg"; +import code39Svg from "./barcodes/code39.svg"; +import code93Svg from "./barcodes/code93.svg"; import ean13Ean2Svg from "./barcodes/ean13-ean2.svg"; import ean13Ean5Svg from "./barcodes/ean13-ean5.svg"; import ean13FlatSvg from "./barcodes/ean13-flat.svg"; -import ean8Svg from "./barcodes/ean8.svg"; +import ean13Svg from "./barcodes/ean13.svg"; import ean8Ean2Svg from "./barcodes/ean8-ean2.svg"; import ean8Ean5Svg from "./barcodes/ean8-ean5.svg"; import ean8FlatSvg from "./barcodes/ean8-flat.svg"; -import upcSvg from "./barcodes/upc.svg"; -import upcEan2Svg from "./barcodes/upc-ean2.svg"; -import upcEan5Svg from "./barcodes/upc-ean5.svg"; -import code39Svg from "./barcodes/code39.svg"; +import ean8Svg from "./barcodes/ean8.svg"; import itf14Svg from "./barcodes/itf14.svg"; import msiSvg from "./barcodes/msi.svg"; import pharmacodeSvg from "./barcodes/pharmacode.svg"; -import codabarSvg from "./barcodes/codabar.svg"; -import code93Svg from "./barcodes/code93.svg"; +import upcEan2Svg from "./barcodes/upc-ean2.svg"; +import upcEan5Svg from "./barcodes/upc-ean5.svg"; +import upcSvg from "./barcodes/upc.svg"; type BarcodeImageVariants = { default: string; diff --git a/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx b/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx index 94816d2045..8f29af1214 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx @@ -1,9 +1,8 @@ +import { ReactElement } from "react"; +import { DownloadButton } from "./DownloadButton"; +import { BarcodeTypeConfig } from "../config/Barcode.config"; import { useRenderBarcode } from "../hooks/useRenderBarcode"; import { downloadCode } from "../utils/download-code"; -import { BarcodeTypeConfig } from "../config/Barcode.config"; -import { DownloadButton } from "./DownloadButton"; - -import { ReactElement } from "react"; interface BarcodeRendererProps { config: BarcodeTypeConfig; diff --git a/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx b/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx index 6b8ea98dc4..d07f7b7bc4 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx @@ -1,8 +1,8 @@ import { QRCodeSVG } from "qrcode.react"; import { forwardRef, ReactElement, useRef } from "react"; +import { DownloadButton } from "./DownloadButton"; import { QRCodeTypeConfig } from "../config/Barcode.config"; import { downloadCode } from "../utils/download-code"; -import { DownloadButton } from "./DownloadButton"; interface QRCodeRendererProps { config: QRCodeTypeConfig; diff --git a/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts b/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts index a702482210..78a01c19a1 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts @@ -13,17 +13,15 @@ interface DownloadButtonConfig { buttonPosition: "top" | "bottom"; } -type CodeType = "barcode" | "qrcode"; - -export interface CodeBaseTypeConfig extends Pick { - type: T; +export interface CodeBaseTypeConfig extends Pick { codeValue: string; margin: number; downloadButton?: DownloadButtonConfig; } /** Configuration for barcode (non-QR) rendering */ -export interface BarcodeTypeConfig extends CodeBaseTypeConfig<"barcode"> { +export interface BarcodeTypeConfig extends CodeBaseTypeConfig { + type: "barcode"; width: number; height: number; format: CodeFormatEnum | CustomCodeFormatEnum; @@ -40,7 +38,8 @@ export interface BarcodeTypeConfig extends CodeBaseTypeConfig<"barcode"> { } /** Configuration for QR code rendering */ -export interface QRCodeTypeConfig extends CodeBaseTypeConfig<"qrcode"> { +export interface QRCodeTypeConfig extends CodeBaseTypeConfig { + type: "qrcode"; size: number; title: string; showTitle: boolean; @@ -72,20 +71,18 @@ export function barcodeConfig(props: BarcodeGeneratorContainerProps): BarcodeCon : undefined; const baseConfig: CodeBaseTypeConfig = { - type: "barcode", codeValue, - margin: props.codeMargin ?? 2, + margin: (format === "QRCode" ? props.qrMargin : props.codeMargin) ?? 2, logLevel: props.logLevel, downloadButton: downloadButtonConfig }; if (format === "QRCode") { - const qrConfig: QRCodeTypeConfig = { - ...baseConfig, - margin: props.qrMargin ?? 2, + return { type: "qrcode", + ...baseConfig, size: props.qrSize ?? 128, - showTitle: props.showTitle ?? false, + showTitle: props.showTitle, title: props.qrTitle.status === "available" ? props.qrTitle.value : "QR Code", level: props.qrLevel ?? "L", overlay: @@ -101,12 +98,11 @@ export function barcodeConfig(props: BarcodeGeneratorContainerProps): BarcodeCon } : undefined }; - return qrConfig; } - const barcodeConfig: BarcodeTypeConfig = { - ...baseConfig, + return { type: "barcode", + ...baseConfig, width: props.codeWidth ?? 128, height: props.codeHeight ?? 128, format, @@ -121,8 +117,6 @@ export function barcodeConfig(props: BarcodeGeneratorContainerProps): BarcodeCon addonFormat: props.addonFormat, addonSpacing: props.addonSpacing ?? 20 }; - - return barcodeConfig; } function generateFileName(customFileName: string | undefined, format: string, codeValue: string): string { diff --git a/packages/pluggableWidgets/barcode-generator-web/src/hooks/useRenderBarcode.ts b/packages/pluggableWidgets/barcode-generator-web/src/hooks/useRenderBarcode.ts index 76fda107a1..3d6af89992 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/hooks/useRenderBarcode.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/hooks/useRenderBarcode.ts @@ -1,7 +1,7 @@ -import { BarcodeTypeConfig } from "../config/Barcode.config"; import { RefObject, useEffect, useRef, useState } from "react"; -import { type BarcodeRenderOptions, renderBarcode } from "../utils/barcodeRenderer-utils"; +import { BarcodeTypeConfig } from "../config/Barcode.config"; import { validateAddonValue, validateBarcodeValue } from "../config/validation"; +import { type BarcodeRenderOptions, renderBarcode } from "../utils/barcodeRenderer-utils"; import { printError } from "../utils/helpers"; export const useRenderBarcode = ( diff --git a/packages/pluggableWidgets/barcode-generator-web/src/utils/helpers.ts b/packages/pluggableWidgets/barcode-generator-web/src/utils/helpers.ts index f4f6c5f27e..2721935434 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/utils/helpers.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/utils/helpers.ts @@ -1,6 +1,6 @@ import { LogLevelEnum } from "../../typings/BarcodeGeneratorProps"; -export function printError(message: string, logLevel: LogLevelEnum) { +export function printError(message: string, logLevel: LogLevelEnum): void { if (logLevel === "Debug") { console.error(`[Barcode Generator] ${message}`); } diff --git a/packages/shared/eslint-config-web-widgets/package.json b/packages/shared/eslint-config-web-widgets/package.json index e76152ee47..f556ac86a5 100644 --- a/packages/shared/eslint-config-web-widgets/package.json +++ b/packages/shared/eslint-config-web-widgets/package.json @@ -15,6 +15,7 @@ "@mendix/prettier-config-web-widgets": "workspace:*", "eslint": "^9.39.3", "eslint-plugin-cypress": "^5.1.1", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-jest": "^29.15.0", "eslint-plugin-package-json": "^0.89.1", "eslint-plugin-prettier": "^5.5.5", diff --git a/packages/shared/eslint-config-web-widgets/widget-ts.mjs b/packages/shared/eslint-config-web-widgets/widget-ts.mjs index 0816d72572..e055ea8430 100644 --- a/packages/shared/eslint-config-web-widgets/widget-ts.mjs +++ b/packages/shared/eslint-config-web-widgets/widget-ts.mjs @@ -7,11 +7,21 @@ import jestPlugin from "eslint-plugin-jest"; import packageJson from "eslint-plugin-package-json"; import packageJsonFieldsOrder from "@mendix/prettier-config-web-widgets/package-json-fields-order.js"; import { defineConfig } from "eslint/config"; +import importPlugin from "eslint-plugin-import"; export default defineConfig( { name: "generic eslint", - extends: [eslint.configs.recommended], + extends: [eslint.configs.recommended, importPlugin.flatConfigs.recommended], + settings: { + "import/internal-regex": "^@mendix/", + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx"] + } + }, + languageOptions: { + ecmaVersion: "latest" + }, rules: { "no-undef": "warn", "no-unused-vars": "warn", @@ -63,11 +73,24 @@ export default defineConfig( "prefer-spread": "error", radix: "error", "spaced-comment": "error", - "sort-imports": [ - "error", + "sort-imports": "off", + "import/no-unresolved": "off", + "import/namespace": "off", + "import/named": "off", + "import/order": [ + "warn", { - ignoreDeclarationSort: true, - ignoreCase: true + alphabetize: { + order: "asc", + caseInsensitive: true + }, + groups: [ + // Imports of builtins are first + "builtin", + "external", + // Then index file imports + "internal" + ] } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8d9ca2a9f..755141cb4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2656,6 +2656,9 @@ importers: eslint-plugin-cypress: specifier: ^5.1.1 version: 5.4.0(eslint@9.39.3(jiti@2.6.1)) + eslint-plugin-import: + specifier: ^2.32.0 + version: 2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1)) eslint-plugin-jest: specifier: ^29.15.0 version: 29.15.0(@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(jest@29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)))(typescript@5.9.3) @@ -4740,6 +4743,9 @@ packages: rollup: optional: true + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -5003,6 +5009,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/katex@0.16.7': resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} @@ -5501,6 +5510,10 @@ packages: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + array.prototype.flat@1.3.3: resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} @@ -6672,12 +6685,46 @@ packages: '@types/estree': optional: true + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + eslint-plugin-cypress@5.4.0: resolution: {integrity: sha512-XAQYuzMpLWJdFRQorPO3GDx4XHqI362qr1/XIp0N6SNTAa8lyzmpTA26qNRc99I53NnqX9l0SHwbHXX7TAKIkg==} deprecated: 'deprecate: accidentally includes breaking changes from 6.0.0' peerDependencies: eslint: '>=9' + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-plugin-jest@29.15.0: resolution: {integrity: sha512-ZCGr7vTH2WSo2hrK5oM2RULFmMruQ7W3cX7YfwoTiPfzTGTFBMmrVIz45jZHd++cGKj/kWf02li/RhTGcANJSA==} engines: {node: ^20.12.0 || ^22.0.0 || >=24.0.0} @@ -8688,6 +8735,10 @@ packages: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} @@ -10096,6 +10147,10 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -10371,6 +10426,9 @@ packages: '@swc/wasm': optional: true + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -13137,6 +13195,8 @@ snapshots: optionalDependencies: rollup: 3.29.5 + '@rtsao/scc@1.1.0': {} + '@sinclair/typebox@0.27.8': {} '@sinclair/typebox@0.34.41': {} @@ -13410,6 +13470,8 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/json5@0.0.29': {} + '@types/katex@0.16.7': {} '@types/leaflet@1.9.21': @@ -14021,6 +14083,16 @@ snapshots: es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + array.prototype.flat@1.3.3: dependencies: call-bind: 1.0.8 @@ -15357,11 +15429,58 @@ snapshots: optionalDependencies: '@types/estree': 1.0.8 + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.3(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + eslint-plugin-cypress@5.4.0(eslint@9.39.3(jiti@2.6.1)): dependencies: eslint: 9.39.3(jiti@2.6.1) globals: 17.4.0 + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.3(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.3(jiti@2.6.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-jest@29.15.0(@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(jest@29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)))(typescript@5.9.3): dependencies: '@typescript-eslint/utils': 8.57.0(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) @@ -16854,7 +16973,7 @@ snapshots: jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) jest-util: 29.7.0 jest-validate: 29.7.0 - resolve: 1.22.10 + resolve: 1.22.11 resolve.exports: 2.0.3 slash: 3.0.0 @@ -17867,6 +17986,12 @@ snapshots: es-abstract: 1.24.0 es-object-atoms: 1.1.1 + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + object.values@1.2.1: dependencies: call-bind: 1.0.8 @@ -18851,7 +18976,7 @@ snapshots: rechoir@0.8.0: dependencies: - resolve: 1.22.10 + resolve: 1.22.11 recursive-copy@2.0.14: dependencies: @@ -19595,6 +19720,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom@3.0.0: {} + strip-bom@4.0.0: {} strip-final-newline@2.0.0: {} @@ -19862,6 +19989,13 @@ snapshots: optionalDependencies: '@swc/core': 1.13.5 + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@1.14.1: {} tslib@2.8.1: {}