diff --git a/package-lock.json b/package-lock.json index 7487e73ca21..1c214f9f210 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@esri/calcite-colors": "6.1.0", "@prettier/sync": "0.5.2", "@rollup/plugin-node-resolve": "15.2.3", + "@rollup/plugin-replace": "5.0.7", "@rollup/plugin-typescript": "11.1.6", "@storybook/addon-a11y": "8.0.9", "@storybook/addon-controls": "8.0.9", @@ -6422,6 +6423,27 @@ } } }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-typescript": { "version": "11.1.6", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", diff --git a/package.json b/package.json index 78f383c25f4..992a7b6f6f2 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@esri/calcite-colors": "6.1.0", "@prettier/sync": "0.5.2", "@rollup/plugin-node-resolve": "15.2.3", + "@rollup/plugin-replace": "5.0.7", "@rollup/plugin-typescript": "11.1.6", "@storybook/addon-a11y": "8.0.9", "@storybook/addon-controls": "8.0.9", diff --git a/packages/calcite-components/src/utils/config.spec.ts b/packages/calcite-components/src/utils/config.spec.ts index 662dc031954..2795b1e0190 100644 --- a/packages/calcite-components/src/utils/config.spec.ts +++ b/packages/calcite-components/src/utils/config.spec.ts @@ -1,12 +1,10 @@ -import type { CalciteConfig } from "./config"; - describe("config", () => { - let config: CalciteConfig; + let config: typeof import("./config"); /** * Need to load the config at runtime to allow test to specify custom configuration if needed. */ - async function loadConfig(): Promise { + async function loadConfig(): Promise { return import("./config"); } @@ -28,4 +26,29 @@ describe("config", () => { expect(config.focusTrapStack).toBe(customFocusTrapStack); }); + + describe("stampVersion", () => { + const calciteVersionPreBuildPlaceholder = "__CALCITE_VERSION__"; + + it("creates global config and stamps the version onto it", async () => { + config = await loadConfig(); + config.stampVersion(); + expect(globalThis.calciteConfig.version).toBe(calciteVersionPreBuildPlaceholder); + }); + + it("stamps the version onto existing config if there's no version present", async () => { + globalThis.calciteConfig = {}; + config = await loadConfig(); + config.stampVersion(); + expect(globalThis.calciteConfig.version).toBe(calciteVersionPreBuildPlaceholder); + }); + + it("warns if the version is already set", async () => { + globalThis.calciteConfig = { version: "1.33.7" }; + config = await loadConfig(); + const warnSpy = jest.spyOn(console, "warn"); + config.stampVersion(); + expect(warnSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/calcite-components/src/utils/config.ts b/packages/calcite-components/src/utils/config.ts index 0948e861e53..05d0705ed4d 100644 --- a/packages/calcite-components/src/utils/config.ts +++ b/packages/calcite-components/src/utils/config.ts @@ -13,8 +13,38 @@ export interface CalciteConfig { * @see https://github.com/focus-trap/focus-trap#createoptions */ focusTrapStack: FocusTrap[]; + + /** + * Contains the version of the Calcite components. + * + * @readonly + */ + version?: string; } const customConfig: CalciteConfig = globalThis["calciteConfig"]; export const focusTrapStack: FocusTrap[] = customConfig?.focusTrapStack || []; + +const version = "__CALCITE_VERSION__"; // version number is set by build + +/** + * Stamp the version onto the global config. + */ +export function stampVersion(): void { + if (customConfig && customConfig.version) { + console.warn( + `[calcite-components] while initializing v${version}, an existing configuration with version "${customConfig.version}" was found. This may cause unexpected behavior. The version will not be added to the existing global configuration.`, + ); + return; + } + + const target = customConfig || globalThis["calciteConfig"] || {}; + + Object.defineProperty(target, "version", { + value: version, + writable: false, + }); + + globalThis["calciteConfig"] = target; +} diff --git a/packages/calcite-components/src/utils/globalScript.ts b/packages/calcite-components/src/utils/globalScript.ts index e97b44544e0..bead6265c2e 100644 --- a/packages/calcite-components/src/utils/globalScript.ts +++ b/packages/calcite-components/src/utils/globalScript.ts @@ -1,4 +1,5 @@ import { initModeChangeEvent } from "./mode"; +import { stampVersion } from "./config"; /** * This file is imported in Stencil's `globalScript` config option. @@ -20,4 +21,6 @@ export default function (): void { document.addEventListener("DOMContentLoaded", () => initModeChangeEvent(), { once: true }); } } + + stampVersion(); } diff --git a/packages/calcite-components/stencil.config.ts b/packages/calcite-components/stencil.config.ts index 50d6a6ca87e..f4450fb83a8 100644 --- a/packages/calcite-components/stencil.config.ts +++ b/packages/calcite-components/stencil.config.ts @@ -6,6 +6,7 @@ import { reactOutputTarget } from "@stencil/react-output-target"; import { angularOutputTarget } from "@stencil/angular-output-target"; import tailwindcss, { Config as TailwindConfig } from "tailwindcss"; import stylelint from "stylelint"; +import replace from "@rollup/plugin-replace"; import tailwindConfig from "./tailwind.config"; import { generatePreactTypes } from "./support/preact"; import { version } from "./package.json"; @@ -141,6 +142,17 @@ export const create: () => Config = () => ({ ], }), ], + rollupPlugins: { + before: [ + replace({ + values: { + __CALCITE_VERSION__: version, + }, + include: ["src/utils/config.ts"], + preventAssignment: true, + }), + ], + }, testing: { watchPathIgnorePatterns: ["/../../node_modules", "/dist", "/www", "/hydrate"], moduleNameMapper: {