forked from dienianindya/gsi_ess_mobile
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.
226 lines
8.1 KiB
226 lines
8.1 KiB
"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",
|
|
];
|