unplugin-info
Version:
Export build information as virutal module
396 lines (395 loc) • 12.3 kB
JavaScript
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let node_path = require("node:path");
node_path = __toESM(node_path);
let node_process = require("node:process");
node_process = __toESM(node_process);
let unplugin = require("unplugin");
let ci_info = require("ci-info");
ci_info = __toESM(ci_info);
let simple_git = require("simple-git");
let git_url_parse = require("git-url-parse");
git_url_parse = __toESM(git_url_parse);
let node_fs = require("node:fs");
node_fs = __toESM(node_fs);
//#region src/core/modules/base.ts
var BuildInfoModule = class {
constructor(name, root, options) {
this.name = `${options?.prefix ?? "~build"}/${name}`;
this.root = root;
this.options = options;
}
buildStart(ctx) {}
buildEnd(ctx) {}
};
//#endregion
//#region src/core/modules/time.ts
var BuildTimeModule = class extends BuildInfoModule {
constructor(root, options) {
super("time", root, options);
}
buildStart() {
this.now = this.options.time ? this.options.time : /* @__PURE__ */ new Date();
}
load() {
return `const time = new Date(${this.now.getTime()})\nexport default time`;
}
};
//#endregion
//#region src/core/utils/git.ts
async function getRepoInfo(root, extra = {}) {
const git = (0, simple_git.simpleGit)(root);
if (!await git.checkIsRepo()) return;
const [branch, currentCommit, committer, describe, tags, github, result] = await Promise.all([
getBranch(git),
getCommit(git),
getCommitter(git),
getDescribe(git),
getTags(git),
getGitHubUrl(git),
Promise.all(Object.entries(extra).map(async ([key, fn]) => {
return [key, await fn(git)];
}))
]);
return {
...branch,
...currentCommit,
...committer,
...describe,
...tags,
...github,
...Object.fromEntries(result)
};
}
async function getBranch(git) {
try {
return { branch: (await git.branch([])).current };
} catch (error) {
return { branch: void 0 };
}
}
async function getCommit(git) {
try {
const log = await git.log(["-1"]);
const sha = log.latest?.hash;
const commitMessage = log.latest?.message;
const author = log.latest?.author_name;
const authorEmail = log.latest?.author_email;
const authorDate = log.latest?.date;
return {
sha,
abbreviatedSha: sha?.slice(0, 10),
commitMessage,
author,
authorEmail,
authorDate
};
} catch (error) {
return {
sha: void 0,
abbreviatedSha: void 0,
commitMessage: void 0,
author: void 0,
authorEmail: void 0,
authorDate: void 0
};
}
}
function removeLineBreak(str) {
return str.replace(/[\s\r\n]+$/, "");
}
async function getCommitter(git) {
try {
const [committer, committerEmail, committerDate] = await Promise.all([
git.show(["-s", "--format=%cn"]),
git.show(["-s", "--format=%ce"]),
git.show(["-s", "--format=%cd"])
]);
return {
committer: removeLineBreak(committer),
committerEmail: removeLineBreak(committerEmail),
committerDate: removeLineBreak(committerDate)
};
} catch (error) {
return {
committer: void 0,
committerEmail: void 0,
committerDate: void 0
};
}
}
async function getTags(git) {
try {
const hash = await git.revparse(["HEAD"]);
const tags = await git.tags(["--points-at", hash]);
const all = await git.tags();
return {
tag: tags.all[tags.all.length - 1],
tags: tags.all,
lastTag: all.latest
};
} catch (error) {
return {
tags: void 0,
lastTag: void 0
};
}
}
async function getDescribe(git) {
try {
return { describe: removeLineBreak(await git.raw(["describe", "--always"])) };
} catch (error) {
return { describe: void 0 };
}
}
async function getGitHubUrl(git) {
const url = (await git.getRemotes(true)).find((remote) => remote.name === "origin")?.refs.fetch;
if (url) {
const parsed = (0, git_url_parse.default)(url);
if (parsed.resource === "github.com" && parsed.full_name) return { github: `https://github.com/${parsed.full_name}` };
}
return { github: void 0 };
}
//#endregion
//#region src/core/modules/git.ts
var BuildGitModule = class extends BuildInfoModule {
constructor(root, options) {
super("git", root, options);
}
async load(ctx, id) {
const { root, options } = this;
const info = await getRepoInfo(root, options?.git);
if (info && options?.github) info.github = options.github;
if (!info) ctx.warn("This may not be a git repo");
const keys = [...new Set([
"github",
"sha",
"abbreviatedSha",
"branch",
"tag",
"tags",
"lastTag",
"describe",
"author",
"authorEmail",
"authorDate",
"committer",
"committerEmail",
"committerDate",
"commitMessage",
...Object.keys(options?.git ?? {})
])];
const gen = (key) => {
return `export const ${key} = ${info ? JSON.stringify(info[key]) : "null"}`;
};
return [id.endsWith("info") ? `export const CI = ${ci_info.default.isCI ? `"${ci_info.default.name}"` : "null"}` : ``, ...keys.map((key) => gen(key))].join("\n");
}
};
//#endregion
//#region src/core/modules/info.ts
var LegacyInfoModule = class extends BuildGitModule {
constructor(root, options) {
super(root, options);
this.name = `${options.prefix ?? "~build"}/info`;
}
};
//#endregion
//#region src/core/modules/console.ts
var BuildConsoleModule = class extends BuildInfoModule {
constructor(root, options) {
super("console", root, options);
}
load() {
const { environment = ["development", "production"] } = this.options.console ?? {};
return [
`import time from '~build/time';`,
`import { isCI } from '~build/ci';`,
`import { github } from '~build/git';`,
`import { name, version } from '~build/package';`,
``,
`export const print = () => {`,
` if (!${JSON.stringify(environment)}.includes(process.env.NODE_ENV)) return;`,
` if (typeof import.meta?.env?.SSR !== 'undefined' && import.meta.env.SSR) return;`,
` console.groupCollapsed('~build/console');`,
` console.log('Project:', name);`,
` console.log('Build-at:', time ? time.toLocaleString() : 'Unknown');`,
` console.log('Environment:', \`${process.env.NODE_ENV}\${isCI ? '(ci)' : ''}\`);`,
` console.log('Version:', version);`,
` console.log('GitHub:', github);`,
` console.groupEnd();`,
`};`,
``,
`print();`
].join("\n");
}
};
//#endregion
//#region src/core/modules/ci.ts
var BuildCIModule = class extends BuildInfoModule {
constructor(root, options) {
super("ci", root, options);
}
load() {
return [
`export const isCI = ${ci_info.default.isCI !== null ? ci_info.default.isCI ? "true" : "false" : "null"}`,
`export const isPR = ${ci_info.default.isPR !== null ? ci_info.default.isPR ? "true" : "false" : "null"}`,
`export const name = ${ci_info.default.name !== null ? `\`${ci_info.default.name}\`` : "null"}`
].join("\n");
}
};
//#endregion
//#region src/core/modules/meta.ts
var BuildMetaModule = class extends BuildInfoModule {
constructor(root, options) {
super("meta", root, options);
}
async load() {
const { options } = this;
const get = () => {
if (!options?.meta) return {};
if (typeof options.meta === "function") return options.meta();
return options.meta;
};
const meta = await get();
const body = Object.entries(meta).map(([key, value]) => `export const ${key} = ${JSON.stringify(value, null, 2)};`);
return body.length > 0 ? body.join("\n") : "export {};";
}
};
//#endregion
//#region src/core/modules/env.ts
var BuildEnvModule = class extends BuildInfoModule {
constructor(root, options) {
super("env", root, options);
}
async load() {
const { options } = this;
const get = () => {
if (!options?.env) return {};
if (typeof options.env === "function") return options.env();
return options.env;
};
const cloudflare = options.cloudflare === true;
const meta = await get();
const body = Object.entries(meta).map(([key, value]) => !cloudflare ? `export const ${key} = (typeof import.meta?.env?.SSR !== 'undefined' && import.meta.env.SSR ? process?.env?.['${key.replace(/'/g, "\\\\")}'] : undefined) ?? ${JSON.stringify(value, null, 2)};` : `export const ${key} = ${JSON.stringify(value, null, 2)};`);
return body.length > 0 ? body.join("\n") : "export {};";
}
};
//#endregion
//#region src/core/modules/package.ts
var BuildPackageModule = class extends BuildInfoModule {
constructor(root, options) {
super("package", root, options);
}
load() {
const { root, options } = this;
const pkg = JSON.parse(node_fs.default.readFileSync(node_path.default.join(root, "package.json"), "utf-8"));
const defaults = [
"name",
"version",
"description",
"keywords",
"license",
"author"
];
const keys = new Set(Array.isArray(options?.package) ? [...defaults, ...options.package] : typeof options?.package === "object" ? Object.entries(Object.fromEntries([...defaults.map((d) => [d, true]), ...Object.entries(options.package)])).filter(([k, v]) => !!v).map(([k, v]) => k) : defaults);
const resolved = {
name: "",
version: "0.0.0",
description: "",
keywords: [],
license: "",
author: "",
...pkg
};
return [...keys].map((key) => [key, resolved[key]]).map(([key, value]) => `export const ${key} = ${JSON.stringify(value, null, 2)};`).join("\n");
}
};
//#endregion
//#region src/core/index.ts
const UnpluginInfo = /* @__PURE__ */ (0, unplugin.createUnplugin)((options = {}, meta) => {
const root = node_path.default.resolve(options?.root ?? node_process.default.cwd());
const modules = {
Time: new BuildTimeModule(root, options),
Git: new BuildGitModule(root, options),
CI: new BuildCIModule(root, options),
Info: new LegacyInfoModule(root, options),
Console: new BuildConsoleModule(root, options),
Meta: new BuildMetaModule(root, options),
Env: new BuildEnvModule(root, options),
Package: new BuildPackageModule(root, options)
};
return {
name: "unplugin-info",
async buildStart() {
await Promise.all(Object.values(modules).map((mod) => mod.buildStart(this)));
},
async buildEnd() {
await Promise.all(Object.values(modules).map((mod) => mod.buildEnd(this)));
},
resolveId(id) {
if (Object.values(modules).map((m) => m.name).includes(id)) return `\0${id}`;
},
loadInclude(id) {
if (!id.startsWith("\0")) return false;
id = id.slice(1);
return Object.values(modules).map((m) => m.name).includes(id);
},
async load(id) {
if (!id.startsWith("\0")) return;
id = id.slice(1);
for (const mod of Object.values(modules)) if (id === mod.name) {
if (id === modules.Info.name) this.warn(`${modules.Info.name} is deprecated, please migrate to ${modules.Git.name} and ${modules.CI.name}.`);
if (id === modules.Env.name && meta.framework !== "vite") {
this.warn(`${modules.Env.name} is only supported in Vite.`);
return;
}
return mod.load(this, id);
}
},
vite: { handleHotUpdate({ file, server }) {
if (file === normalizePath(node_path.default.resolve(root, "package.json"))) {
const module = server.moduleGraph.getModuleById("\0" + modules.Package.name);
if (module) {
server.moduleGraph.invalidateModule(module);
server.ws.send({ type: "full-reload" });
}
}
} }
};
});
function normalizePath(filename) {
return filename.split(node_path.default.win32.sep).join(node_path.default.posix.sep);
}
//#endregion
Object.defineProperty(exports, "UnpluginInfo", {
enumerable: true,
get: function() {
return UnpluginInfo;
}
});
Object.defineProperty(exports, "__toESM", {
enumerable: true,
get: function() {
return __toESM;
}
});