123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.Config = void 0;
- const _ = require("lodash");
- const clc = require("colorette");
- const fs = require("fs-extra");
- const path = require("path");
- const cjson = require("cjson");
- const detectProjectRoot_1 = require("./detectProjectRoot");
- const error_1 = require("./error");
- const fsutils = require("./fsutils");
- const prompt_1 = require("./prompt");
- const projectPath_1 = require("./projectPath");
- const utils = require("./utils");
- const firebaseConfigValidate_1 = require("./firebaseConfigValidate");
- const logger_1 = require("./logger");
- const loadCJSON_1 = require("./loadCJSON");
- const parseBoltRules = require("./parseBoltRules");
- class Config {
- constructor(src, options = {}) {
- var _a;
- this.data = {};
- this.defaults = {};
- this.notes = {};
- this.options = options;
- this.projectDir = this.options.projectDir || (0, detectProjectRoot_1.detectProjectRoot)(this.options);
- this._src = src;
- if (this._src.firebase) {
- this.defaults.project = this._src.firebase;
- utils.logWarning(clc.bold('"firebase"') +
- " key in firebase.json is deprecated. Run " +
- clc.bold("firebase use --add") +
- " instead");
- }
- if ((_a = this._src) === null || _a === void 0 ? void 0 : _a.rules) {
- this._src.database = Object.assign(Object.assign({}, this._src.database), { rules: this._src.rules });
- }
- Config.MATERIALIZE_TARGETS.forEach((target) => {
- if (_.get(this._src, target)) {
- _.set(this.data, target, this.materialize(target));
- }
- });
- if (this.projectDir && fsutils.dirExistsSync(this.path(Config.DEFAULT_FUNCTIONS_SOURCE))) {
- if (Array.isArray(this.get("functions"))) {
- if (!this.get("functions.[0].source")) {
- this.set("functions.[0].source", Config.DEFAULT_FUNCTIONS_SOURCE);
- }
- }
- else {
- if (!this.get("functions.source")) {
- this.set("functions.source", Config.DEFAULT_FUNCTIONS_SOURCE);
- }
- }
- }
- }
- materialize(target) {
- const val = _.get(this._src, target);
- if (typeof val === "string") {
- let out = this.parseFile(target, val);
- const segments = target.split(".");
- const lastSegment = segments[segments.length - 1];
- if (Object.keys(out).length === 1 && out[lastSegment]) {
- out = out[lastSegment];
- }
- return out;
- }
- else if (val !== null && typeof val === "object") {
- return val;
- }
- throw new error_1.FirebaseError('Parse Error: "' + target + '" must be object or import path', {
- exit: 1,
- });
- }
- parseFile(target, filePath) {
- const fullPath = (0, projectPath_1.resolveProjectPath)(this.options, filePath);
- const ext = path.extname(filePath);
- if (!fsutils.fileExistsSync(fullPath)) {
- throw new error_1.FirebaseError("Parse Error: Imported file " + filePath + " does not exist", {
- exit: 1,
- });
- }
- switch (ext) {
- case ".json":
- if (target === "database") {
- this.notes.databaseRules = "json";
- }
- else if (target === "database.rules") {
- this.notes.databaseRulesFile = filePath;
- try {
- return fs.readFileSync(fullPath, "utf8");
- }
- catch (e) {
- if (e.code === "ENOENT") {
- throw new error_1.FirebaseError(`File not found: ${fullPath}`, { original: e });
- }
- throw e;
- }
- }
- return (0, loadCJSON_1.loadCJSON)(fullPath);
- case ".bolt":
- if (target === "database") {
- this.notes.databaseRules = "bolt";
- }
- return parseBoltRules(fullPath);
- default:
- throw new error_1.FirebaseError("Parse Error: " + filePath + " is not of a supported config file type", { exit: 1 });
- }
- }
- get src() {
- return this._src;
- }
- get(key, fallback) {
- return _.get(this.data, key, fallback);
- }
- set(key, value) {
- _.set(this._src, key, value);
- return _.set(this.data, key, value);
- }
- has(key) {
- return _.has(this.data, key);
- }
- path(pathName) {
- const outPath = path.normalize(path.join(this.projectDir, pathName));
- if (path.relative(this.projectDir, outPath).includes("..")) {
- throw new error_1.FirebaseError(clc.bold(pathName) + " is outside of project directory", { exit: 1 });
- }
- return outPath;
- }
- readProjectFile(p, options = {}) {
- options = options || {};
- try {
- const content = fs.readFileSync(this.path(p), "utf8");
- if (options.json) {
- return JSON.parse(content);
- }
- return content;
- }
- catch (e) {
- if (options.fallback) {
- return options.fallback;
- }
- if (e.code === "ENOENT") {
- throw new error_1.FirebaseError(`File not found: ${this.path(p)}`, { original: e });
- }
- throw e;
- }
- }
- writeProjectFile(p, content) {
- if (typeof content !== "string") {
- content = JSON.stringify(content, null, 2) + "\n";
- }
- fs.ensureFileSync(this.path(p));
- fs.writeFileSync(this.path(p), content, "utf8");
- }
- projectFileExists(p) {
- return fs.existsSync(this.path(p));
- }
- deleteProjectFile(p) {
- fs.removeSync(this.path(p));
- }
- askWriteProjectFile(p, content, force) {
- const writeTo = this.path(p);
- let next;
- if (fsutils.fileExistsSync(writeTo) && !force) {
- next = (0, prompt_1.promptOnce)({
- type: "confirm",
- message: "File " + clc.underline(p) + " already exists. Overwrite?",
- default: false,
- });
- }
- else {
- next = Promise.resolve(true);
- }
- return next.then((result) => {
- if (result) {
- this.writeProjectFile(p, content);
- utils.logSuccess("Wrote " + clc.bold(p));
- }
- else {
- utils.logBullet("Skipping write of " + clc.bold(p));
- }
- });
- }
- static load(options, allowMissing) {
- const pd = (0, detectProjectRoot_1.detectProjectRoot)(options);
- const filename = options.configPath || Config.FILENAME;
- if (pd) {
- try {
- const filePath = path.resolve(pd, path.basename(filename));
- const data = cjson.load(filePath);
- const validator = (0, firebaseConfigValidate_1.getValidator)();
- const valid = validator(data);
- if (!valid && validator.errors) {
- for (const e of validator.errors) {
- logger_1.logger.debug((0, firebaseConfigValidate_1.getErrorMessage)(e));
- }
- }
- return new Config(data, options);
- }
- catch (e) {
- throw new error_1.FirebaseError(`There was an error loading ${filename}:\n\n` + e.message, {
- exit: 1,
- });
- }
- }
- if (allowMissing) {
- return null;
- }
- throw new error_1.FirebaseError("Not in a Firebase app directory (could not locate firebase.json)", {
- exit: 1,
- });
- }
- }
- exports.Config = Config;
- Config.DEFAULT_FUNCTIONS_SOURCE = "functions";
- Config.FILENAME = "firebase.json";
- Config.MATERIALIZE_TARGETS = [
- "database",
- "emulators",
- "extensions",
- "firestore",
- "functions",
- "hosting",
- "storage",
- "remoteconfig",
- ];
|