You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
8.4 KiB
193 lines
8.4 KiB
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.hostingConfig = exports.normalize = exports.resolveTargets = exports.validate = exports.extract = exports.filterExcept = exports.filterOnly = void 0;
|
|
const colorette_1 = require("colorette");
|
|
const utils_1 = require("../utils");
|
|
const error_1 = require("../error");
|
|
const functional_1 = require("../functional");
|
|
const fsutils_1 = require("../fsutils");
|
|
const projectPath_1 = require("../projectPath");
|
|
const path = require("node:path");
|
|
const experiments = require("../experiments");
|
|
const logger_1 = require("../logger");
|
|
function matchingConfigs(configs, targets, assertMatches) {
|
|
const matches = [];
|
|
const [hasSite, hasTarget] = (0, functional_1.partition)(configs, (c) => "site" in c);
|
|
for (const target of targets) {
|
|
const siteMatch = hasSite.find((c) => c.site === target);
|
|
const targetMatch = hasTarget.find((c) => c.target === target);
|
|
if (siteMatch) {
|
|
matches.push(siteMatch);
|
|
}
|
|
else if (targetMatch) {
|
|
matches.push(targetMatch);
|
|
}
|
|
else if (assertMatches) {
|
|
throw new error_1.FirebaseError(`Hosting site or target ${(0, colorette_1.bold)(target)} not detected in firebase.json`);
|
|
}
|
|
}
|
|
return matches;
|
|
}
|
|
function filterOnly(configs, onlyString) {
|
|
if (!onlyString) {
|
|
return configs;
|
|
}
|
|
let onlyTargets = onlyString.split(",");
|
|
if (onlyTargets.includes("hosting")) {
|
|
return configs;
|
|
}
|
|
onlyTargets = onlyTargets
|
|
.filter((target) => target.startsWith("hosting:"))
|
|
.map((target) => target.replace("hosting:", ""));
|
|
return matchingConfigs(configs, onlyTargets, true);
|
|
}
|
|
exports.filterOnly = filterOnly;
|
|
function filterExcept(configs, exceptOption) {
|
|
if (!exceptOption) {
|
|
return configs;
|
|
}
|
|
const exceptTargets = exceptOption.split(",");
|
|
if (exceptTargets.includes("hosting")) {
|
|
return [];
|
|
}
|
|
const exceptValues = exceptTargets
|
|
.filter((t) => t.startsWith("hosting:"))
|
|
.map((t) => t.replace("hosting:", ""));
|
|
const toReject = matchingConfigs(configs, exceptValues, false);
|
|
return configs.filter((c) => !toReject.find((r) => c.site === r.site && c.target === r.target));
|
|
}
|
|
exports.filterExcept = filterExcept;
|
|
function extract(options) {
|
|
const config = options.config.src;
|
|
if (!config.hosting) {
|
|
return [];
|
|
}
|
|
const assertOneTarget = (config) => {
|
|
if (config.target && config.site) {
|
|
throw new error_1.FirebaseError(`Hosting configs should only include either "site" or "target", not both.`);
|
|
}
|
|
};
|
|
if (!Array.isArray(config.hosting)) {
|
|
const res = (0, utils_1.cloneDeep)(config.hosting);
|
|
if (!res.target && !res.site) {
|
|
res.site = options.site;
|
|
}
|
|
assertOneTarget(res);
|
|
return [res];
|
|
}
|
|
else {
|
|
config.hosting.forEach(assertOneTarget);
|
|
return (0, utils_1.cloneDeep)(config.hosting);
|
|
}
|
|
}
|
|
exports.extract = extract;
|
|
function validate(configs, options) {
|
|
for (const config of configs) {
|
|
validateOne(config, options);
|
|
}
|
|
}
|
|
exports.validate = validate;
|
|
function validateOne(config, options) {
|
|
var _a, _b, _c, _d;
|
|
const hasAnyStaticRewrites = !!((_a = config.rewrites) === null || _a === void 0 ? void 0 : _a.find((rw) => "destination" in rw));
|
|
const hasAnyDynamicRewrites = !!((_b = config.rewrites) === null || _b === void 0 ? void 0 : _b.find((rw) => !("destination" in rw)));
|
|
const hasAnyRedirects = !!((_c = config.redirects) === null || _c === void 0 ? void 0 : _c.length);
|
|
if (config.source && config.public) {
|
|
throw new error_1.FirebaseError('Can only specify "source" or "public" in a Hosting config, not both');
|
|
}
|
|
const root = experiments.isEnabled("webframeworks")
|
|
? config.source || config.public
|
|
: config.public;
|
|
const orSource = experiments.isEnabled("webframeworks") ? ' or "source"' : "";
|
|
if (!root && hasAnyStaticRewrites) {
|
|
throw new error_1.FirebaseError(`Must supply a "public"${orSource} directory when using "destination" rewrites.`);
|
|
}
|
|
if (!root && !hasAnyDynamicRewrites && !hasAnyRedirects) {
|
|
throw new error_1.FirebaseError(`Must supply a "public"${orSource} directory or at least one rewrite or redirect in each "hosting" config.`);
|
|
}
|
|
if (root && !(0, fsutils_1.dirExistsSync)((0, projectPath_1.resolveProjectPath)(options, root))) {
|
|
logger_1.logger.debug(`Specified "${config.source ? "source" : "public"}" directory "${root}" does not exist; Deploy to Hosting site "${config.site || config.target || ""}" may fail or be empty.`);
|
|
}
|
|
const regionWithoutFunction = (rewrite) => typeof rewrite.region === "string" && typeof rewrite.function !== "string";
|
|
const violation = (_d = config.rewrites) === null || _d === void 0 ? void 0 : _d.find(regionWithoutFunction);
|
|
if (violation) {
|
|
throw new error_1.FirebaseError("Rewrites only support 'region' as a top-level field when 'function' is set as a string");
|
|
}
|
|
if (config.i18n) {
|
|
if (!root) {
|
|
throw new error_1.FirebaseError(`Must supply a "public"${orSource} directory when using "i18n" configuration.`);
|
|
}
|
|
if (!config.i18n.root) {
|
|
throw new error_1.FirebaseError('Must supply a "root" in "i18n" config.');
|
|
}
|
|
const i18nPath = path.join(root, config.i18n.root);
|
|
if (!(0, fsutils_1.dirExistsSync)((0, projectPath_1.resolveProjectPath)(options, i18nPath))) {
|
|
(0, utils_1.logLabeledWarning)("hosting", `Couldn't find specified i18n root directory ${(0, colorette_1.bold)(config.i18n.root)} in public directory ${(0, colorette_1.bold)(root)}`);
|
|
}
|
|
}
|
|
}
|
|
function resolveTargets(configs, options) {
|
|
return configs.map((config) => {
|
|
const newConfig = (0, utils_1.cloneDeep)(config);
|
|
if (config.site) {
|
|
return newConfig;
|
|
}
|
|
if (!config.target) {
|
|
throw new error_1.FirebaseError("Assertion failed: resolving hosting target of a site with no site name " +
|
|
"or target name. This should have caused an error earlier", { exit: 2 });
|
|
}
|
|
if (!options.project) {
|
|
throw new error_1.FirebaseError("Assertion failed: options.project is not set. Commands depending on hosting.config should use requireProject", { exit: 2 });
|
|
}
|
|
const matchingTargets = options.rc.requireTarget(options.project, "hosting", config.target);
|
|
if (matchingTargets.length > 1) {
|
|
throw new error_1.FirebaseError(`Hosting target ${(0, colorette_1.bold)(config.target)} is linked to multiple sites, ` +
|
|
`but only one is permitted. ` +
|
|
`To clear, run:\n\n ${(0, colorette_1.bold)(`firebase target:clear hosting ${config.target}`)}`);
|
|
}
|
|
newConfig.site = matchingTargets[0];
|
|
return newConfig;
|
|
});
|
|
}
|
|
exports.resolveTargets = resolveTargets;
|
|
function isLegacyFunctionsRewrite(rewrite) {
|
|
return "function" in rewrite && typeof rewrite.function === "string";
|
|
}
|
|
function normalize(configs) {
|
|
var _a;
|
|
for (const config of configs) {
|
|
config.rewrites = (_a = config.rewrites) === null || _a === void 0 ? void 0 : _a.map((rewrite) => {
|
|
if (!("function" in rewrite)) {
|
|
return rewrite;
|
|
}
|
|
if (isLegacyFunctionsRewrite(rewrite)) {
|
|
const modern = Object.assign(Object.assign({}, rewrite), { function: {
|
|
functionId: rewrite.function,
|
|
} });
|
|
delete modern.region;
|
|
if ("region" in rewrite && typeof rewrite.region === "string") {
|
|
modern.function.region = rewrite.region;
|
|
}
|
|
if (rewrite.region) {
|
|
modern.function.region = rewrite.region;
|
|
}
|
|
return modern;
|
|
}
|
|
return rewrite;
|
|
});
|
|
}
|
|
}
|
|
exports.normalize = normalize;
|
|
function hostingConfig(options) {
|
|
if (!options.normalizedHostingConfig) {
|
|
let configs = extract(options);
|
|
configs = filterOnly(configs, options.only);
|
|
configs = filterExcept(configs, options.except);
|
|
normalize(configs);
|
|
validate(configs, options);
|
|
const resolved = resolveTargets(configs, options);
|
|
options.normalizedHostingConfig = resolved;
|
|
}
|
|
return options.normalizedHostingConfig;
|
|
}
|
|
exports.hostingConfig = hostingConfig;
|