UNPKG

@adonisjs/application

Version:

AdonisJS application class to read app related data

1,589 lines (1,574 loc) 45.1 kB
import { __export, debug_default } from "./chunk-QXFCAPYD.js"; // src/errors.ts var errors_exports = {}; __export(errors_exports, { E_INVALID_PRELOAD_FILE: () => E_INVALID_PRELOAD_FILE, E_INVALID_PROVIDER: () => E_INVALID_PROVIDER, E_MISSING_ASSEMBLER_RUNNER_COMMAND: () => E_MISSING_ASSEMBLER_RUNNER_COMMAND, E_MISSING_ASSEMBLER_RUNNER_NAME: () => E_MISSING_ASSEMBLER_RUNNER_NAME, E_MISSING_BUNDLER_BUILD_COMMAND: () => E_MISSING_BUNDLER_BUILD_COMMAND, E_MISSING_BUNDLER_DEV_COMMAND: () => E_MISSING_BUNDLER_DEV_COMMAND, E_MISSING_BUNDLER_NAME: () => E_MISSING_BUNDLER_NAME, E_MISSING_METAFILE_PATTERN: () => E_MISSING_METAFILE_PATTERN, E_MISSING_PRELOAD_FILE: () => E_MISSING_PRELOAD_FILE, E_MISSING_PROVIDER_FILE: () => E_MISSING_PROVIDER_FILE, E_MISSING_SUITE_FILES: () => E_MISSING_SUITE_FILES, E_MISSING_SUITE_NAME: () => E_MISSING_SUITE_NAME }); import { createError } from "@poppinss/utils"; var E_MISSING_METAFILE_PATTERN = createError( 'Invalid metafile entry "%s". Missing pattern property', "E_MISSING_METAFILE_PATTERN" ); var E_MISSING_PRELOAD_FILE = createError( 'Invalid preload entry "%s". Missing file property', "E_MISSING_PRELOAD_FILE" ); var E_INVALID_PRELOAD_FILE = createError( 'Invalid preload entry "%s". The file property must be a function', "E_INVALID_PRELOAD_FILE" ); var E_MISSING_PROVIDER_FILE = createError( 'Invalid provider entry "%s". Missing file property', "E_MISSING_PROVIDER_FILE" ); var E_INVALID_PROVIDER = createError( 'Invalid provider entry "%s". The file property must be a function', "E_INVALID_PROVIDER" ); var E_MISSING_SUITE_NAME = createError( 'Invalid suite entry "%s". Missing name property', "E_MISSING_SUITE_NAME" ); var E_MISSING_SUITE_FILES = createError( 'Invalid suite entry "%s". Missing files property', "E_MISSING_SUITE_FILES" ); var E_MISSING_BUNDLER_DEV_COMMAND = createError( "Invalid assetsBundler entry. Missing devServer property", "E_MISSING_BUNDLER_DEV_COMMAND" ); var E_MISSING_BUNDLER_BUILD_COMMAND = createError( "Invalid assetsBundler entry. Missing build property", "E_MISSING_BUNDLER_BUILD_COMMAND" ); var E_MISSING_BUNDLER_NAME = createError( "Invalid assetsBundler entry. Missing name property", "E_MISSING_BUNDLER_NAME" ); var E_MISSING_ASSEMBLER_RUNNER_NAME = createError( "Invalid assembler.runner entry. Missing name property", "E_MISSING_ASSEMBLER_RUNNER_NAME" ); var E_MISSING_ASSEMBLER_RUNNER_COMMAND = createError( "Invalid assembler.runner entry. Missing command property", "E_MISSING_ASSEMBLER_RUNNER_COMMAND" ); // src/generators.ts import { slash } from "@poppinss/utils"; import { extname, join } from "node:path"; import string from "@poppinss/utils/string"; import StringBuilder from "@poppinss/utils/string_builder"; var generators = { /** * The given controller names will always be generated * in singular form */ singularControllerNames: [ "home", "admin", "session", "application", "money", "signup", "login", "auth", "authentication", "adonis", "adonisjs", "dashboard", "api", "about", "conatact", "blog" ], /** * Creates the entity path and name from the user * input. */ createEntity(entityName) { entityName = entityName.replace(new RegExp(`${extname(entityName)}$`), ""); const parts = entityName.split("/"); const [name] = parts.splice(-1); if (parts.length) { return { path: parts.join("/"), name }; } return { path: "./", name }; }, /** * Construct paths to make an import path */ importPath(...paths) { return slash(join(...paths)); }, /** * Converts an entity name to database table name */ tableName(entityName) { return new StringBuilder( this.modelName(new StringBuilder(entityName).removeSuffix("table").toString()) ).plural().snakeCase().toString(); }, /** * Converts an entity name to model name */ modelName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("model").singular().pascalCase().toString(); }, /** * Converts an entity name to model file name */ modelFileName(entityName) { return new StringBuilder(this.modelName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to a controller name */ controllerName(entityName, singular = false) { const controller = new StringBuilder(entityName).removeExtension().removeSuffix("controller"); if (this.singularControllerNames.includes(controller.toString().toLowerCase())) { controller.singular(); } else if (singular) { controller.singular(); } else { controller.plural(); } return controller.pascalCase().suffix("Controller").toString(); }, /** * Converts an entity name to a controller file name */ controllerFileName(entityName, singular = false) { return new StringBuilder(this.controllerName(entityName, singular)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to an event name */ eventName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("event").pascalCase().toString(); }, /** * Converts an entity name to an event file name */ eventFileName(entityName) { return new StringBuilder(this.eventName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to listener name */ listenerName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("listener").pascalCase().toString(); }, /** * Converts an entity name to listener file name */ listenerFileName(entityName) { return new StringBuilder(this.listenerName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to middleware name */ middlewareName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("middleware").pascalCase().suffix("Middleware").toString(); }, /** * Converts an entity name to middleware file name */ middlewareFileName(entityName) { return new StringBuilder(this.middlewareName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to provider name */ providerName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("provider").singular().pascalCase().suffix("Provider").toString(); }, /** * Converts an entity name to provider file name */ providerFileName(entityName) { return new StringBuilder(this.providerName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to policy name */ policyName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("policy").removeSuffix("model").singular().pascalCase().suffix("Policy").toString(); }, /** * Converts an entity name to policy file name */ policyFileName(entityName) { return new StringBuilder(this.policyName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to factory name */ factoryName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("factory").removeSuffix("model").singular().pascalCase().suffix("Factory").toString(); }, /** * Converts an entity name to factory file name */ factoryFileName(entityName) { return new StringBuilder(this.factoryName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to service name */ serviceName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("service").removeSuffix("model").singular().pascalCase().suffix("Service").toString(); }, /** * Converts an entity name to service file name */ serviceFileName(entityName) { return new StringBuilder(this.serviceName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to seeder name */ seederName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("seeder").removeSuffix("model").singular().pascalCase().suffix("Seeder").toString(); }, /** * Converts an entity name to seeder file name */ seederFileName(entityName) { return new StringBuilder(this.seederName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to command terminal name */ commandTerminalName(entityName) { const dashCase = new StringBuilder(this.commandName(entityName)).dashCase().toString(); const [namespace, ...rest] = dashCase.split("-"); if (!rest.length) { return namespace; } return `${namespace}:${rest.join("-")}`; }, /** * Converts an entity name to command name */ commandName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("command").pascalCase().toString(); }, /** * Converts an entity name to command file name */ commandFileName(entityName) { return new StringBuilder(this.commandName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to validator name */ validatorName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("validator").singular().pascalCase().toString(); }, /** * Converts an entity name to validator action * name */ validatorActionName(entityName, action) { return new StringBuilder(this.validatorName(entityName)).prefix(`${action}_`).suffix("_validator").camelCase().toString(); }, /** * Converts an entity name to validator file name */ validatorFileName(entityName) { return new StringBuilder(this.validatorName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to exception name */ exceptionName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix("exception").pascalCase().suffix("Exception").toString(); }, /** * Converts an entity name to exception file name */ exceptionFileName(entityName) { return new StringBuilder(this.exceptionName(entityName)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to mailer name */ mailerName(entityName, type = "notification") { return new StringBuilder(entityName).removeExtension().removeSuffix("notification").removeSuffix("provision").removeSuffix("mailer").pascalCase().suffix(string.pascalCase(type)).toString(); }, /** * Converts an entity name to mailer file name */ mailerFileName(entityName, type = "notification") { return new StringBuilder(this.mailerName(entityName, type)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity name to class-based mail name */ mailName(entityName, type = "notification") { return new StringBuilder(entityName).removeExtension().removeSuffix(type).removeSuffix("mailer", { similarWords: ["emailer"] }).removeSuffix("mail", { similarWords: ["email"] }).pascalCase().suffix(string.pascalCase(type)).toString(); }, /** * Converts an entity name to class-name mail filename */ mailFileName(entityName, type = "notification") { return new StringBuilder(this.mailName(entityName, type)).snakeCase().ext(".ts").toString(); }, /** * Converts an entity to test group name */ testGroupName(entity) { return new StringBuilder(`${entity.path}/${entity.name}`).removeExtension().removeSuffix(".spec").sentenceCase().toString(); }, /** * Converts an entity name to test file name */ testFileName(entityName) { return new StringBuilder(entityName).removeExtension().removeSuffix(".spec").snakeCase().ext(".spec.ts").toString(); }, /** * Converts an entity name to the view template file */ viewFileName(entityName) { return new StringBuilder(entityName).removeExtension().snakeCase().ext(".edge").toString(); } }; var generators_default = generators; // src/rc_file/parser.ts import { inspect } from "node:util"; import globParent from "glob-parent"; import { ObjectBuilder } from "@poppinss/utils"; // src/directories.ts var directories = { config: "config", commands: "commands", contracts: "contracts", public: "public", providers: "providers", languageFiles: "resources/lang", migrations: "database/migrations", seeders: "database/seeders", factories: "database/factories", views: "resources/views", start: "start", tmp: "tmp", tests: "tests", httpControllers: "app/controllers", models: "app/models", services: "app/services", exceptions: "app/exceptions", mailers: "app/mailers", mails: "app/mails", middleware: "app/middleware", policies: "app/policies", validators: "app/validators", events: "app/events", listeners: "app/listeners", stubs: "stubs" }; // src/rc_file/parser.ts var RcFileParser = class { /** * Defaults for the RcFile. This object initiates all * the known properties */ #defaults = { typescript: true, preloads: [], metaFiles: [], commandsAliases: {}, commands: [], providers: [], directories, tests: { suites: [], timeout: 2e3, forceExit: true }, raw: {}, experimental: {} }; /** * RcFile merged with defaults */ #rcFile; constructor(rcFile) { this.#rcFile = Object.assign(this.#defaults, rcFile); this.#rcFile.raw = rcFile; } /** * An array of known environments */ #knownEnvironments() { return ["web", "console", "test", "repl"]; } /** * Returns the assets bundler object */ #getAssetsBundler() { if (this.#rcFile.assetsBundler === false) { return false; } if (!this.#rcFile.assetsBundler) { return; } if (!this.#rcFile.assetsBundler.name) { throw new E_MISSING_BUNDLER_NAME(); } if (!this.#rcFile.assetsBundler.devServer) { throw new E_MISSING_BUNDLER_DEV_COMMAND(); } if (!this.#rcFile.assetsBundler.build) { throw new E_MISSING_BUNDLER_BUILD_COMMAND(); } return { name: this.#rcFile.assetsBundler.name, devServer: this.#rcFile.assetsBundler.devServer, build: this.#rcFile.assetsBundler.build }; } /** * Returns the assembler object */ #getHooks() { const hooksProperty = this.#rcFile.hooks || this.#rcFile.unstable_assembler; if (!hooksProperty) { return; } return new ObjectBuilder({}).add("onBuildStarting", hooksProperty.onBuildStarting).add("onBuildCompleted", hooksProperty.onBuildCompleted).add("onDevServerStarted", hooksProperty.onDevServerStarted).add("onSourceFileChanged", hooksProperty.onSourceFileChanged).toObject(); } /** * Returns a normalized array of preload files */ #getPreloads() { return this.#rcFile.preloads.map((preload) => { const normalizedPreload = typeof preload === "function" ? { file: preload, environment: this.#knownEnvironments() } : preload; if (!normalizedPreload.file) { throw new E_MISSING_PRELOAD_FILE([inspect(preload)]); } if (typeof normalizedPreload.file !== "function") { throw new E_INVALID_PRELOAD_FILE([inspect(preload)]); } return { file: normalizedPreload.file, environment: normalizedPreload.environment ?? this.#knownEnvironments() }; }); } /** * Returns a normalized array of providers */ #getProviders() { return this.#rcFile.providers.map((provider) => { const normalizedProvider = typeof provider === "function" ? { file: provider, environment: this.#knownEnvironments() } : provider; if (!normalizedProvider.file) { throw new E_MISSING_PROVIDER_FILE([inspect(provider)]); } if (typeof normalizedProvider.file !== "function") { throw new E_INVALID_PROVIDER([inspect(provider)]); } return { file: normalizedProvider.file, environment: normalizedProvider.environment ?? this.#knownEnvironments() }; }); } /** * Returns a nornalized array of meta files */ #getMetaFiles() { return this.#rcFile.metaFiles.map((pattern) => { const normalizeMetaFile = typeof pattern === "string" ? { pattern, reloadServer: true } : pattern; if (!normalizeMetaFile.pattern) { throw new E_MISSING_METAFILE_PATTERN([inspect(pattern)]); } return { pattern: normalizeMetaFile.pattern, reloadServer: normalizeMetaFile.reloadServer ?? true }; }); } /** * Returns a normalized array of test suites */ #getSuites() { const suites = this.#rcFile.tests.suites || []; return suites.map((suite) => { if (!suite.name) { throw new E_MISSING_SUITE_NAME([inspect(suite)]); } if (!suite.files) { throw new E_MISSING_SUITE_FILES([inspect(suite)]); } const files = Array.isArray(suite.files) ? [...suite.files] : [suite.files]; return { name: suite.name, files, directories: files.map((file) => globParent(file)), timeout: suite.timeout }; }); } /** * Parse and validate file contents and merge them with defaults */ parse() { const assembler = this.#getHooks(); const assetsBundler = this.#getAssetsBundler(); return { typescript: this.#rcFile.typescript, ...assembler ? { hooks: assembler } : {}, ...assetsBundler !== void 0 ? { assetsBundler } : {}, preloads: this.#getPreloads(), metaFiles: this.#getMetaFiles(), commands: [...this.#rcFile.commands], directories: { ...directories, ...this.#rcFile.directories }, commandsAliases: { ...this.#rcFile.commandsAliases }, providers: this.#getProviders(), tests: { suites: this.#getSuites(), timeout: this.#rcFile.tests.timeout ?? 2e3, forceExit: this.#rcFile.tests.forceExit ?? true }, experimental: this.#rcFile.experimental, raw: this.#rcFile.raw }; } }; // src/feature_flags.ts var FeatureFlags = class { #flags; #flagsFactory; constructor(flags) { if (typeof flags === "function") { this.#flagsFactory = flags; } else { this.#flags = flags; } } enabled(feature) { const flags = this.#flags ?? this.#flagsFactory(); return flags[feature] === true; } disabled(feature) { const flags = this.#flags ?? this.#flagsFactory(); return flags[feature] === false; } has(feature) { const flags = this.#flags ?? this.#flagsFactory(); return feature in flags; } when(feature, enabledCallback, disabledCallback) { if (this.enabled(feature)) { return enabledCallback(); } return disabledCallback ? disabledCallback() : void 0; } }; // src/application.ts import Hooks from "@poppinss/hooks"; import { fileURLToPath } from "node:url"; import { join as join2, relative } from "node:path"; import { Container } from "@adonisjs/fold"; import Macroable from "@poppinss/macroable"; import { importDefault, RuntimeException as RuntimeException2 } from "@poppinss/utils"; // src/managers/config.ts import { Config, ConfigLoader } from "@adonisjs/config"; var ConfigManager = class { #appRoot; /** * Config tree set explicitly */ #configValues; /** * Reference to the config class. The value is defined * after the "init" method call */ config; constructor(appRoot) { this.#appRoot = appRoot; } /** * Define the config values to use when booting the * config provider. Calling this method disables * reading files from the config directory. */ useConfig(values) { this.#configValues = values; return this; } /** * Process config values. */ async process(configDirectory) { if (this.#configValues) { this.config = new Config(this.#configValues); } else { const loader = new ConfigLoader(new URL(configDirectory, this.#appRoot)); debug_default('loading config from directory "%s"', configDirectory); this.config = new Config(await loader.load()); } this.#configValues = void 0; } }; // src/managers/rc_file.ts var RcFileManager = class { #appRoot; /** * RcFile contents set explicitly */ #rcContents; /** * Reference to the parsed rc file. The value is defined * after the "init" method call */ rcFile; constructor(appRoot) { this.#appRoot = appRoot; } /** * Specify the contents of the "adonisrc.js" file as * an object. Calling this method will disable loading * the "adonisrc.js" file from the disk. */ rcContents(value) { this.#rcContents = value; return this; } /** * Process the contents for the rcFile */ async process() { if (!this.#rcContents) { const rcTSFile = new URL("adonisrc.js", this.#appRoot); try { const rcExports = await import(rcTSFile.href); this.#rcContents = rcExports.default; debug_default("adonisrc.ts file contents: %O", this.#rcContents); } catch (error) { if (!/Cannot find module/.test(error.message)) { throw error; } } } this.rcFile = new RcFileParser(this.#rcContents).parse(); this.#rcContents = void 0; } }; // src/managers/node_env.ts var TEST_ENVS = ["test", "testing"]; var PROD_ENVS = ["prod", "production"]; var DEV_ENVS = ["dev", "develop", "development"]; var NodeEnvManager = class { nodeEnvironment = "unknown"; /** * Normalizes node env */ #normalizeNodeEnv(env) { if (!env || typeof env !== "string") { return "unknown"; } env = env.toLowerCase(); if (DEV_ENVS.includes(env)) { return "development"; } if (PROD_ENVS.includes(env)) { return "production"; } if (TEST_ENVS.includes(env)) { return "test"; } return env; } /** * Capture the current node env */ process() { this.nodeEnvironment = this.#normalizeNodeEnv(process.env.NODE_ENV); } }; // src/managers/preloads.ts var PreloadsManager = class { /** * List of registered preloads */ #list = []; /** * The options accepted by the manager. */ #options; constructor(options) { this.#options = options; } /** * Filters the preload modules by the current environment. */ #filterByEnvironment(provider) { if (this.#options.environment === "unknown") { return false; } return provider.environment.includes(this.#options.environment); } /** * Pass an array of preload modules to import */ use(list) { this.#list = list; return this; } /** * Switch the environment in which the app is running. */ setEnvironment(environment) { debug_default( 'switching environment for preloads { from:"%s", to: "%s" }', this.#options.environment, environment ); this.#options.environment = environment; return this; } /** * Import preload files */ async import() { const preloads = this.#list.filter((preload) => this.#filterByEnvironment(preload)); debug_default("preloading modules %O", preloads); await Promise.all(preloads.map((preload) => preload.file())); this.#list = []; } }; // src/managers/providers.ts import { RuntimeException } from "@poppinss/utils"; var ProvidersManager = class { /** * An array of collected providers */ #providers = []; /** * An array of providers with the `shutdown` method. We release the * values from the providers array and only keep the once with * shutdown method */ #providersWithShutdownListeners = []; /** * An array of providers modules picked from the ".adonisrc.ts" * file. */ #list = []; /** * The options accepted by the manager */ #options; constructor(options) { this.#options = options; } /** * Filters the providers by the current environment. */ #filterByEnvironment(provider) { if (this.#options.environment === "unknown") { return false; } return provider.environment.includes(this.#options.environment); } /** * Check if value is a class */ #isAClass(providerClass) { return typeof providerClass === "function" && providerClass.toString().startsWith("class "); } /** * Imports all providers from the registered module path. The method relies * on --experimental-import-meta-resolve flag to resolve paths from * the app root. */ async #resolveProvider(provider) { const providerExports = await provider.file(); const exportsLength = Object.keys(providerExports).length; if (exportsLength === 0) { return null; } if (!providerExports.default) { throw new RuntimeException( `Invalid exports from "${provider.file.toString()}" provider. It must have a default export` ); } if (!this.#isAClass(providerExports.default)) { throw new RuntimeException( `Default export from module "${provider.file.toString()}" is not a class` ); } return providerExports.default; } /** * Resolves all providers from the supplied list of module paths. */ #resolve() { const providers = this.#list.filter((provider) => this.#filterByEnvironment(provider)); debug_default("loading providers %O", providers); return Promise.all(providers.map((provider) => this.#resolveProvider(provider))); } /** * Pass an array of providers to use */ use(list) { this.#list = list; return this; } /** * Switch the environment in which the app is running. */ setEnvironment(environment) { debug_default( 'switching environment for providers { from:"%s", to: "%s" }', this.#options.environment, environment ); this.#options.environment = environment; return this; } /** * Invoke register method on the providers. */ async register() { const providers = await this.#resolve(); this.#list = []; providers.forEach((provider) => { if (provider) { const providerInstance = new provider(...this.#options.providersState); this.#providers.push(providerInstance); if (providerInstance.shutdown) { this.#providersWithShutdownListeners.push(providerInstance); } if (providerInstance.register) { providerInstance.register(); } } }); } /** * Invoke boot method on the providers. The existing providers * instances are used. */ async boot() { for (let provider of this.#providers) { if (provider.boot) { await provider.boot(); } } } /** * Invoke start method on all the providers */ async start() { for (let provider of this.#providers) { if (provider.start) { await provider.start(); } } } /** * Invoke ready method on all the providers */ async ready() { for (let provider of this.#providers) { if (provider.ready) { await provider.ready(); } } this.#providers = []; } /** * Invoke shutdown method on all the providers */ async shutdown(inReverseOrder) { const providersWithShutdownListeners = inReverseOrder ? Array.from(this.#providersWithShutdownListeners).reverse() : Array.from(this.#providersWithShutdownListeners); this.#providersWithShutdownListeners = []; for (let provider of providersWithShutdownListeners) { if (provider.shutdown) { await provider.shutdown(); } } } }; // src/application.ts var Application = class extends Macroable { /** * Importer function to import modules from the application * context */ #importer; /** * Flag to know if we have started the termination * process */ #terminating = false; /** * The environment in which the app is running. Currently we track * pm2 only */ #surroundedEnvironment = { pm2: false }; /** * Application root. The path must end with '/' */ #appRoot; /** * Current application environment */ #environment; /** * Current state of the application */ #state = "created"; /** * Managers for sub-features */ #configManager; #rcFileManager; #nodeEnvManager; #preloadsManager; #providersManager; /** * Lifecycle hooks */ #hooks = new Hooks(); /** * Store info metadata about the app. */ info = /* @__PURE__ */ new Map(); /** * Returns the application name from the info map */ get appName() { return this.info.get("appName") || "adonisjs_app"; } /** * Returns the application version from the info map */ get version() { return this.info.get("version") || null; } /** * The parsed version for the "@adonisjs/core" package. */ get adonisVersion() { return this.info.get("adonisVersion") || null; } /** * The URL for the root of the application */ get appRoot() { return this.#appRoot; } /** * A boolean to know if the application has been booted */ get isBooted() { return this.#state !== "created" && this.#state !== "initiated"; } /** * A boolean to know if the application is ready */ get isReady() { return this.#state === "ready"; } /** * A boolean to know if the application has been terminated */ get isTerminated() { return this.#state === "terminated"; } /** * A boolean to know if the application is in the middle of getting * terminating */ get isTerminating() { return this.#terminating && this.#state !== "terminated"; } /** * Reference to the config class. The value is defined * after the "init" method call */ get config() { return this.#configManager.config; } /** * Reference to the parsed rc file. The value is defined * after the "init" method call */ get rcFile() { return this.#rcFileManager.rcFile; } /** * Normalized current NODE_ENV */ get nodeEnvironment() { return this.#nodeEnvManager.nodeEnvironment; } /** * Return true when `this.nodeEnvironment === 'production'` */ get inProduction() { return this.nodeEnvironment === "production"; } /** * Return true when `this.nodeEnvironment === 'development'` */ get inDev() { return this.nodeEnvironment === "development"; } /** * Returns true when `this.nodeEnvironment === 'test'` */ get inTest() { return this.nodeEnvironment === "test"; } /** * Find if the process is managed and run under * pm2 */ get managedByPm2() { return this.#surroundedEnvironment.pm2; } /** * Reference to scaffolding generators */ get generators() { return generators_default; } /** * Reference to the stubs module to scaffold * resources or eject stubs */ stubs = { create: async () => { const { StubsManager } = await import("./manager-G6OIUQGQ.js"); return new StubsManager(this, this.makePath(this.rcFile.directories.stubs)); } }; /** * Check the status of the configured feature flags and act on them */ experimentalFlags = new FeatureFlags( () => this.#rcFileManager.rcFile.experimental ); /** * A flag to know if VineJS provider is configured. When set * to true, you may import `@vinejs/vine` package */ usingVineJS = false; /** * A flag to know if Edge provider is configured. When set * to true, you may import `edge.js` package */ usingEdgeJS = false; constructor(appRoot, options) { super(); this.#appRoot = appRoot; this.#importer = options.importer; this.#environment = options.environment; this.#nodeEnvManager = new NodeEnvManager(); this.#configManager = new ConfigManager(this.appRoot); this.#rcFileManager = new RcFileManager(this.appRoot); this.#providersManager = new ProvidersManager({ environment: this.#environment, providersState: [this] }); this.#preloadsManager = new PreloadsManager({ environment: this.#environment }); this.#surroundedEnvironment.pm2 = !!process.env.pm2_id; if (debug_default.enabled) { debug_default("app environment :%O", { pm2: this.#surroundedEnvironment.pm2, environment: this.#environment, nodeEnv: this.#nodeEnvManager.nodeEnvironment }); } } /** * Instantiate the application container */ #instantiateContainer() { this.container = new Container(); } /** * The current environment in which the application * is running */ getEnvironment() { return this.#environment; } /** * Switch the environment in which the app is running. The * environment can only be changed before the app is * booted. */ setEnvironment(environment) { if (this.#state !== "created" && this.#state !== "initiated") { throw new RuntimeException2("Cannot switch environment once the app has been booted"); } debug_default('switching environment { from:"%s", to: "%s" }', this.#environment, environment); this.#environment = environment; this.#preloadsManager.setEnvironment(environment); this.#providersManager.setEnvironment(environment); return this; } /** * The current state of the application. */ getState() { return this.#state; } /** * Specify the contents of the "adonisrc.js" file as * an object. Calling this method will disable loading * the "adonisrc.js" file from the disk. */ rcContents(value) { this.#rcFileManager.rcContents(value); return this; } /** * Define the config values to use when booting the * config provider. Calling this method disables * reading files from the config directory. */ useConfig(values) { this.#configManager.useConfig(values); return this; } /** * Notify the parent process when the Node.js process is spawned with an IPC channel. * The arguments accepted are same as "process.send" */ notify(message, sendHandle, options, callback) { if (process.send) { process.send(message, sendHandle, options, callback); } } /** * Listen for a process signal. This method is same as calling * "process.on(signal)" */ listen(signal, callback) { process.on(signal, callback); return this; } /** * Listen for a process signal once. This method is same as calling * "process.once(signal)" */ listenOnce(signal, callback) { process.once(signal, callback); return this; } /** * Listen for a process signal conditionally. */ listenIf(conditional, signal, callback) { if (conditional) { process.on(signal, callback); } return this; } /** * Listen for a process signal once conditionally. */ listenOnceIf(conditional, signal, callback) { if (conditional) { process.once(signal, callback); } return this; } /** * Register hooks that are called before the app starts * the initiating process */ initiating(handler) { this.#hooks.add("initiating", handler); return this; } /** * Initiate the application. Calling this method performs following * operations. * * - Parses the "adonisrc.js" file * - Validate and set environment variables * - Loads the application config from the configured config dir. * - Configures the logger * - Instantiates the IoC container */ async init() { if (this.#state !== "created") { debug_default('cannot initiate app from state "%s"', this.#state); return; } debug_default("initiating app"); this.#instantiateContainer(); await this.#hooks.runner("initiating").run(this); await this.#rcFileManager.process(); this.#hooks.clear("initiating"); this.#state = "initiated"; } /** * Register hooks that are called before the app boot * process starts */ booting(handler) { this.#hooks.add("booting", handler); return this; } /** * Boot the application. Calling this method performs the following * operations. * * - Resolve providers and call the "register" method on them. * - Call the "boot" method on providers * - Run the "booted" hooks */ async boot() { if (this.#state !== "initiated") { debug_default('cannot boot app from state "%s"', this.#state); return; } debug_default("booting app"); await this.#hooks.runner("booting").run(this); this.#hooks.clear("booting"); this.#nodeEnvManager.process(); await this.#configManager.process(this.rcFile.directories.config); this.#providersManager.use(this.rcFile.providers); await this.#providersManager.register(); await this.#providersManager.boot(); await this.#hooks.runner("booted").run(this); this.#hooks.clear("booted"); this.#state = "booted"; } /** * Register a hook to get notified when the application has * been booted. * * The hook will be called immediately if the app has already * been booted. */ async booted(handler) { if (this.isBooted) { await handler(this); } else { this.#hooks.add("booted", handler); } } /** * Register hooks that are called when the app is starting */ starting(handler) { this.#hooks.add("starting", handler); return this; } /** * Start the application. Calling this method performs the following * operations. * * - Run the "start" lifecycle hooks on all the providers * - Start the application by invoking the supplied callback * - Run the "ready" lifecycle hooks on all the providers * - Run the "ready" application hooks */ async start(callback) { if (this.#state !== "booted") { debug_default('cannot start app from state "%s"', this.#state); return; } debug_default("starting app"); await this.#providersManager.start(); await this.#hooks.runner("starting").run(this); this.#hooks.clear("starting"); await this.#preloadsManager.use(this.rcFile.preloads).import(); await callback(this); await this.#providersManager.ready(); await this.#hooks.runner("ready").run(this); this.#hooks.clear("ready"); this.#state = "ready"; debug_default("application ready"); this.notify("ready"); } /** * Register hooks that are called when the app is * ready */ async ready(handler) { if (this.isReady) { await handler(this); } else { this.#hooks.add("ready", handler); } } /** * Register hooks that are called before the app is * terminated. */ terminating(handler) { this.#hooks.add("terminating", handler); return this; } /** * Terminate application gracefully. Calling this method performs * the following operations. * * - Run "shutdown" hooks on all the providers * - Run "terminating" app lifecycle hooks */ async terminate() { if (this.#state === "created" || this.#state === "terminated") { debug_default('cannot terminate app from state "%s"', this.#state); return; } const shutdownInReverseOrder = this.experimentalFlags.enabled("shutdownInReverseOrder"); debug_default("terminating app"); this.#terminating = true; if (shutdownInReverseOrder) { await this.#hooks.runner("terminating").runReverse(this); } else { await this.#hooks.runner("terminating").run(this); } await this.#providersManager.shutdown(shutdownInReverseOrder); this.#hooks.clear("terminating"); this.#state = "terminated"; } /** * Returns relative path to a file from the app root */ relativePath(absolutePath) { return relative(fileURLToPath(this.appRoot), absolutePath); } /** * Returns URL to a path from the application root. */ makeURL(...paths) { return new URL(join2(...paths), this.#appRoot); } /** * Returns file system path from the application root. */ makePath(...paths) { return fileURLToPath(this.makeURL(...paths)); } /** * Makes path to the config directory */ configPath(...paths) { return this.makePath(this.rcFile.directories.config, ...paths); } /** * Makes path to the public directory */ publicPath(...paths) { return this.makePath(this.rcFile.directories.public, ...paths); } /** * Makes path to the providers directory */ providersPath(...paths) { return this.makePath(this.rcFile.directories.providers, ...paths); } /** * Makes path to the factories directory */ factoriesPath(...paths) { return this.makePath(this.rcFile.directories.factories, ...paths); } /** * Makes path to the migrations directory */ migrationsPath(...paths) { return this.makePath(this.rcFile.directories.migrations, ...paths); } /** * Makes path to the seeders directory */ seedersPath(...paths) { return this.makePath(this.rcFile.directories.seeders, ...paths); } /** * Makes path to the language files directory */ languageFilesPath(...paths) { return this.makePath(this.rcFile.directories.languageFiles, ...paths); } /** * Makes path to the views directory */ viewsPath(...paths) { return this.makePath(this.rcFile.directories.views, ...paths); } /** * Makes path to the start directory */ startPath(...paths) { return this.makePath(this.rcFile.directories.start, ...paths); } /** * Makes path to the tmp directory */ tmpPath(...paths) { return this.makePath(this.rcFile.directories.tmp, ...paths); } /** * Makes path to the contracts directory * @deprecated */ contractsPath(...paths) { return this.makePath(this.rcFile.directories.contracts, ...paths); } /** * Makes path to the http controllers directory */ httpControllersPath(...paths) { return this.makePath(this.rcFile.directories.httpControllers, ...paths); } /** * Makes path to the models directory */ modelsPath(...paths) { return this.makePath(this.rcFile.directories.models, ...paths); } /** * Makes path to the services directory */ servicesPath(...paths) { return this.makePath(this.rcFile.directories.services, ...paths); } /** * Makes path to the exceptions directory */ exceptionsPath(...paths) { return this.makePath(this.rcFile.directories.exceptions, ...paths); } /** * Makes path to the mailers directory */ mailersPath(...paths) { return this.makePath(this.rcFile.directories.mailers, ...paths); } /** * Makes path to the mails directory */ mailsPath(...paths) { return this.makePath(this.rcFile.directories.mails, ...paths); } /** * Makes path to the middleware directory */ middlewarePath(...paths) { return this.makePath(this.rcFile.directories.middleware, ...paths); } /** * Makes path to the policies directory */ policiesPath(...paths) { return this.makePath(this.rcFile.directories.policies, ...paths); } /** * Makes path to the validators directory */ validatorsPath(...paths) { return this.makePath(this.rcFile.directories.validators, ...paths); } /** * Makes path to the commands directory */ commandsPath(...paths) { return this.makePath(this.rcFile.directories.commands, ...paths); } /** * Makes path to the events directory */ eventsPath(...paths) { return this.makePath(this.rcFile.directories.events, ...paths); } /** * Makes path to the listeners directory */ listenersPath(...paths) { return this.makePath(this.rcFile.directories.listeners, ...paths); } /** * Import a module by identifier. This method uses the importer function * defined at the time of creating the application instance and throws * an error if no importer was defined. */ import(moduleIdentifier) { if (!this.#importer) { throw new RuntimeException2( `Cannot import "${moduleIdentifier}". Register a module importer with the application first.` ); } return this.#importer(moduleIdentifier); } /** * Import a module by identifier. This method uses the importer function * defined at the time of creating the application instance and throws * an error if no importer was defined. */ importDefault(moduleIdentifier) { if (!this.#importer) { throw new RuntimeException2( `Cannot import "${moduleIdentifier}". Register a module importer with the application first.` ); } return importDefault(() => this.#importer(moduleIdentifier)); } /** * JSON representation of the application */ toJSON() { return { isReady: this.isReady, isTerminating: this.isTerminating, environment: this.#environment, nodeEnvironment: this.nodeEnvironment, appName: this.appName, version: this.version ? this.version.toString() : null, adonisVersion: this.adonisVersion ? this.adonisVersion.toString() : null }; } }; export { errors_exports, generators_default, RcFileParser, FeatureFlags, Application };