Ei kuvausta
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.

command.js 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.validateProjectId = exports.Command = void 0;
  4. const clc = require("colorette");
  5. const lodash_1 = require("lodash");
  6. const error_1 = require("./error");
  7. const utils_1 = require("./utils");
  8. const rc_1 = require("./rc");
  9. const config_1 = require("./config");
  10. const configstore_1 = require("./configstore");
  11. const detectProjectRoot_1 = require("./detectProjectRoot");
  12. const track_1 = require("./track");
  13. const auth_1 = require("./auth");
  14. const projects_1 = require("./management/projects");
  15. const requireAuth_1 = require("./requireAuth");
  16. class Command {
  17. constructor(cmd) {
  18. this.cmd = cmd;
  19. this.name = "";
  20. this.descriptionText = "";
  21. this.options = [];
  22. this.actionFn = () => {
  23. };
  24. this.befores = [];
  25. this.helpText = "";
  26. this.positionalArgs = [];
  27. this.name = (0, lodash_1.first)(cmd.split(" ")) || "";
  28. }
  29. description(t) {
  30. this.descriptionText = t;
  31. return this;
  32. }
  33. option(...args) {
  34. this.options.push(args);
  35. return this;
  36. }
  37. withForce(message) {
  38. this.options.push(["-f, --force", message || "automatically accept all interactive prompts"]);
  39. return this;
  40. }
  41. before(fn, ...args) {
  42. this.befores.push({ fn: fn, args: args });
  43. return this;
  44. }
  45. help(t) {
  46. this.helpText = t;
  47. return this;
  48. }
  49. action(fn) {
  50. this.actionFn = fn;
  51. return this;
  52. }
  53. register(client) {
  54. this.client = client;
  55. const program = client.cli;
  56. const cmd = program.command(this.cmd);
  57. if (this.descriptionText) {
  58. cmd.description(this.descriptionText);
  59. }
  60. this.options.forEach((args) => {
  61. const flags = args.shift();
  62. cmd.option(flags, ...args);
  63. });
  64. if (this.helpText) {
  65. cmd.on("--help", () => {
  66. console.log();
  67. console.log(this.helpText);
  68. });
  69. }
  70. this.positionalArgs = cmd._args;
  71. cmd.action((...args) => {
  72. const runner = this.runner();
  73. const start = process.uptime();
  74. const options = (0, lodash_1.last)(args);
  75. if (args.length - 1 > cmd._args.length) {
  76. client.errorOut(new error_1.FirebaseError(`Too many arguments. Run ${clc.bold("firebase help " + this.name)} for usage instructions`, { exit: 1 }));
  77. return;
  78. }
  79. const isEmulator = this.name.includes("emulator") || this.name === "serve";
  80. if (isEmulator) {
  81. void (0, track_1.trackEmulator)("command_start", { command_name: this.name });
  82. }
  83. runner(...args)
  84. .then(async (result) => {
  85. if ((0, utils_1.getInheritedOption)(options, "json")) {
  86. console.log(JSON.stringify({
  87. status: "success",
  88. result: result,
  89. }, null, 2));
  90. }
  91. const duration = Math.floor((process.uptime() - start) * 1000);
  92. const trackSuccess = (0, track_1.track)(this.name, "success", duration);
  93. if (!isEmulator) {
  94. await (0, utils_1.withTimeout)(5000, trackSuccess);
  95. }
  96. else {
  97. await (0, utils_1.withTimeout)(5000, Promise.all([
  98. trackSuccess,
  99. (0, track_1.trackEmulator)("command_success", {
  100. command_name: this.name,
  101. duration,
  102. }),
  103. ]));
  104. }
  105. process.exit();
  106. })
  107. .catch(async (err) => {
  108. if ((0, utils_1.getInheritedOption)(options, "json")) {
  109. console.log(JSON.stringify({
  110. status: "error",
  111. error: err.message,
  112. }, null, 2));
  113. }
  114. const duration = Math.floor((process.uptime() - start) * 1000);
  115. await (0, utils_1.withTimeout)(5000, Promise.all([
  116. (0, track_1.track)(this.name, "error", duration),
  117. (0, track_1.track)(err.exit === 1 ? "Error (User)" : "Error (Unexpected)", "", duration),
  118. isEmulator
  119. ? (0, track_1.trackEmulator)("command_error", {
  120. command_name: this.name,
  121. duration,
  122. error_type: err.exit === 1 ? "user" : "unexpected",
  123. })
  124. : Promise.resolve(),
  125. ]));
  126. client.errorOut(err);
  127. });
  128. });
  129. }
  130. async prepare(options) {
  131. options = options || {};
  132. options.project = (0, utils_1.getInheritedOption)(options, "project");
  133. if (!process.stdin.isTTY || (0, utils_1.getInheritedOption)(options, "nonInteractive")) {
  134. options.nonInteractive = true;
  135. }
  136. if ((0, utils_1.getInheritedOption)(options, "interactive")) {
  137. options.interactive = true;
  138. options.nonInteractive = false;
  139. }
  140. if ((0, utils_1.getInheritedOption)(options, "debug")) {
  141. options.debug = true;
  142. }
  143. if ((0, utils_1.getInheritedOption)(options, "json")) {
  144. options.nonInteractive = true;
  145. }
  146. else {
  147. (0, utils_1.setupLoggers)();
  148. }
  149. if ((0, utils_1.getInheritedOption)(options, "config")) {
  150. options.configPath = (0, utils_1.getInheritedOption)(options, "config");
  151. }
  152. try {
  153. options.config = config_1.Config.load(options);
  154. }
  155. catch (e) {
  156. options.configError = e;
  157. }
  158. const account = (0, utils_1.getInheritedOption)(options, "account");
  159. options.account = account;
  160. options.projectRoot = (0, detectProjectRoot_1.detectProjectRoot)(options);
  161. const projectRoot = options.projectRoot;
  162. const activeAccount = (0, auth_1.selectAccount)(account, projectRoot);
  163. if (activeAccount) {
  164. (0, auth_1.setActiveAccount)(options, activeAccount);
  165. }
  166. this.applyRC(options);
  167. if (options.project) {
  168. await this.resolveProjectIdentifiers(options);
  169. validateProjectId(options.projectId);
  170. }
  171. }
  172. applyRC(options) {
  173. const rc = (0, rc_1.loadRC)(options);
  174. options.rc = rc;
  175. options.project =
  176. options.project || (configstore_1.configstore.get("activeProjects") || {})[options.projectRoot];
  177. if (options.config && !options.project) {
  178. options.project = options.config.defaults.project;
  179. }
  180. const aliases = rc.projects;
  181. const rcProject = (0, lodash_1.get)(aliases, options.project);
  182. if (rcProject) {
  183. options.projectAlias = options.project;
  184. options.project = rcProject;
  185. }
  186. else if (!options.project && (0, lodash_1.size)(aliases) === 1) {
  187. options.projectAlias = (0, lodash_1.head)((0, lodash_1.keys)(aliases));
  188. options.project = (0, lodash_1.head)((0, lodash_1.values)(aliases));
  189. }
  190. }
  191. async resolveProjectIdentifiers(options) {
  192. var _a;
  193. if ((_a = options.project) === null || _a === void 0 ? void 0 : _a.match(/^\d+$/)) {
  194. await (0, requireAuth_1.requireAuth)(options);
  195. const { projectId, projectNumber } = await (0, projects_1.getFirebaseProject)(options.project);
  196. options.projectId = projectId;
  197. options.projectNumber = projectNumber;
  198. }
  199. else {
  200. options.projectId = options.project;
  201. }
  202. }
  203. runner() {
  204. return async (...args) => {
  205. if (typeof (0, lodash_1.last)(args) !== "object" || (0, lodash_1.last)(args) === null) {
  206. args.push({});
  207. }
  208. while (args.length < this.positionalArgs.length + 1) {
  209. args.splice(args.length - 1, 0, "");
  210. }
  211. const options = (0, lodash_1.last)(args);
  212. await this.prepare(options);
  213. for (const before of this.befores) {
  214. await before.fn(options, ...before.args);
  215. }
  216. return this.actionFn(...args);
  217. };
  218. }
  219. }
  220. exports.Command = Command;
  221. const PROJECT_ID_REGEX = /^(?:[^:]+:)?[a-z0-9-]+$/;
  222. function validateProjectId(project) {
  223. if (PROJECT_ID_REGEX.test(project)) {
  224. return;
  225. }
  226. (0, track_1.track)("Project ID Check", "invalid");
  227. const invalidMessage = "Invalid project id: " + clc.bold(project) + ".";
  228. if (project.toLowerCase() !== project) {
  229. throw new error_1.FirebaseError(invalidMessage + "\nNote: Project id must be all lowercase.");
  230. }
  231. else {
  232. throw new error_1.FirebaseError(invalidMessage);
  233. }
  234. }
  235. exports.validateProjectId = validateProjectId;