refactor: Stamp build information in as "defines" (#2654)

This commit is contained in:
Dermot Duffy
2026-08-03 22:36:32 -07:00
committed by GitHub
parent 2d124fe3cd
commit 06bcfd58ba
13 changed files with 133 additions and 148 deletions
-1
View File
@@ -81,7 +81,6 @@
"playwright": "1.62.0", "playwright": "1.62.0",
"prettier": "^3.3.2", "prettier": "^3.3.2",
"rollup": "^3.29.4", "rollup": "^3.29.4",
"rollup-plugin-git-info": "^1.0.0",
"rollup-plugin-serve": "^1.1.1", "rollup-plugin-serve": "^1.1.1",
"rollup-plugin-styler": "^1.8.0", "rollup-plugin-styler": "^1.8.0",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
+3 -14
View File
@@ -5,13 +5,12 @@ import { nodeResolve } from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace'; import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser'; import terser from '@rollup/plugin-terser';
import typescript from '@rollup/plugin-typescript'; import typescript from '@rollup/plugin-typescript';
import gitInfo from 'rollup-plugin-git-info';
import serve from 'rollup-plugin-serve'; import serve from 'rollup-plugin-serve';
import styles from 'rollup-plugin-styler'; import styles from 'rollup-plugin-styler';
import { visualizer } from 'rollup-plugin-visualizer'; import { visualizer } from 'rollup-plugin-visualizer';
import { getBuildDefines } from './scripts/build-defines.js';
import { cleanDist } from './scripts/clean-dist-plugin.js'; import { cleanDist } from './scripts/clean-dist-plugin.js';
import { RELEASE_VERSION_TOKEN } from './scripts/release-version.js';
import { svgPath } from './scripts/svg-path-plugin.js'; import { svgPath } from './scripts/svg-path-plugin.js';
const watch = process.env.ROLLUP_WATCH === 'true' || process.env.ROLLUP_WATCH === '1'; const watch = process.env.ROLLUP_WATCH === 'true' || process.env.ROLLUP_WATCH === '1';
@@ -39,16 +38,6 @@ const serveopts = {
*/ */
const plugins = [ const plugins = [
cleanDist(), cleanDist(),
gitInfo.default(
// Limit git-info to the project's own package.json. Without this it also
// rewrites any dependency's imported package.json into ESM, which then breaks
// the json() plugin downstream (ha-nunjucks imports its own package.json).
{
enableBuildDate: true,
updateVersion: false,
include: 'package.json',
},
),
styles({ styles({
modules: false, modules: false,
// Behavior of inject mode, without actually injecting style // Behavior of inject mode, without actually injecting style
@@ -72,12 +61,12 @@ const plugins = [
inlineSources: dev, inlineSources: dev,
exclude: ['dist/**', 'tests/**/*.test.ts'], exclude: ['dist/**', 'tests/**/*.test.ts'],
}), }),
json({ exclude: 'package.json' }), json(),
replace({ replace({
preventAssignment: true, preventAssignment: true,
values: { values: {
'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'), 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'),
[RELEASE_VERSION_TOKEN]: process.env.RELEASE_VERSION ?? (dev ? 'dev' : 'pkg'), ...getBuildDefines({ dev, releaseVersion: process.env.RELEASE_VERSION }),
}, },
}), }),
serveEnabled && serve(serveopts), serveEnabled && serve(serveopts),
+44
View File
@@ -0,0 +1,44 @@
import { execFileSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
/**
* Asks git something or gives back nothing when it cannot be asked.
*/
const askGit = (...args) => {
try {
return execFileSync('git', args, {
encoding: 'utf-8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
} catch {
return '';
}
};
const getPackageVersion = () =>
JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8')).version;
/**
* What the build stamps into the card, as names for the bundler to substitute.
*
* `releaseVersion` is the version being released, which only the release
* workflow knows; a build without one reports the version in `package.json`, or
* a development build the commit it was made from.
*
* The values are JSON so that a bundler can drop them in as written.
*/
export const getBuildDefines = ({ dev, releaseVersion }) => {
const gitHash = askGit('rev-parse', '--short', 'HEAD');
const developmentVersion = gitHash ? `dev+${gitHash}` : 'dev';
return {
__ADVANCED_CAMERA_CARD_RELEASE_VERSION__: JSON.stringify(
releaseVersion ?? (dev ? developmentVersion : getPackageVersion()),
),
__ADVANCED_CAMERA_CARD_GIT_HASH__: JSON.stringify(gitHash),
__ADVANCED_CAMERA_CARD_GIT_DATE__: JSON.stringify(
askGit('log', '-1', '--format=%cI'),
),
__ADVANCED_CAMERA_CARD_BUILD_DATE__: JSON.stringify(new Date().toISOString()),
};
};
-25
View File
@@ -1,25 +0,0 @@
import { RELEASE_VERSION_TOKEN } from './release-version.js';
// What the card substitutes to mean "the version in package.json". The
// development substitution is not used here because it appends a git hash that
// only a build step knows.
const PACKAGE_VERSION = 'pkg';
/**
* Substitutes the release version the way the build does.
*
* The card reads it out of a string literal that Rollup rewrites, so without
* this it renders the placeholder itself: the loading screen shows the raw
* token, which then appears in every failure screenshot.
*/
export const releaseVersion = () => ({
name: 'release-version',
transform(code, id) {
if (!id.includes('src/utils/diagnostics.ts')) {
return null;
}
return { code: code.replace(RELEASE_VERSION_TOKEN, PACKAGE_VERSION), map: null };
},
});
-12
View File
@@ -1,12 +0,0 @@
/**
* The literal the card carries in place of its version, for the build to
* rewrite.
*
* `getReleaseVersion` cannot import this: it has to sit in that source as a
* plain string for the build to have something to replace. It lives in its own
* module because the build, the browser tests and a unit test all have to agree
* on it, and none of them should have to depend on either of the others.
*
* It must be in a JS file as Node's loader cannot import TypeScript.
*/
export const RELEASE_VERSION_TOKEN = '__ADVANCED_CAMERA_CARD_RELEASE_VERSION__';
+1 -1
View File
@@ -65,7 +65,7 @@ import { localize } from './localize/localize.js';
import cardStyle from './scss/card.scss'; import cardStyle from './scss/card.scss';
import type { MediaLoadedInfoEventDetail } from './types.js'; import type { MediaLoadedInfoEventDetail } from './types.js';
import { hasAction } from './utils/action.js'; import { hasAction } from './utils/action.js';
import { getReleaseVersion } from './utils/diagnostics'; import { getReleaseVersion } from './utils/build-info.js';
// *************************************************************************** // ***************************************************************************
// General Card-Wide Notes // General Card-Wide Notes
+1 -1
View File
@@ -9,7 +9,7 @@ import { customElement, property } from 'lit/decorators.js';
import loadingStyle from '../scss/loading.scss'; import loadingStyle from '../scss/loading.scss';
import type { EffectName, EffectsManagerInterface } from '../types'; import type { EffectName, EffectsManagerInterface } from '../types';
import { getReleaseVersion } from '../utils/diagnostics'; import { getReleaseVersion } from '../utils/build-info.js';
import './icon'; import './icon';
+41
View File
@@ -0,0 +1,41 @@
declare const __ADVANCED_CAMERA_CARD_RELEASE_VERSION__: string | undefined;
declare const __ADVANCED_CAMERA_CARD_GIT_HASH__: string | undefined;
declare const __ADVANCED_CAMERA_CARD_GIT_DATE__: string | undefined;
declare const __ADVANCED_CAMERA_CARD_BUILD_DATE__: string | undefined;
const DEVELOPMENT_VERSION = 'dev';
/* v8 ignore start: substituted by the build -- @preserve */
const RELEASE_VERSION =
typeof __ADVANCED_CAMERA_CARD_RELEASE_VERSION__ === 'undefined'
? DEVELOPMENT_VERSION
: __ADVANCED_CAMERA_CARD_RELEASE_VERSION__;
const GIT_HASH =
typeof __ADVANCED_CAMERA_CARD_GIT_HASH__ === 'undefined'
? undefined
: __ADVANCED_CAMERA_CARD_GIT_HASH__;
const GIT_DATE =
typeof __ADVANCED_CAMERA_CARD_GIT_DATE__ === 'undefined'
? undefined
: __ADVANCED_CAMERA_CARD_GIT_DATE__;
const BUILD_DATE =
typeof __ADVANCED_CAMERA_CARD_BUILD_DATE__ === 'undefined'
? undefined
: __ADVANCED_CAMERA_CARD_BUILD_DATE__;
/* v8 ignore stop -- @preserve */
export interface GitInfo {
hash?: string;
commitDate?: string;
buildDate?: string;
}
export const getReleaseVersion = (): string => RELEASE_VERSION;
export const getGitInfo = (): GitInfo => ({
hash: GIT_HASH,
commitDate: GIT_DATE,
buildDate: BUILD_DATE,
});
+6 -20
View File
@@ -1,4 +1,3 @@
import pkg from '../../package.json';
import type { IssueKey, IssuePresence } from '../card-controller/issues/types'; import type { IssueKey, IssuePresence } from '../card-controller/issues/types';
import type { RawAdvancedCameraCardConfig } from '../config/types'; import type { RawAdvancedCameraCardConfig } from '../config/types';
import { getIntegrationManifest } from '../ha/integration'; import { getIntegrationManifest } from '../ha/integration';
@@ -7,6 +6,7 @@ import type { DeviceRegistryManager } from '../ha/registry/device';
import type { HomeAssistant } from '../ha/types'; import type { HomeAssistant } from '../ha/types';
import { HASS_WEB_PROXY_DOMAIN } from '../ha/web-proxy'; import { HASS_WEB_PROXY_DOMAIN } from '../ha/web-proxy';
import { getLanguage } from '../localize/localize'; import { getLanguage } from '../localize/localize';
import { getGitInfo, getReleaseVersion } from './build-info';
type FrigateDevices = Record<string, string>; type FrigateDevices = Record<string, string>;
@@ -21,22 +21,6 @@ interface IntegrationDiagnostics {
version?: string; version?: string;
} }
export const getReleaseVersion = (): string => {
const releaseVersion: string = '__ADVANCED_CAMERA_CARD_RELEASE_VERSION__';
/* v8 ignore if: depends on rollup substitution -- @preserve */
if (releaseVersion === 'pkg') {
return pkg.version;
}
/* v8 ignore if: depends on rollup substitution -- @preserve */
if (releaseVersion === 'dev') {
return `dev+${pkg['gitAbbrevHash']}`;
}
return releaseVersion;
};
interface Diagnostics { interface Diagnostics {
card_version: string; card_version: string;
browser: string; browser: string;
@@ -103,6 +87,8 @@ export const getDiagnostics = async (
}); });
}); });
const gitInfo = getGitInfo();
return { return {
card_version: getReleaseVersion(), card_version: getReleaseVersion(),
browser: navigator.userAgent, browser: navigator.userAgent,
@@ -110,9 +96,9 @@ export const getDiagnostics = async (
lang: getLanguage(), lang: getLanguage(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
git: { git: {
...(pkg['gitAbbrevHash'] && { hash: pkg['gitAbbrevHash'] }), ...(gitInfo.hash && { hash: gitInfo.hash }),
...(pkg['buildDate'] && { build_date: pkg['buildDate'] }), ...(gitInfo.buildDate && { build_date: gitInfo.buildDate }),
...(pkg['gitDate'] && { commit_date: pkg['gitDate'] }), ...(gitInfo.commitDate && { commit_date: gitInfo.commitDate }),
}, },
...(hass && { ha_version: hass.config.version }), ...(hass && { ha_version: hass.config.version }),
custom_integrations: { custom_integrations: {
+18
View File
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { getGitInfo, getReleaseVersion } from '../../src/utils/build-info';
// As these are running as tests, the won't be build substitutes so this only
// tests default/fallback values.
describe('getReleaseVersion', () => {
it('should report an unbuilt card as a development one', () => {
expect(getReleaseVersion()).toBe('dev');
});
});
describe('getGitInfo', () => {
it('should report nothing about an unbuilt card', () => {
expect(getGitInfo()).toEqual({});
});
});
+17 -23
View File
@@ -2,31 +2,25 @@ import type { HassConfig } from 'home-assistant-js-websocket';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended'; import { mock } from 'vitest-mock-extended';
import { RELEASE_VERSION_TOKEN } from '../../scripts/release-version.js';
import type { DeviceRegistryManager } from '../../src/ha/registry/device'; import type { DeviceRegistryManager } from '../../src/ha/registry/device';
import { homeAssistantWSRequest } from '../../src/ha/ws-request'; import { homeAssistantWSRequest } from '../../src/ha/ws-request';
import { getLanguage } from '../../src/localize/localize'; import { getLanguage } from '../../src/localize/localize';
import { getDiagnostics, getReleaseVersion } from '../../src/utils/diagnostics.js'; import { getDiagnostics } from '../../src/utils/diagnostics.js';
import { createHASS, createRegistryDevice } from '../test-utils'; import { createHASS, createRegistryDevice } from '../test-utils';
vi.mock('../../package.json', () => ({ vi.mock('../../src/utils/build-info.js', () => ({
default: { getReleaseVersion: () => '1.2.3',
gitAbbrevHash: 'g4cf13b1', getGitInfo: () => ({
buildDate: 'Tue, 19 Sep 2023 04:59:27 GMT', hash: 'g4cf13b1',
gitDate: 'Wed, 6 Sep 2023 21:27:28 -0700', buildDate: '2023-09-19T04:59:27.000Z',
}, commitDate: '2023-09-06T21:27:28-07:00',
}),
})); }));
vi.mock('../../src/ha'); vi.mock('../../src/ha');
vi.mock('../../src/localize/localize.js'); vi.mock('../../src/localize/localize.js');
vi.mock('../../src/ha/registry/device/index.js'); vi.mock('../../src/ha/registry/device/index.js');
vi.mock('../../src/ha/ws-request.js'); vi.mock('../../src/ha/ws-request.js');
describe('getReleaseVersion', () => {
it('should get release version', () => {
expect(getReleaseVersion()).toBe(RELEASE_VERSION_TOKEN);
});
});
describe('getDiagnostics', () => { describe('getDiagnostics', () => {
const now = new Date('2023-10-01T21:53Z'); const now = new Date('2023-10-01T21:53Z');
const hass = createHASS(); const hass = createHASS();
@@ -78,13 +72,13 @@ describe('getDiagnostics', () => {
}), }),
).toEqual({ ).toEqual({
browser: 'AdvancedCameraCardTest/1.0', browser: 'AdvancedCameraCardTest/1.0',
card_version: '__ADVANCED_CAMERA_CARD_RELEASE_VERSION__', card_version: '1.2.3',
config: { config: {
cameras: [{ camera_entity: 'camera.office' }], cameras: [{ camera_entity: 'camera.office' }],
}, },
git: { git: {
build_date: 'Tue, 19 Sep 2023 04:59:27 GMT', build_date: '2023-09-19T04:59:27.000Z',
commit_date: 'Wed, 6 Sep 2023 21:27:28 -0700', commit_date: '2023-09-06T21:27:28-07:00',
hash: 'g4cf13b1', hash: 'g4cf13b1',
}, },
custom_integrations: { custom_integrations: {
@@ -133,10 +127,10 @@ describe('getDiagnostics', () => {
it('should fetch diagnostics without hass or config', async () => { it('should fetch diagnostics without hass or config', async () => {
expect(await getDiagnostics()).toEqual({ expect(await getDiagnostics()).toEqual({
browser: 'AdvancedCameraCardTest/1.0', browser: 'AdvancedCameraCardTest/1.0',
card_version: '__ADVANCED_CAMERA_CARD_RELEASE_VERSION__', card_version: '1.2.3',
git: { git: {
build_date: 'Tue, 19 Sep 2023 04:59:27 GMT', build_date: '2023-09-19T04:59:27.000Z',
commit_date: 'Wed, 6 Sep 2023 21:27:28 -0700', commit_date: '2023-09-06T21:27:28-07:00',
hash: 'g4cf13b1', hash: 'g4cf13b1',
}, },
custom_integrations: { custom_integrations: {
@@ -185,10 +179,10 @@ describe('getDiagnostics', () => {
expect(await getDiagnostics(hass, deviceRegistryManager)).toEqual({ expect(await getDiagnostics(hass, deviceRegistryManager)).toEqual({
browser: 'AdvancedCameraCardTest/1.0', browser: 'AdvancedCameraCardTest/1.0',
card_version: '__ADVANCED_CAMERA_CARD_RELEASE_VERSION__', card_version: '1.2.3',
git: { git: {
build_date: 'Tue, 19 Sep 2023 04:59:27 GMT', build_date: '2023-09-19T04:59:27.000Z',
commit_date: 'Wed, 6 Sep 2023 21:27:28 -0700', commit_date: '2023-09-06T21:27:28-07:00',
hash: 'g4cf13b1', hash: 'g4cf13b1',
}, },
custom_integrations: { custom_integrations: {
+1 -2
View File
@@ -2,7 +2,6 @@ import { playwright } from '@vitest/browser-playwright';
import { defineConfig } from 'vitest/config'; import { defineConfig } from 'vitest/config';
import { getBrowsers, type Browser } from './scripts/browsers.js'; import { getBrowsers, type Browser } from './scripts/browsers.js';
import { releaseVersion } from './scripts/release-version-plugin.js';
import { scssString } from './scripts/scss-string-plugin.js'; import { scssString } from './scripts/scss-string-plugin.js';
import { svgPath } from './scripts/svg-path-plugin.js'; import { svgPath } from './scripts/svg-path-plugin.js';
@@ -14,7 +13,7 @@ export default defineConfig({
// supply the same asset shapes the build's plugins do: an SVG becomes the // supply the same asset shapes the build's plugins do: an SVG becomes the
// `{ path, viewBox }` a custom iconset serves, SCSS the string `unsafeCSS` // `{ path, viewBox }` a custom iconset serves, SCSS the string `unsafeCSS`
// takes. `svgPath` is the build's own plugin, reused unchanged. // takes. `svgPath` is the build's own plugin, reused unchanged.
plugins: [releaseVersion(), scssString(), svgPath()], plugins: [scssString(), svgPath()],
// Where the Mock Service Worker script is served from, which Vite serves at // Where the Mock Service Worker script is served from, which Vite serves at
// the root of the page. Named rather than left at its default of `public/` in // the root of the page. Named rather than left at its default of `public/` in
+1 -49
View File
@@ -1610,17 +1610,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@rollup/plugin-json@npm:^4.1.0":
version: 4.1.0
resolution: "@rollup/plugin-json@npm:4.1.0"
dependencies:
"@rollup/pluginutils": "npm:^3.0.8"
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
checksum: 10c0/9fc4a3ee60929afcb5269ebda602914d1cf5dc020808f85be90c0a5a2ba9ca26136b0284a1935984861f0549a1e1db30fc372906c14425f5da4909f0fd21e5ea
languageName: node
linkType: hard
"@rollup/plugin-json@npm:^6.1.0": "@rollup/plugin-json@npm:^6.1.0":
version: 6.1.0 version: 6.1.0
resolution: "@rollup/plugin-json@npm:6.1.0" resolution: "@rollup/plugin-json@npm:6.1.0"
@@ -1704,19 +1693,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@rollup/pluginutils@npm:^3.0.8":
version: 3.1.0
resolution: "@rollup/pluginutils@npm:3.1.0"
dependencies:
"@types/estree": "npm:0.0.39"
estree-walker: "npm:^1.0.1"
picomatch: "npm:^2.2.2"
peerDependencies:
rollup: ^1.20.0||^2.0.0
checksum: 10c0/7151753160d15ba2b259461a6c25b3932150994ea52dba8fd3144f634c7647c2e56733d986e2c15de67c4d96a9ee7d6278efa6d2e626a7169898fd64adc0f90c
languageName: node
linkType: hard
"@rollup/pluginutils@npm:^5.0.0, @rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": "@rollup/pluginutils@npm:^5.0.0, @rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0":
version: 5.1.0 version: 5.1.0
resolution: "@rollup/pluginutils@npm:5.1.0" resolution: "@rollup/pluginutils@npm:5.1.0"
@@ -2009,13 +1985,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/estree@npm:0.0.39":
version: 0.0.39
resolution: "@types/estree@npm:0.0.39"
checksum: 10c0/f0af6c95ac1988c4827964bd9d3b51d24da442e2188943f6dfcb1e1559103d5d024d564b2e9d3f84c53714a02a0a7435c7441138eb63d9af5de4dfc66cdc0d92
languageName: node
linkType: hard
"@types/estree@npm:^1.0.6": "@types/estree@npm:^1.0.6":
version: 1.0.7 version: 1.0.7
resolution: "@types/estree@npm:1.0.7" resolution: "@types/estree@npm:1.0.7"
@@ -2547,7 +2516,6 @@ __metadata:
propagating-hammerjs: "npm:^2.0.1" propagating-hammerjs: "npm:^2.0.1"
quick-lru: "npm:^6.1.2" quick-lru: "npm:^6.1.2"
rollup: "npm:^3.29.4" rollup: "npm:^3.29.4"
rollup-plugin-git-info: "npm:^1.0.0"
rollup-plugin-serve: "npm:^1.1.1" rollup-plugin-serve: "npm:^1.1.1"
rollup-plugin-styler: "npm:^1.8.0" rollup-plugin-styler: "npm:^1.8.0"
rollup-plugin-visualizer: "npm:^5.12.0" rollup-plugin-visualizer: "npm:^5.12.0"
@@ -4415,13 +4383,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"estree-walker@npm:^1.0.1":
version: 1.0.1
resolution: "estree-walker@npm:1.0.1"
checksum: 10c0/fa9e5f8c1bbe8d01e314c0f03067b64a4f22d4c58410fc5237060d0c15b81e58c23921c41acc60abbdab490f1fdfcbd6408ede2d03ca704454272e0244d61a55
languageName: node
linkType: hard
"estree-walker@npm:^2.0.2": "estree-walker@npm:^2.0.2":
version: 2.0.2 version: 2.0.2
resolution: "estree-walker@npm:2.0.2" resolution: "estree-walker@npm:2.0.2"
@@ -8221,7 +8182,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1":
version: 2.3.1 version: 2.3.1
resolution: "picomatch@npm:2.3.1" resolution: "picomatch@npm:2.3.1"
checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be
@@ -9188,15 +9149,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"rollup-plugin-git-info@npm:^1.0.0":
version: 1.0.0
resolution: "rollup-plugin-git-info@npm:1.0.0"
dependencies:
"@rollup/plugin-json": "npm:^4.1.0"
checksum: 10c0/d0d6d20d47da9abf6452a76932066d2fb831a33a1f5618f7bc876ad1a290abdcfe5065c761a256f13c433fd98bc6264cfb096cad08d348684399521f6d637724
languageName: node
linkType: hard
"rollup-plugin-serve@npm:^1.1.1": "rollup-plugin-serve@npm:^1.1.1":
version: 1.1.1 version: 1.1.1
resolution: "rollup-plugin-serve@npm:1.1.1" resolution: "rollup-plugin-serve@npm:1.1.1"