firebase-tools
Version:
Command-Line Interface for Firebase
172 lines (171 loc) • 7.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getKitPackage = getKitPackage;
exports.getInstanceId = getInstanceId;
exports.getExtensionRef = getExtensionRef;
exports.formatExtensionsTable = formatExtensionsTable;
exports.getMigratableInstances = getMigratableInstances;
exports.promptInstanceSelection = promptInstanceSelection;
exports.createMigrationPlan = createMigrationPlan;
const clc = require("colorette");
const Table = require("cli-table3");
const error_1 = require("../error");
const logger_1 = require("../logger");
const utils_1 = require("../utils");
const extensionsHelper_1 = require("./extensionsHelper");
const extensionsApi_1 = require("./extensionsApi");
const prompt_1 = require("../prompt");
const replacements = require("./replacements.json");
function getKitPackage(extensionRef, packageOverride) {
if (packageOverride) {
return packageOverride;
}
const data = replacements;
const map = data.replacements || {};
let entry = map[extensionRef];
if (!entry && !extensionRef.includes("/")) {
entry = map[`firebase/${extensionRef}`];
}
if (entry && entry.npmPackage && entry.status === "REPLACEMENT_AVAILABLE") {
return entry.npmPackage;
}
return undefined;
}
function getInstanceId(instance) {
return (0, utils_1.last)(instance.name.split("/")) ?? instance.name;
}
function getExtensionRef(instance) {
return instance.config.extensionRef || instance.config.source?.spec?.name || "";
}
function formatExtensionsTable(instances, packageOverride) {
const table = new Table({
head: ["Extension", "publisher", "Instances", "kit package"],
style: { head: ["yellow"] },
});
const grouped = new Map();
instances.forEach((instance) => {
const ref = getExtensionRef(instance);
const instanceId = getInstanceId(instance);
let publisher = "N/A";
if (ref.includes("/")) {
publisher = ref.split("/")[0];
}
const kitPkg = getKitPackage(ref, packageOverride) ?? "N/A";
const groupEntry = grouped.get(ref);
if (!groupEntry) {
grouped.set(ref, { publisher, instances: [instanceId], kitPackage: kitPkg });
}
else {
groupEntry.instances.push(instanceId);
}
});
const rows = [];
grouped.forEach((data, ref) => {
table.push([ref, data.publisher, data.instances.join(", "), data.kitPackage]);
rows.push({
extension: ref,
publisher: data.publisher,
instances: data.instances,
kitPackage: data.kitPackage,
});
});
return { tableString: table.toString(), rows };
}
function getMigratableInstances(instances, packageOverride) {
const result = [];
for (const instance of instances) {
const ref = getExtensionRef(instance);
const instanceId = getInstanceId(instance);
const kitPkg = getKitPackage(ref, packageOverride);
if (kitPkg) {
result.push({
instance,
instanceId,
extensionRef: ref,
kitPackage: kitPkg,
});
}
}
return result;
}
async function promptInstanceSelection(migratableInstances, nonInteractive) {
const choices = migratableInstances.map((item) => ({
name: `${item.instanceId} (${item.extensionRef})`,
value: item,
}));
const selected = await (0, prompt_1.select)({
message: "Which extension instance would you like to migrate?",
choices,
nonInteractive,
});
return selected;
}
async function createMigrationPlan(projectId, options) {
const instances = await (0, extensionsApi_1.listInstances)(projectId);
if (options.extInstance) {
const foundInstance = instances.find((inst) => getInstanceId(inst) === options.extInstance);
if (!foundInstance) {
throw new error_1.FirebaseError(`Extension instance ${options.extInstance} was not found on project ${projectId}.`);
}
const ref = getExtensionRef(foundInstance);
const kitPkg = getKitPackage(ref, options.package);
if (!kitPkg) {
throw new error_1.FirebaseError("This extension does not have an associated function kit. You can create your own function kit by forking the extension.");
}
return {
instance: foundInstance,
instanceId: getInstanceId(foundInstance),
extensionRef: ref,
kitPackage: kitPkg,
};
}
if (options.extension) {
const targetExt = options.extension;
const matchingInstances = instances.filter((inst) => {
const ref = getExtensionRef(inst);
return (ref === targetExt ||
(ref.includes("/") && ref.split("/")[1] === targetExt) ||
(targetExt.includes("/") && ref === targetExt.split("/")[1]));
});
if (matchingInstances.length === 0) {
throw new error_1.FirebaseError(`Extension ${options.extension} is not installed on project ${projectId}.`);
}
const matchingInstancesWithKit = matchingInstances
.map((inst) => {
const ref = getExtensionRef(inst);
const kitPkg = getKitPackage(ref, options.package);
return { inst, ref, kitPkg };
})
.filter((item) => item.kitPkg !== undefined);
if (matchingInstancesWithKit.length === 0) {
throw new error_1.FirebaseError("This extension does not have an associated function kit. You can create your own function kit by forking the extension.");
}
if (matchingInstancesWithKit.length === 1) {
const { inst, ref, kitPkg } = matchingInstancesWithKit[0];
return {
instance: inst,
instanceId: getInstanceId(inst),
extensionRef: ref,
kitPackage: kitPkg,
};
}
const migratableChoices = matchingInstancesWithKit.map(({ inst, ref, kitPkg }) => ({
instance: inst,
instanceId: getInstanceId(inst),
extensionRef: ref,
kitPackage: kitPkg,
}));
return promptInstanceSelection(migratableChoices, options.nonInteractive);
}
if (instances.length === 0) {
throw new error_1.FirebaseError(`All extensions in project ${clc.bold(projectId)} have already been migrated.`);
}
const { tableString } = formatExtensionsTable(instances, options.package);
(0, utils_1.logLabeledBullet)(extensionsHelper_1.logPrefix, `list of extensions installed in ${clc.bold(projectId)}:`);
logger_1.logger.info(tableString);
const migratable = getMigratableInstances(instances, options.package);
if (migratable.length === 0) {
throw new error_1.FirebaseError("No remaining Extensions have an associated function kit. You can create your own function kit by forking the extension.");
}
return promptInstanceSelection(migratable, options.nonInteractive);
}