velocious 1.0.580 → 1.0.581
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/cli/command-arguments.js +45 -0
- package/build/cli/index.js +10 -0
- package/build/configuration-types.js +1 -0
- package/build/database/generation-context.js +121 -0
- package/build/database/initializer-from-require-context.js +7 -0
- package/build/environment-handlers/node/cli/commands/db/schema/dump.js +25 -0
- package/build/environment-handlers/node/cli/commands/db/schema/load.js +37 -8
- package/build/environment-handlers/node/cli/commands/generate/base-models.js +82 -13
- package/build/src/cli/command-arguments.d.ts +27 -0
- package/build/src/cli/command-arguments.d.ts.map +1 -0
- package/build/src/cli/command-arguments.js +38 -0
- package/build/src/cli/index.d.ts.map +1 -1
- package/build/src/cli/index.js +9 -1
- package/build/src/configuration-types.d.ts +8 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +2 -1
- package/build/src/database/generation-context.d.ts +62 -0
- package/build/src/database/generation-context.d.ts.map +1 -0
- package/build/src/database/generation-context.js +102 -0
- package/build/src/database/initializer-from-require-context.d.ts.map +1 -1
- package/build/src/database/initializer-from-require-context.js +6 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/dump.js +22 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts +11 -0
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/db/schema/load.js +33 -7
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts +14 -0
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/base-models.js +371 -308
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/cli/command-arguments.js +45 -0
- package/src/cli/index.js +10 -0
- package/src/configuration-types.js +1 -0
- package/src/database/generation-context.js +121 -0
- package/src/database/initializer-from-require-context.js +7 -0
- package/src/environment-handlers/node/cli/commands/db/schema/dump.js +25 -0
- package/src/environment-handlers/node/cli/commands/db/schema/load.js +37 -8
- package/src/environment-handlers/node/cli/commands/generate/base-models.js +82 -13
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Built-in record auditing for model lifecycle changes (see [docs/auditing.md](docs/auditing.md))
|
|
9
9
|
* Declarative state machines for models, with typed event methods generated into the base model (see [docs/state-machine.md](docs/state-machine.md))
|
|
10
10
|
* Migrations for schema changes and UTC datetime storage (see [docs/database-migrations.md](docs/database-migrations.md))
|
|
11
|
+
* Tenant-selected base-model and structure generation with one immutable, fail-closed physical database context; tenant-only model metadata initializes only after that context is active (see [docs/tenant-selected-database-generation.md](docs/tenant-selected-database-generation.md))
|
|
11
12
|
* External packages (engines) that contribute data models, frontend-model resources and migrations to a consuming app (see [docs/packages.md](docs/packages.md))
|
|
12
13
|
* Optional Rampway-owned durable deployment control plane mounted through the standard routes DSL on Velocious 1.0.577 or newer (see [docs/rampway-integration.md](docs/rampway-integration.md))
|
|
13
14
|
* Controllers and views for HTTP endpoints
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} CommandArgumentDefinition
|
|
5
|
+
* @property {string[]} [booleanOptions] - Flags that do not accept a value.
|
|
6
|
+
* @property {string[]} [valueOptions] - Flags that require one value.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parses and validates one command's arguments.
|
|
11
|
+
* @param {object} args - Parser arguments.
|
|
12
|
+
* @param {CommandArgumentDefinition} args.definition - Accepted command options.
|
|
13
|
+
* @param {string[]} args.processArgs - Raw command arguments including the command name.
|
|
14
|
+
* @returns {Record<string, string | boolean>} - Values keyed by long option name without `--`.
|
|
15
|
+
*/
|
|
16
|
+
export default function commandArguments({definition, processArgs}) {
|
|
17
|
+
const commandName = processArgs[0] || "command"
|
|
18
|
+
const booleanOptions = new Set(definition.booleanOptions || [])
|
|
19
|
+
const valueOptions = new Set(definition.valueOptions || [])
|
|
20
|
+
/** @type {Record<string, string | boolean>} */
|
|
21
|
+
const parsed = {}
|
|
22
|
+
|
|
23
|
+
for (let index = 1; index < processArgs.length; index++) {
|
|
24
|
+
const argument = processArgs[index]
|
|
25
|
+
|
|
26
|
+
if (booleanOptions.has(argument)) {
|
|
27
|
+
parsed[argument.slice(2)] = true
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (valueOptions.has(argument)) {
|
|
32
|
+
const value = processArgs[index + 1]
|
|
33
|
+
|
|
34
|
+
if (!value || value.startsWith("-")) throw new Error(`Missing value for ${argument}`)
|
|
35
|
+
|
|
36
|
+
parsed[argument.slice(2)] = value
|
|
37
|
+
index++
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
throw new Error(`Unknown argument for ${commandName}: ${argument}`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return parsed
|
|
45
|
+
}
|
package/build/cli/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
const COMMAND_VALUE_OPTIONS = new Set(["--tenant"])
|
|
4
|
+
|
|
3
5
|
export default class VelociousCli {
|
|
4
6
|
/**
|
|
5
7
|
* Runs constructor.
|
|
@@ -94,6 +96,7 @@ export default class VelociousCli {
|
|
|
94
96
|
* Current group.
|
|
95
97
|
* @type {string[]} */
|
|
96
98
|
let currentGroup = []
|
|
99
|
+
let expectsOptionValue = false
|
|
97
100
|
|
|
98
101
|
for (const processArg of processArgs) {
|
|
99
102
|
if (currentGroup.length == 0) {
|
|
@@ -103,11 +106,18 @@ export default class VelociousCli {
|
|
|
103
106
|
continue
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
if (expectsOptionValue) {
|
|
110
|
+
currentGroup.push(processArg)
|
|
111
|
+
expectsOptionValue = false
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
|
|
106
115
|
if (!processArg.startsWith("-") && commandNames.has(processArg)) {
|
|
107
116
|
groups.push(currentGroup)
|
|
108
117
|
currentGroup = [processArg]
|
|
109
118
|
} else {
|
|
110
119
|
currentGroup.push(processArg)
|
|
120
|
+
expectsOptionValue = COMMAND_VALUE_OPTIONS.has(processArg)
|
|
111
121
|
}
|
|
112
122
|
}
|
|
113
123
|
|
|
@@ -661,6 +661,7 @@
|
|
|
661
661
|
/**
|
|
662
662
|
* @typedef {object} TenantDatabaseProviderType
|
|
663
663
|
* @property {(args: {configuration: import("./configuration.js").default, identifier: string}) => Array<ReturnType<typeof JSON.parse>> | Promise<Array<ReturnType<typeof JSON.parse>>>} listTenants - Lists tenants that should be created, checked, or migrated for this database identifier.
|
|
664
|
+
* @property {(args: {configuration: import("./configuration.js").default, identifier: string}) => ReturnType<typeof JSON.parse> | void | Promise<ReturnType<typeof JSON.parse> | void>} [resolveGenerationTenant] - Resolves one explicit tenant descriptor for schema/base-model generation without enumerating lifecycle tenants.
|
|
664
665
|
* @property {(args: {configuration: import("./configuration.js").default, identifier: string}) => Array<ReturnType<typeof JSON.parse>> | Promise<Array<ReturnType<typeof JSON.parse>>>} [listRestrictTenants] - Lists existing tenants that should be checked for dependent restrict destroys. Defaults to listTenants.
|
|
665
666
|
* @property {(args: {configuration: import("./configuration.js").default, databaseConfiguration: DatabaseConfigurationType, identifier: string, tenant: ReturnType<typeof JSON.parse>}) => void | Promise<void>} [createDatabase] - Creates the tenant database/schema for one tenant.
|
|
666
667
|
* @property {(args: {configuration: import("./configuration.js").default, databaseConfiguration: DatabaseConfigurationType, identifier: string, tenant: ReturnType<typeof JSON.parse>}) => void | Promise<void>} [dropDatabase] - Drops the tenant database/schema for one tenant.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import Tenant from "../tenants/tenant.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Immutable selection of one logical tenant database and one provider-resolved
|
|
7
|
+
* physical tenant. Schema tools can share this contract without ambient or
|
|
8
|
+
* process-global selection state.
|
|
9
|
+
*/
|
|
10
|
+
export default class DatabaseGenerationContext {
|
|
11
|
+
/**
|
|
12
|
+
* Resolves one tenant-only database from its provider and captures its physical identity.
|
|
13
|
+
* @param {object} args - Selection arguments.
|
|
14
|
+
* @param {import("../configuration.js").default} args.configuration - Owning configuration.
|
|
15
|
+
* @param {string} args.databaseIdentifier - Logical tenant-only database identifier.
|
|
16
|
+
* @returns {Promise<DatabaseGenerationContext>} - Immutable selected database context.
|
|
17
|
+
*/
|
|
18
|
+
static async resolve({configuration, databaseIdentifier}) {
|
|
19
|
+
const databaseConfiguration = configuration.getDatabaseConfiguration()[databaseIdentifier]
|
|
20
|
+
|
|
21
|
+
if (!databaseConfiguration) {
|
|
22
|
+
throw new Error(`No such tenant database identifier configured: ${databaseIdentifier}`)
|
|
23
|
+
}
|
|
24
|
+
if (!databaseConfiguration.tenantOnly) {
|
|
25
|
+
throw new Error(`Database identifier ${databaseIdentifier} is not configured with tenantOnly: true`)
|
|
26
|
+
}
|
|
27
|
+
if (configuration.getDisabledDatabaseIdentifiers().has(databaseIdentifier)) {
|
|
28
|
+
throw new Error(`Tenant database identifier ${databaseIdentifier} is disabled by VELOCIOUS_DISABLED_DATABASE_IDENTIFIERS`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const provider = configuration.getTenantDatabaseProvider(databaseIdentifier)
|
|
32
|
+
|
|
33
|
+
await configuration.initialize({type: "database-generation"})
|
|
34
|
+
|
|
35
|
+
const tenants = await configuration.ensureConnections({name: `Resolve database generation context: ${databaseIdentifier}`}, async () => {
|
|
36
|
+
if (provider.resolveGenerationTenant) {
|
|
37
|
+
const tenant = await provider.resolveGenerationTenant({configuration, identifier: databaseIdentifier})
|
|
38
|
+
|
|
39
|
+
return tenant === undefined ? [] : [tenant]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return await provider.listTenants({configuration, identifier: databaseIdentifier})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if (!Array.isArray(tenants)) {
|
|
46
|
+
throw new Error(`Tenant database provider for ${databaseIdentifier} must return an array from listTenants`)
|
|
47
|
+
}
|
|
48
|
+
if (tenants.length === 0) {
|
|
49
|
+
throw new Error(`Tenant database selection ${databaseIdentifier} resolved no tenants`)
|
|
50
|
+
}
|
|
51
|
+
if (tenants.length !== 1) {
|
|
52
|
+
throw new Error(`Tenant database selection ${databaseIdentifier} is ambiguous: provider returned ${tenants.length} tenants`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const tenant = tenants[0]
|
|
56
|
+
|
|
57
|
+
if (!tenant || typeof tenant !== "object" || Array.isArray(tenant)) {
|
|
58
|
+
throw new Error(`Tenant database selection ${databaseIdentifier} returned an invalid tenant descriptor`)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const handle = Tenant.handle(tenant, configuration)
|
|
62
|
+
|
|
63
|
+
// Resolve now so an inactive/stale descriptor fails before a selected
|
|
64
|
+
// schema connection can be checked out or read.
|
|
65
|
+
handle.databaseConfiguration(databaseIdentifier)
|
|
66
|
+
|
|
67
|
+
return new DatabaseGenerationContext({configuration, databaseIdentifier, handle})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Runs constructor.
|
|
72
|
+
* @param {object} args - Captured selection.
|
|
73
|
+
* @param {import("../configuration.js").default} args.configuration - Owning configuration.
|
|
74
|
+
* @param {string} args.databaseIdentifier - Logical database identifier.
|
|
75
|
+
* @param {ReturnType<typeof Tenant.handle>} args.handle - Captured tenant handle.
|
|
76
|
+
*/
|
|
77
|
+
constructor({configuration, databaseIdentifier, handle}) {
|
|
78
|
+
this._configuration = configuration
|
|
79
|
+
this._databaseIdentifier = databaseIdentifier
|
|
80
|
+
this._handle = handle
|
|
81
|
+
|
|
82
|
+
Object.freeze(this)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns the captured logical database identifier.
|
|
87
|
+
* @returns {string} - Captured logical database identifier.
|
|
88
|
+
*/
|
|
89
|
+
databaseIdentifier() { return this._databaseIdentifier }
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the captured physical database configuration.
|
|
93
|
+
* @returns {import("../configuration-types.js").DatabaseConfigurationType} - Captured physical database configuration.
|
|
94
|
+
*/
|
|
95
|
+
databaseConfiguration() { return this._handle.databaseConfiguration(this._databaseIdentifier) }
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns the captured tenant descriptor.
|
|
99
|
+
* @returns {ReturnType<ReturnType<typeof Tenant.handle>["tenant"]>} - Captured immutable tenant descriptor.
|
|
100
|
+
*/
|
|
101
|
+
tenant() { return this._handle.tenant() }
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Runs work on one connection pinned to the captured physical database.
|
|
105
|
+
* @template T
|
|
106
|
+
* @param {object} args - Work arguments.
|
|
107
|
+
* @param {(connection: import("./drivers/base.js").default) => Promise<T>} args.callback - Selected database work.
|
|
108
|
+
* @param {string} args.name - Checkout name.
|
|
109
|
+
* @returns {Promise<T>} - Callback result.
|
|
110
|
+
*/
|
|
111
|
+
async run({callback, name}) {
|
|
112
|
+
return await this._configuration.runWithTenant(this.tenant(), async () => {
|
|
113
|
+
return await this._configuration.withDatabaseOperation({
|
|
114
|
+
databaseConfiguration: this.databaseConfiguration(),
|
|
115
|
+
databaseIdentifier: this.databaseIdentifier(),
|
|
116
|
+
name,
|
|
117
|
+
tenant: this.tenant()
|
|
118
|
+
}, async (operation) => await callback(operation.connection()))
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -43,6 +43,13 @@ export default class VelociousDatabaseInitializerFromRequireContext {
|
|
|
43
43
|
|
|
44
44
|
if (!modelClass) throw new Error(`Model wasn't exported from: ${fileName}`)
|
|
45
45
|
|
|
46
|
+
const configuredDatabase = configuration.getDatabaseConfiguration()[modelClass.getConfiguredDatabaseIdentifier()]
|
|
47
|
+
|
|
48
|
+
if (configuredDatabase?.tenantOnly && !configuration.isDatabaseIdentifierActive(modelClass.getConfiguredDatabaseIdentifier())) {
|
|
49
|
+
modelClass.registerRecordClass({configuration})
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
if (!modelClass.getEagerLoadRecordMetadata()) {
|
|
47
54
|
modelClass.registerRecordClass({configuration})
|
|
48
55
|
await this._bestEffortInitializeDeferredModel({configuration, modelClass})
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import BaseCommand from "../../../../../../cli/base-command.js"
|
|
2
|
+
import commandArguments from "../../../../../../cli/command-arguments.js"
|
|
3
|
+
import DatabaseGenerationContext from "../../../../../../database/generation-context.js"
|
|
2
4
|
import fileExists from "../../../../../../utils/file-exists.js"
|
|
3
5
|
import path from "path"
|
|
4
6
|
|
|
@@ -8,6 +10,29 @@ export default class DbSchemaDump extends BaseCommand {
|
|
|
8
10
|
* Runs execute.
|
|
9
11
|
* @returns {Promise<void>} */
|
|
10
12
|
async execute() {
|
|
13
|
+
const parsedArguments = commandArguments({
|
|
14
|
+
definition: {valueOptions: ["--tenant"]},
|
|
15
|
+
processArgs: this.processArgs || []
|
|
16
|
+
})
|
|
17
|
+
const tenantDatabaseIdentifier = parsedArguments.tenant
|
|
18
|
+
|
|
19
|
+
if (typeof tenantDatabaseIdentifier === "string") {
|
|
20
|
+
const context = await DatabaseGenerationContext.resolve({
|
|
21
|
+
configuration: this.getConfiguration(),
|
|
22
|
+
databaseIdentifier: tenantDatabaseIdentifier
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
await context.run({name: "DB selected tenant schema dump", callback: async (db) => {
|
|
26
|
+
const dbs = {[context.databaseIdentifier()]: db}
|
|
27
|
+
const shouldGenerate = await this.shouldGenerateStructureSql({dbs})
|
|
28
|
+
|
|
29
|
+
if (!shouldGenerate) return
|
|
30
|
+
|
|
31
|
+
await this.getEnvironmentHandler().afterMigrations({dbs, reason: "schemaDump"})
|
|
32
|
+
}})
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
11
36
|
await this.getConfiguration().ensureConnections({name: "DB schema dump"}, async (dbs) => {
|
|
12
37
|
const shouldGenerate = await this.shouldGenerateStructureSql({dbs})
|
|
13
38
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import BaseCommand from "../../../../../../cli/base-command.js"
|
|
2
|
+
import commandArguments from "../../../../../../cli/command-arguments.js"
|
|
3
|
+
import DatabaseGenerationContext from "../../../../../../database/generation-context.js"
|
|
2
4
|
import fs from "fs/promises"
|
|
3
5
|
import path from "path"
|
|
4
6
|
import StructureSqlLoader from "../../../../../../database/structure-sql-loader.js"
|
|
@@ -9,17 +11,44 @@ export default class DbSchemaLoad extends BaseCommand {
|
|
|
9
11
|
* Runs execute.
|
|
10
12
|
* @returns {Promise<void>} */
|
|
11
13
|
async execute() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const parsedArguments = commandArguments({
|
|
15
|
+
definition: {valueOptions: ["--tenant"]},
|
|
16
|
+
processArgs: this.processArgs || []
|
|
17
|
+
})
|
|
18
|
+
const tenantDatabaseIdentifier = parsedArguments.tenant
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
if (typeof tenantDatabaseIdentifier === "string") {
|
|
21
|
+
const context = await DatabaseGenerationContext.resolve({
|
|
22
|
+
configuration: this.getConfiguration(),
|
|
23
|
+
databaseIdentifier: tenantDatabaseIdentifier
|
|
24
|
+
})
|
|
20
25
|
|
|
21
|
-
|
|
26
|
+
await context.run({name: "DB selected tenant schema load", callback: async (db) => {
|
|
27
|
+
await this.loadStructureSql({db, identifier: context.databaseIdentifier()})
|
|
28
|
+
}})
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await this.getConfiguration().ensureConnections({name: "DB schema load"}, async (dbs) => {
|
|
33
|
+
for (const identifier of Object.keys(dbs)) {
|
|
34
|
+
await this.loadStructureSql({db: dbs[identifier], identifier})
|
|
22
35
|
}
|
|
23
36
|
})
|
|
24
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Loads one identifier's explicit structure file into one selected connection.
|
|
41
|
+
* @param {object} args - Load arguments.
|
|
42
|
+
* @param {import("../../../../../../database/drivers/base.js").default} args.db - Target connection.
|
|
43
|
+
* @param {string} args.identifier - Logical database identifier used in the file name.
|
|
44
|
+
* @returns {Promise<void>} - Resolves after loading.
|
|
45
|
+
*/
|
|
46
|
+
async loadStructureSql({db, identifier}) {
|
|
47
|
+
const dbDir = path.join(this.directory(), "db")
|
|
48
|
+
const loader = new StructureSqlLoader()
|
|
49
|
+
const structureFilePath = path.join(dbDir, `structure-${identifier}.sql`)
|
|
50
|
+
const structureSql = await fs.readFile(structureFilePath, "utf8")
|
|
51
|
+
|
|
52
|
+
await loader.load({db, structureSql})
|
|
53
|
+
}
|
|
25
54
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import BaseCommand from "../../../../../cli/base-command.js"
|
|
4
|
+
import commandArguments from "../../../../../cli/command-arguments.js"
|
|
5
|
+
import DatabaseGenerationContext from "../../../../../database/generation-context.js"
|
|
4
6
|
import deburrColumnName from "../../../../../utils/deburr-column-name.js"
|
|
5
7
|
import fileExists from "../../../../../utils/file-exists.js"
|
|
6
8
|
import fs from "fs/promises"
|
|
@@ -62,15 +64,64 @@ function generatedRelationshipMethod({abstract = false, body, name, param, retur
|
|
|
62
64
|
|
|
63
65
|
export default class DbGenerateModel extends BaseCommand {
|
|
64
66
|
async execute() {
|
|
67
|
+
const parsedArguments = commandArguments({
|
|
68
|
+
definition: {
|
|
69
|
+
booleanOptions: ["--allow-missing-tables"],
|
|
70
|
+
valueOptions: ["--tenant"]
|
|
71
|
+
},
|
|
72
|
+
processArgs: this.processArgs || []
|
|
73
|
+
})
|
|
74
|
+
const allowMissingTables = parsedArguments["allow-missing-tables"] === true
|
|
75
|
+
const tenantDatabaseIdentifier = parsedArguments.tenant
|
|
76
|
+
|
|
77
|
+
if (typeof tenantDatabaseIdentifier === "string") {
|
|
78
|
+
const context = await DatabaseGenerationContext.resolve({
|
|
79
|
+
configuration: this.getConfiguration(),
|
|
80
|
+
databaseIdentifier: tenantDatabaseIdentifier
|
|
81
|
+
})
|
|
82
|
+
const selectedModelClasses = Object.values(this.getConfiguration().getModelClasses()).filter((modelClass) => {
|
|
83
|
+
const databaseIdentifier = modelClass.getDatabaseIdentifier({
|
|
84
|
+
enforceTenantDatabaseScope: false,
|
|
85
|
+
tenant: context.tenant()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (databaseIdentifier !== context.databaseIdentifier()) return false
|
|
89
|
+
|
|
90
|
+
return modelClass.getDatabaseIdentifier({tenant: context.tenant()}) === context.databaseIdentifier()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
return await context.run({name: "Generate selected tenant base models", callback: async (connection) => {
|
|
95
|
+
await this.generateBaseModels({allowMissingTables, connections: {[context.databaseIdentifier()]: connection}, context})
|
|
96
|
+
}})
|
|
97
|
+
} finally {
|
|
98
|
+
for (const modelClass of selectedModelClasses) modelClass.resetRecordMetadata()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
65
102
|
await this.getConfiguration().initializeModels()
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
return await this.getConfiguration().ensureConnections({name: "Generate base models"}, async (connections) => {
|
|
105
|
+
await this.generateBaseModels({allowMissingTables, connections})
|
|
106
|
+
})
|
|
107
|
+
}
|
|
68
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Generates model bases from explicit connections.
|
|
111
|
+
* @param {object} args - Generation arguments.
|
|
112
|
+
* @param {boolean} args.allowMissingTables - Whether absent tables are skipped.
|
|
113
|
+
* @param {Record<string, import("../../../../../database/drivers/base.js").default>} args.connections - Connections keyed by logical identifier.
|
|
114
|
+
* @param {DatabaseGenerationContext} [args.context] - Selected tenant database context.
|
|
115
|
+
* @returns {Promise<void>} - Resolves after writing generated bases.
|
|
116
|
+
*/
|
|
117
|
+
async generateBaseModels({allowMissingTables, connections, context}) {
|
|
69
118
|
const rootDirectory = this.directory()
|
|
70
119
|
const modelsDir = `${rootDirectory}/src/models`
|
|
71
120
|
const baseModelsDir = `${rootDirectory}/src/model-bases`
|
|
72
121
|
const modelClasses = this.getConfiguration().getModelClasses()
|
|
73
|
-
const
|
|
122
|
+
const regenerateCommand = context
|
|
123
|
+
? `${BASE_MODELS_REGENERATE_COMMAND} --tenant ${context.databaseIdentifier()}`
|
|
124
|
+
: BASE_MODELS_REGENERATE_COMMAND
|
|
74
125
|
let devMode = false
|
|
75
126
|
|
|
76
127
|
if (baseModelsDir.includes("/spec/dummy/src/model-bases")) {
|
|
@@ -81,13 +132,33 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
81
132
|
await fs.mkdir(baseModelsDir, {recursive: true})
|
|
82
133
|
}
|
|
83
134
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
await this.getConfiguration().ensureConnections({name: "Generate base models"}, async () => {
|
|
88
|
-
for (const modelClassName in modelClasses) {
|
|
135
|
+
for (const modelClassName in modelClasses) {
|
|
89
136
|
const modelClass = modelClasses[modelClassName]
|
|
90
|
-
|
|
137
|
+
let databaseIdentifier
|
|
138
|
+
|
|
139
|
+
if (context) {
|
|
140
|
+
databaseIdentifier = modelClass.getDatabaseIdentifier({
|
|
141
|
+
enforceTenantDatabaseScope: false,
|
|
142
|
+
tenant: context.tenant()
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
if (databaseIdentifier !== context.databaseIdentifier()) continue
|
|
146
|
+
|
|
147
|
+
databaseIdentifier = modelClass.getDatabaseIdentifier({tenant: context.tenant()})
|
|
148
|
+
} else {
|
|
149
|
+
databaseIdentifier = modelClass.getConfiguredDatabaseIdentifier()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (context && databaseIdentifier !== context.databaseIdentifier()) continue
|
|
153
|
+
|
|
154
|
+
const connection = connections[databaseIdentifier]
|
|
155
|
+
|
|
156
|
+
// Default generation continues to ignore inactive tenant-only identifiers.
|
|
157
|
+
if (!connection) continue
|
|
158
|
+
|
|
159
|
+
if (context) modelClass.resetRecordMetadata()
|
|
160
|
+
|
|
161
|
+
const table = await connection.getTableByName(modelClass.tableName(), {throwError: !allowMissingTables})
|
|
91
162
|
|
|
92
163
|
if (!table) {
|
|
93
164
|
console.warn(`Skipping base model for '${modelClass.name}': table '${modelClass.tableName()}' was not found (--allow-missing-tables). Keeping any existing base model.`)
|
|
@@ -95,6 +166,8 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
95
166
|
continue
|
|
96
167
|
}
|
|
97
168
|
|
|
169
|
+
await modelClass.ensureInitialized({configuration: this.getConfiguration(), connection})
|
|
170
|
+
|
|
98
171
|
const modelName = inflection.dasherize(modelClassName)
|
|
99
172
|
const modelNameCamelized = inflection.camelize(modelName.replaceAll("-", "_"))
|
|
100
173
|
const modelBaseFileName = `${inflection.dasherize(inflection.underscore(modelName))}.js`
|
|
@@ -111,7 +184,7 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
111
184
|
sourceModelFilePath = "velocious/build/src/database/record/index.js"
|
|
112
185
|
}
|
|
113
186
|
|
|
114
|
-
let fileContent = generatedFileBanner(
|
|
187
|
+
let fileContent = generatedFileBanner(regenerateCommand)
|
|
115
188
|
let velociousPath
|
|
116
189
|
|
|
117
190
|
if (devMode) {
|
|
@@ -454,10 +527,6 @@ export default class DbGenerateModel extends BaseCommand {
|
|
|
454
527
|
fileContent += "}\n"
|
|
455
528
|
|
|
456
529
|
await fs.writeFile(modelPath, fileContent)
|
|
457
|
-
}
|
|
458
|
-
})
|
|
459
|
-
} finally {
|
|
460
|
-
this.getConfiguration().setEnforceTenantDatabaseScopes(enforceTenantDatabaseScopes)
|
|
461
530
|
}
|
|
462
531
|
}
|
|
463
532
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type CommandArgumentDefinition = {
|
|
2
|
+
/**
|
|
3
|
+
* - Flags that do not accept a value.
|
|
4
|
+
*/
|
|
5
|
+
booleanOptions?: string[];
|
|
6
|
+
/**
|
|
7
|
+
* - Flags that require one value.
|
|
8
|
+
*/
|
|
9
|
+
valueOptions?: string[];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} CommandArgumentDefinition
|
|
13
|
+
* @property {string[]} [booleanOptions] - Flags that do not accept a value.
|
|
14
|
+
* @property {string[]} [valueOptions] - Flags that require one value.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Parses and validates one command's arguments.
|
|
18
|
+
* @param {object} args - Parser arguments.
|
|
19
|
+
* @param {CommandArgumentDefinition} args.definition - Accepted command options.
|
|
20
|
+
* @param {string[]} args.processArgs - Raw command arguments including the command name.
|
|
21
|
+
* @returns {Record<string, string | boolean>} - Values keyed by long option name without `--`.
|
|
22
|
+
*/
|
|
23
|
+
export default function commandArguments({ definition, processArgs }: {
|
|
24
|
+
definition: CommandArgumentDefinition;
|
|
25
|
+
processArgs: string[];
|
|
26
|
+
}): Record<string, string | boolean>;
|
|
27
|
+
//# sourceMappingURL=command-arguments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-arguments.d.ts","sourceRoot":"","sources":["../../../src/cli/command-arguments.js"],"names":[],"mappings":"AAGG,YAAkB,yBAAyB,GAC3C;;;;IAAsB,cAAc,AAApC,CACA,EADW,MAAM,EAAE,CACnB;;;;IAAsB,YAAY,AAAlC,CACF,EADa,MAAM,EAAE,CACrB;CAAA,CAAA;AAJD;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAC,UAAU,EAAE,WAAW,EAAC,EAJ/D;IAAwC,UAAU,EAA1C,yBAAyB,CACjC;IAAuB,WAAW,EAA1B,MAAM,EAAE,CAChB;CAE+D,GAFrD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CA+B5C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {object} CommandArgumentDefinition
|
|
4
|
+
* @property {string[]} [booleanOptions] - Flags that do not accept a value.
|
|
5
|
+
* @property {string[]} [valueOptions] - Flags that require one value.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Parses and validates one command's arguments.
|
|
9
|
+
* @param {object} args - Parser arguments.
|
|
10
|
+
* @param {CommandArgumentDefinition} args.definition - Accepted command options.
|
|
11
|
+
* @param {string[]} args.processArgs - Raw command arguments including the command name.
|
|
12
|
+
* @returns {Record<string, string | boolean>} - Values keyed by long option name without `--`.
|
|
13
|
+
*/
|
|
14
|
+
export default function commandArguments({ definition, processArgs }) {
|
|
15
|
+
const commandName = processArgs[0] || "command";
|
|
16
|
+
const booleanOptions = new Set(definition.booleanOptions || []);
|
|
17
|
+
const valueOptions = new Set(definition.valueOptions || []);
|
|
18
|
+
/** @type {Record<string, string | boolean>} */
|
|
19
|
+
const parsed = {};
|
|
20
|
+
for (let index = 1; index < processArgs.length; index++) {
|
|
21
|
+
const argument = processArgs[index];
|
|
22
|
+
if (booleanOptions.has(argument)) {
|
|
23
|
+
parsed[argument.slice(2)] = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (valueOptions.has(argument)) {
|
|
27
|
+
const value = processArgs[index + 1];
|
|
28
|
+
if (!value || value.startsWith("-"))
|
|
29
|
+
throw new Error(`Missing value for ${argument}`);
|
|
30
|
+
parsed[argument.slice(2)] = value;
|
|
31
|
+
index++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Unknown argument for ${commandName}: ${argument}`);
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWFuZC1hcmd1bWVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL2NvbW1hbmQtYXJndW1lbnRzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7OztHQUlHO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE9BQU8sVUFBVSxnQkFBZ0IsQ0FBQyxFQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUM7SUFDaEUsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLFNBQVMsQ0FBQTtJQUMvQyxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsY0FBYyxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQy9ELE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxDQUFDLFVBQVUsQ0FBQyxZQUFZLElBQUksRUFBRSxDQUFDLENBQUE7SUFDM0QsK0NBQStDO0lBQy9DLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQTtJQUVqQixLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsV0FBVyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDO1FBQ3hELE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUVuQyxJQUFJLGNBQWMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNqQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQTtZQUNoQyxTQUFRO1FBQ1YsQ0FBQztRQUVELElBQUksWUFBWSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUE7WUFFcEMsSUFBSSxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHFCQUFxQixRQUFRLEVBQUUsQ0FBQyxDQUFBO1lBRXJGLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFBO1lBQ2pDLEtBQUssRUFBRSxDQUFBO1lBQ1AsU0FBUTtRQUNWLENBQUM7UUFFRCxNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixXQUFXLEtBQUssUUFBUSxFQUFFLENBQUMsQ0FBQTtJQUNyRSxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUE7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbi8qKlxuICogQHR5cGVkZWYge29iamVjdH0gQ29tbWFuZEFyZ3VtZW50RGVmaW5pdGlvblxuICogQHByb3BlcnR5IHtzdHJpbmdbXX0gW2Jvb2xlYW5PcHRpb25zXSAtIEZsYWdzIHRoYXQgZG8gbm90IGFjY2VwdCBhIHZhbHVlLlxuICogQHByb3BlcnR5IHtzdHJpbmdbXX0gW3ZhbHVlT3B0aW9uc10gLSBGbGFncyB0aGF0IHJlcXVpcmUgb25lIHZhbHVlLlxuICovXG5cbi8qKlxuICogUGFyc2VzIGFuZCB2YWxpZGF0ZXMgb25lIGNvbW1hbmQncyBhcmd1bWVudHMuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFBhcnNlciBhcmd1bWVudHMuXG4gKiBAcGFyYW0ge0NvbW1hbmRBcmd1bWVudERlZmluaXRpb259IGFyZ3MuZGVmaW5pdGlvbiAtIEFjY2VwdGVkIGNvbW1hbmQgb3B0aW9ucy5cbiAqIEBwYXJhbSB7c3RyaW5nW119IGFyZ3MucHJvY2Vzc0FyZ3MgLSBSYXcgY29tbWFuZCBhcmd1bWVudHMgaW5jbHVkaW5nIHRoZSBjb21tYW5kIG5hbWUuXG4gKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgYm9vbGVhbj59IC0gVmFsdWVzIGtleWVkIGJ5IGxvbmcgb3B0aW9uIG5hbWUgd2l0aG91dCBgLS1gLlxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBjb21tYW5kQXJndW1lbnRzKHtkZWZpbml0aW9uLCBwcm9jZXNzQXJnc30pIHtcbiAgY29uc3QgY29tbWFuZE5hbWUgPSBwcm9jZXNzQXJnc1swXSB8fCBcImNvbW1hbmRcIlxuICBjb25zdCBib29sZWFuT3B0aW9ucyA9IG5ldyBTZXQoZGVmaW5pdGlvbi5ib29sZWFuT3B0aW9ucyB8fCBbXSlcbiAgY29uc3QgdmFsdWVPcHRpb25zID0gbmV3IFNldChkZWZpbml0aW9uLnZhbHVlT3B0aW9ucyB8fCBbXSlcbiAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBib29sZWFuPn0gKi9cbiAgY29uc3QgcGFyc2VkID0ge31cblxuICBmb3IgKGxldCBpbmRleCA9IDE7IGluZGV4IDwgcHJvY2Vzc0FyZ3MubGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgY29uc3QgYXJndW1lbnQgPSBwcm9jZXNzQXJnc1tpbmRleF1cblxuICAgIGlmIChib29sZWFuT3B0aW9ucy5oYXMoYXJndW1lbnQpKSB7XG4gICAgICBwYXJzZWRbYXJndW1lbnQuc2xpY2UoMildID0gdHJ1ZVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICBpZiAodmFsdWVPcHRpb25zLmhhcyhhcmd1bWVudCkpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gcHJvY2Vzc0FyZ3NbaW5kZXggKyAxXVxuXG4gICAgICBpZiAoIXZhbHVlIHx8IHZhbHVlLnN0YXJ0c1dpdGgoXCItXCIpKSB0aHJvdyBuZXcgRXJyb3IoYE1pc3NpbmcgdmFsdWUgZm9yICR7YXJndW1lbnR9YClcblxuICAgICAgcGFyc2VkW2FyZ3VtZW50LnNsaWNlKDIpXSA9IHZhbHVlXG4gICAgICBpbmRleCsrXG4gICAgICBjb250aW51ZVxuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBhcmd1bWVudCBmb3IgJHtjb21tYW5kTmFtZX06ICR7YXJndW1lbnR9YClcbiAgfVxuXG4gIHJldHVybiBwYXJzZWRcbn1cbiJdfQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.js"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,OAAO,YAAY;IAcxB,IAAI;wBAVA,OAAO,qBAAqB,EAAE,OAAO;oBACrC,MAAM;6BACN,OAAO,iCAAiC,EAAE,OAAO;4BACjD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;sBACrD,MAAM,EAAE;kBACR,OAAO;;IAMX,aAAa;IAEb,kBAAkB;IAhBzB;;;;;;;;;OASG;IACH,YAAY,IAAI,GAPb;QAAqD,aAAa,AAAlE,CACA,EADQ,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,SAAS,AAA/B,CACA,EADQ,MAAM,CACd;QAAiE,kBAAkB,AAAnF,CACA,EADQ,OAAO,iCAAiC,EAAE,OAAO,CACzD;QAAqE,iBAAiB,AAAtF,CACA,EADQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAC7D;QAAwB,WAAW,AAAnC,CACA,EADQ,MAAM,EAAE,CAChB;QAAuB,OAAO,AAA9B,CACF,EADU,OAAO,CACjB;KACoB,EASpB;IAED;;;OAGG;IACG,OAAO,IAFA,OAAO,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAmBlD;IAED;;;;OAIG;IACG,cAAc,CAAC,WAAW,EAHrB,MAAM,EAGe,GAFnB,OAAO,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CA4BlD;IAED;;;OAGG;IACG,aAAa,IAFN,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAgD/B;IAED;;;OAGG;IACH,gBAAgB,IAFH,OAAO,qBAAqB,EAAE,OAAO,CAEF;IAEhD;;;OAGG;IACH,6BAA6B,IAFhB,OAAO,CAUnB;IAED;;;OAGG;IACH,UAAU,IAFG,OAAO,CAInB;CACF"}
|
package/build/src/cli/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const COMMAND_VALUE_OPTIONS = new Set(["--tenant"]);
|
|
2
3
|
export default class VelociousCli {
|
|
3
4
|
/**
|
|
4
5
|
* Runs constructor.
|
|
@@ -85,6 +86,7 @@ export default class VelociousCli {
|
|
|
85
86
|
* Current group.
|
|
86
87
|
* @type {string[]} */
|
|
87
88
|
let currentGroup = [];
|
|
89
|
+
let expectsOptionValue = false;
|
|
88
90
|
for (const processArg of processArgs) {
|
|
89
91
|
if (currentGroup.length == 0) {
|
|
90
92
|
if (processArg.startsWith("-"))
|
|
@@ -92,12 +94,18 @@ export default class VelociousCli {
|
|
|
92
94
|
currentGroup = [processArg];
|
|
93
95
|
continue;
|
|
94
96
|
}
|
|
97
|
+
if (expectsOptionValue) {
|
|
98
|
+
currentGroup.push(processArg);
|
|
99
|
+
expectsOptionValue = false;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
95
102
|
if (!processArg.startsWith("-") && commandNames.has(processArg)) {
|
|
96
103
|
groups.push(currentGroup);
|
|
97
104
|
currentGroup = [processArg];
|
|
98
105
|
}
|
|
99
106
|
else {
|
|
100
107
|
currentGroup.push(processArg);
|
|
108
|
+
expectsOptionValue = COMMAND_VALUE_OPTIONS.has(processArg);
|
|
101
109
|
}
|
|
102
110
|
}
|
|
103
111
|
if (currentGroup.length > 0) {
|
|
@@ -135,4 +143,4 @@ export default class VelociousCli {
|
|
|
135
143
|
return this.args.testing || false;
|
|
136
144
|
}
|
|
137
145
|
}
|
|
138
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixNQUFNLENBQUMsT0FBTyxPQUFPLFlBQVk7SUFDL0I7Ozs7Ozs7OztPQVNHO0lBQ0gsWUFBWSxJQUFJLEdBQUcsRUFBRTtRQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWE7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUE7UUFFOUUsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUE7UUFDaEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFBO1FBRXZDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLHFCQUFxQixFQUFFLENBQUE7UUFDcEUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNyQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQzlELENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsT0FBTztRQUNYLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFBO1FBQ2hELElBQUksTUFBTSxDQUFBO1FBRVYsS0FBSyxNQUFNLGtCQUFrQixJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQy9DLE1BQU0sOEJBQThCLEdBQUcsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLEVBQUUsQ0FBQTtZQUU1RSxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFBO1lBQ3hELENBQUM7b0JBQVMsQ0FBQztnQkFDVCxJQUFJLDhCQUE4QixFQUFFLENBQUM7b0JBQ25DLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUMsd0JBQXdCLEVBQUUsQ0FBQTtnQkFDMUQsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUE7SUFDZixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsV0FBVztRQUM5QixJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFBO1FBQzdDLENBQUM7UUFFRCxNQUFNLFlBQVksR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQzlDLE1BQU0sa0JBQWtCLEdBQUcsRUFBRSxDQUFBO1FBRTdCLEtBQUssSUFBSSxXQUFXLElBQUksWUFBWSxFQUFFLENBQUM7WUFDckMsSUFBSSxXQUFXLElBQUksR0FBRztnQkFBRSxXQUFXLEdBQUcsU0FBUyxDQUFBO1lBQy9DLElBQUksV0FBVyxJQUFJLEdBQUc7Z0JBQUUsV0FBVyxHQUFHLFNBQVMsQ0FBQTtZQUMvQyxJQUFJLFdBQVcsSUFBSSxHQUFHO2dCQUFFLFdBQVcsR0FBRyxVQUFVLENBQUE7WUFDaEQsSUFBSSxXQUFXLElBQUksR0FBRztnQkFBRSxXQUFXLEdBQUcsUUFBUSxDQUFBO1lBRTlDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUN0QyxDQUFDO1FBRUQsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUFDLEVBQUMsWUFBWSxFQUFFLGtCQUFrQixFQUFDLENBQUMsQ0FBQTtRQUNyRyxNQUFNLGVBQWUsR0FBRyxJQUFJLFlBQVksQ0FBQztZQUN2QyxJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxFQUFDLFdBQVcsRUFBQyxDQUFDO1lBQ2pELEdBQUcsRUFBRSxJQUFJO1NBQ1YsQ0FBQyxDQUFBO1FBRUYsTUFBTSxlQUFlLENBQUMsVUFBVSxFQUFFLENBQUE7UUFFbEMsT0FBTyxNQUFNLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtJQUN4QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLGFBQWE7UUFDakIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFBO1FBQy9DLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLFlBQVksRUFBRSxDQUFBO1FBQzdELE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO1FBQ3JFOztnQ0FFd0I7UUFDeEIsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFBO1FBQ2pCOzs4QkFFc0I7UUFDdEIsSUFBSSxZQUFZLEdBQUcsRUFBRSxDQUFBO1FBRXJCLEtBQUssTUFBTSxVQUFVLElBQUksV0FBVyxFQUFFLENBQUM7WUFDckMsSUFBSSxZQUFZLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM3QixJQUFJLFVBQVUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO29CQUFFLFNBQVE7Z0JBRXhDLFlBQVksR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFBO2dCQUMzQixTQUFRO1lBQ1YsQ0FBQztZQUVELElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDaEUsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtnQkFDekIsWUFBWSxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDN0IsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDL0IsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDNUIsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUMzQixDQUFDO1FBRUQsSUFBSSxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQTtRQUM3QyxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUE7SUFDZixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsZ0JBQWdCLEtBQUssT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFBLENBQUMsQ0FBQztJQUVoRDs7O09BR0c7SUFDSCw2QkFBNkI7UUFDM0IsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLHFCQUFxQixFQUFFLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFBO1FBQ2hGLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVksS0FBSyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLDRDQUE0QyxDQUFDO2dCQUFFLE9BQU8sS0FBSyxDQUFBO1lBRWxILE1BQU0sS0FBSyxDQUFBO1FBQ2IsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxVQUFVO1FBQ1IsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUE7SUFDbkMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZlbG9jaW91c0NsaSB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gW2FyZ3MuY29uZmlndXJhdGlvbl0gLSBDb25maWd1cmF0aW9uIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuZGlyZWN0b3J5XSAtIERpcmVjdG9yeSBwYXRoLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2Vudmlyb25tZW50LWhhbmRsZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gW2FyZ3MuZW52aXJvbm1lbnRIYW5kbGVyXSAtIEVudmlyb25tZW50IGhhbmRsZXIuXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IHVuZGVmaW5lZD59IFthcmdzLnBhcnNlZFByb2Nlc3NBcmdzXSAtIFBhcnNlZCBwcm9jZXNzIGFyZ3MuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IFthcmdzLnByb2Nlc3NBcmdzXSAtIFByb2Nlc3MgYXJncy5cbiAgICogQHBhcmFtIHtib29sZWFufSBbYXJncy50ZXN0aW5nXSAtIFdoZXRoZXIgdGVzdGluZy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGFyZ3MgPSB7fSkge1xuICAgIGlmICghYXJncy5jb25maWd1cmF0aW9uKSB0aHJvdyBuZXcgRXJyb3IoXCJjb25maWd1cmF0aW9uIGFyZ3VtZW50IGlzIHJlcXVpcmVkXCIpXG5cbiAgICB0aGlzLmFyZ3MgPSBhcmdzXG4gICAgdGhpcy5jb25maWd1cmF0aW9uID0gYXJncy5jb25maWd1cmF0aW9uXG5cbiAgICB0aGlzLmVudmlyb25tZW50SGFuZGxlciA9IGFyZ3MuY29uZmlndXJhdGlvbi5nZXRFbnZpcm9ubWVudEhhbmRsZXIoKVxuICAgIHRoaXMuZW52aXJvbm1lbnRIYW5kbGVyLnNldEFyZ3MoYXJncylcbiAgICB0aGlzLmVudmlyb25tZW50SGFuZGxlci5zZXRDb25maWd1cmF0aW9uKGFyZ3MuY29uZmlndXJhdGlvbilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGV4ZWN1dGUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gLSBSZXNvbHZlcyB3aXRoIHRoZSBmaW5hbCBjb21tYW5kIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGV4ZWN1dGUoKSB7XG4gICAgY29uc3QgY29tbWFuZEdyb3VwcyA9IGF3YWl0IHRoaXMuY29tbWFuZEdyb3VwcygpXG4gICAgbGV0IHJlc3VsdFxuXG4gICAgZm9yIChjb25zdCBjb21tYW5kUHJvY2Vzc0FyZ3Mgb2YgY29tbWFuZEdyb3Vwcykge1xuICAgICAgY29uc3Qgc2hvdWxkQ2xvc2VEYXRhYmFzZUNvbm5lY3Rpb25zID0gIXRoaXMuaGFzQ3VycmVudERhdGFiYXNlQ29ubmVjdGlvbnMoKVxuXG4gICAgICB0cnkge1xuICAgICAgICByZXN1bHQgPSBhd2FpdCB0aGlzLmV4ZWN1dGVDb21tYW5kKGNvbW1hbmRQcm9jZXNzQXJncylcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGlmIChzaG91bGRDbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmdldENvbmZpZ3VyYXRpb24oKS5jbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZXhlY3V0ZSBjb21tYW5kLlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBwcm9jZXNzQXJncyAtIFByb2Nlc3MgYXJncyBmb3IgYSBzaW5nbGUgY29tbWFuZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4+fSAtIFJlc29sdmVzIHdpdGggdGhlIGNvbW1hbmQgcmVzdWx0LlxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZUNvbW1hbmQocHJvY2Vzc0FyZ3MpIHtcbiAgICBpZiAoIXByb2Nlc3NBcmdzWzBdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNaXNzaW5nIGNvbW1hbmQgYXJndW1lbnRcIilcbiAgICB9XG5cbiAgICBjb25zdCBjb21tYW5kUGFydHMgPSBwcm9jZXNzQXJnc1swXS5zcGxpdChcIjpcIilcbiAgICBjb25zdCBwYXJzZWRDb21tYW5kUGFydHMgPSBbXVxuXG4gICAgZm9yIChsZXQgY29tbWFuZFBhcnQgb2YgY29tbWFuZFBhcnRzKSB7XG4gICAgICBpZiAoY29tbWFuZFBhcnQgPT0gXCJjXCIpIGNvbW1hbmRQYXJ0ID0gXCJjb25zb2xlXCJcbiAgICAgIGlmIChjb21tYW5kUGFydCA9PSBcImRcIikgY29tbWFuZFBhcnQgPSBcImRlc3Ryb3lcIlxuICAgICAgaWYgKGNvbW1hbmRQYXJ0ID09IFwiZ1wiKSBjb21tYW5kUGFydCA9IFwiZ2VuZXJhdGVcIlxuICAgICAgaWYgKGNvbW1hbmRQYXJ0ID09IFwic1wiKSBjb21tYW5kUGFydCA9IFwic2VydmVyXCJcblxuICAgICAgcGFyc2VkQ29tbWFuZFBhcnRzLnB1c2goY29tbWFuZFBhcnQpXG4gICAgfVxuXG4gICAgY29uc3QgQ29tbWFuZENsYXNzID0gYXdhaXQgdGhpcy5lbnZpcm9ubWVudEhhbmRsZXIucmVxdWlyZUNvbW1hbmQoe2NvbW1hbmRQYXJ0czogcGFyc2VkQ29tbWFuZFBhcnRzfSlcbiAgICBjb25zdCBjb21tYW5kSW5zdGFuY2UgPSBuZXcgQ29tbWFuZENsYXNzKHtcbiAgICAgIGFyZ3M6IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuYXJncywge3Byb2Nlc3NBcmdzfSksXG4gICAgICBjbGk6IHRoaXNcbiAgICB9KVxuXG4gICAgYXdhaXQgY29tbWFuZEluc3RhbmNlLmluaXRpYWxpemUoKVxuXG4gICAgcmV0dXJuIGF3YWl0IGNvbW1hbmRJbnN0YW5jZS5leGVjdXRlKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGNvbW1hbmQgZ3JvdXBzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXVtdPn0gLSBDb21tYW5kIGdyb3VwcyB3aXRoIHByb2Nlc3MgYXJncyBmb3IgZWFjaCBjb21tYW5kLlxuICAgKi9cbiAgYXN5bmMgY29tbWFuZEdyb3VwcygpIHtcbiAgICBjb25zdCBwcm9jZXNzQXJncyA9IHRoaXMuYXJncy5wcm9jZXNzQXJncyB8fCBbXVxuICAgIGNvbnN0IGNvbW1hbmRzID0gYXdhaXQgdGhpcy5lbnZpcm9ubWVudEhhbmRsZXIuZmluZENvbW1hbmRzKClcbiAgICBjb25zdCBjb21tYW5kTmFtZXMgPSBuZXcgU2V0KGNvbW1hbmRzLm1hcCgoY29tbWFuZCkgPT4gY29tbWFuZC5uYW1lKSlcbiAgICAvKipcbiAgICAgKiBHcm91cHMuXG4gICAgICogQHR5cGUge3N0cmluZ1tdW119ICovXG4gICAgY29uc3QgZ3JvdXBzID0gW11cbiAgICAvKipcbiAgICAgKiBDdXJyZW50IGdyb3VwLlxuICAgICAqIEB0eXBlIHtzdHJpbmdbXX0gKi9cbiAgICBsZXQgY3VycmVudEdyb3VwID0gW11cblxuICAgIGZvciAoY29uc3QgcHJvY2Vzc0FyZyBvZiBwcm9jZXNzQXJncykge1xuICAgICAgaWYgKGN1cnJlbnRHcm91cC5sZW5ndGggPT0gMCkge1xuICAgICAgICBpZiAocHJvY2Vzc0FyZy5zdGFydHNXaXRoKFwiLVwiKSkgY29udGludWVcblxuICAgICAgICBjdXJyZW50R3JvdXAgPSBbcHJvY2Vzc0FyZ11cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKCFwcm9jZXNzQXJnLnN0YXJ0c1dpdGgoXCItXCIpICYmIGNvbW1hbmROYW1lcy5oYXMocHJvY2Vzc0FyZykpIHtcbiAgICAgICAgZ3JvdXBzLnB1c2goY3VycmVudEdyb3VwKVxuICAgICAgICBjdXJyZW50R3JvdXAgPSBbcHJvY2Vzc0FyZ11cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGN1cnJlbnRHcm91cC5wdXNoKHByb2Nlc3NBcmcpXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGN1cnJlbnRHcm91cC5sZW5ndGggPiAwKSB7XG4gICAgICBncm91cHMucHVzaChjdXJyZW50R3JvdXApXG4gICAgfVxuXG4gICAgaWYgKGdyb3Vwcy5sZW5ndGggPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWlzc2luZyBjb21tYW5kIGFyZ3VtZW50XCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIGdyb3Vwc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IGNvbmZpZ3VyYXRpb24uXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGdldENvbmZpZ3VyYXRpb24oKSB7IHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24gfVxuXG4gIC8qKlxuICAgKiBSdW5zIGhhcyBjdXJyZW50IGRhdGFiYXNlIGNvbm5lY3Rpb25zLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoZSBjdXJyZW50IGFzeW5jIGNvbnRleHQgYWxyZWFkeSBoYXMgZGF0YWJhc2UgY29ubmVjdGlvbnMuXG4gICAqL1xuICBoYXNDdXJyZW50RGF0YWJhc2VDb25uZWN0aW9ucygpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLmdldEN1cnJlbnRDb25uZWN0aW9ucygpKS5sZW5ndGggPiAwXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmIGVycm9yLm1lc3NhZ2Uuc3RhcnRzV2l0aChcIk5vIGRhdGFiYXNlIGNvbmZpZ3VyYXRpb24gZm9yIGVudmlyb25tZW50OlwiKSkgcmV0dXJuIGZhbHNlXG5cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IHRlc3RpbmcuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgdGVzdGluZy5cbiAgICovXG4gIGdldFRlc3RpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXJncy50ZXN0aW5nIHx8IGZhbHNlXG4gIH1cbn1cbiJdfQ==
|
|
146
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixNQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQTtBQUVuRCxNQUFNLENBQUMsT0FBTyxPQUFPLFlBQVk7SUFDL0I7Ozs7Ozs7OztPQVNHO0lBQ0gsWUFBWSxJQUFJLEdBQUcsRUFBRTtRQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWE7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUE7UUFFOUUsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUE7UUFDaEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFBO1FBRXZDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLHFCQUFxQixFQUFFLENBQUE7UUFDcEUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNyQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFBO0lBQzlELENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsT0FBTztRQUNYLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFBO1FBQ2hELElBQUksTUFBTSxDQUFBO1FBRVYsS0FBSyxNQUFNLGtCQUFrQixJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQy9DLE1BQU0sOEJBQThCLEdBQUcsQ0FBQyxJQUFJLENBQUMsNkJBQTZCLEVBQUUsQ0FBQTtZQUU1RSxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFBO1lBQ3hELENBQUM7b0JBQVMsQ0FB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LENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQTtJQUNuQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuY29uc3QgQ09NTUFORF9WQUxVRV9PUFRJT05TID0gbmV3IFNldChbXCItLXRlbmFudFwiXSlcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVmVsb2Npb3VzQ2xpIHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucyBvYmplY3QuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBbYXJncy5jb25maWd1cmF0aW9uXSAtIENvbmZpZ3VyYXRpb24gaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5kaXJlY3RvcnldIC0gRGlyZWN0b3J5IHBhdGguXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vZW52aXJvbm1lbnQtaGFuZGxlcnMvYmFzZS5qc1wiKS5kZWZhdWx0fSBbYXJncy5lbnZpcm9ubWVudEhhbmRsZXJdIC0gRW52aXJvbm1lbnQgaGFuZGxlci5cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgdW5kZWZpbmVkPn0gW2FyZ3MucGFyc2VkUHJvY2Vzc0FyZ3NdIC0gUGFyc2VkIHByb2Nlc3MgYXJncy5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW2FyZ3MucHJvY2Vzc0FyZ3NdIC0gUHJvY2VzcyBhcmdzLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthcmdzLnRlc3RpbmddIC0gV2hldGhlciB0ZXN0aW5nLlxuICAgKi9cbiAgY29uc3RydWN0b3IoYXJncyA9IHt9KSB7XG4gICAgaWYgKCFhcmdzLmNvbmZpZ3VyYXRpb24pIHRocm93IG5ldyBFcnJvcihcImNvbmZpZ3VyYXRpb24gYXJndW1lbnQgaXMgcmVxdWlyZWRcIilcblxuICAgIHRoaXMuYXJncyA9IGFyZ3NcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSBhcmdzLmNvbmZpZ3VyYXRpb25cblxuICAgIHRoaXMuZW52aXJvbm1lbnRIYW5kbGVyID0gYXJncy5jb25maWd1cmF0aW9uLmdldEVudmlyb25tZW50SGFuZGxlcigpXG4gICAgdGhpcy5lbnZpcm9ubWVudEhhbmRsZXIuc2V0QXJncyhhcmdzKVxuICAgIHRoaXMuZW52aXJvbm1lbnRIYW5kbGVyLnNldENvbmZpZ3VyYXRpb24oYXJncy5jb25maWd1cmF0aW9uKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZXhlY3V0ZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4+fSAtIFJlc29sdmVzIHdpdGggdGhlIGZpbmFsIGNvbW1hbmQgcmVzdWx0LlxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZSgpIHtcbiAgICBjb25zdCBjb21tYW5kR3JvdXBzID0gYXdhaXQgdGhpcy5jb21tYW5kR3JvdXBzKClcbiAgICBsZXQgcmVzdWx0XG5cbiAgICBmb3IgKGNvbnN0IGNvbW1hbmRQcm9jZXNzQXJncyBvZiBjb21tYW5kR3JvdXBzKSB7XG4gICAgICBjb25zdCBzaG91bGRDbG9zZURhdGFiYXNlQ29ubmVjdGlvbnMgPSAhdGhpcy5oYXNDdXJyZW50RGF0YWJhc2VDb25uZWN0aW9ucygpXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IHRoaXMuZXhlY3V0ZUNvbW1hbmQoY29tbWFuZFByb2Nlc3NBcmdzKVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKHNob3VsZENsb3NlRGF0YWJhc2VDb25uZWN0aW9ucykge1xuICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLmNsb3NlRGF0YWJhc2VDb25uZWN0aW9ucygpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICAvKipcbiAgICogUnVucyBleGVjdXRlIGNvbW1hbmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHByb2Nlc3NBcmdzIC0gUHJvY2VzcyBhcmdzIGZvciBhIHNpbmdsZSBjb21tYW5kLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59IC0gUmVzb2x2ZXMgd2l0aCB0aGUgY29tbWFuZCByZXN1bHQuXG4gICAqL1xuICBhc3luYyBleGVjdXRlQ29tbWFuZChwcm9jZXNzQXJncykge1xuICAgIGlmICghcHJvY2Vzc0FyZ3NbMF0pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgY29tbWFuZCBhcmd1bWVudFwiKVxuICAgIH1cblxuICAgIGNvbnN0IGNvbW1hbmRQYXJ0cyA9IHByb2Nlc3NBcmdzWzBdLnNwbGl0KFwiOlwiKVxuICAgIGNvbnN0IHBhcnNlZENvbW1hbmRQYXJ0cyA9IFtdXG5cbiAgICBmb3IgKGxldCBjb21tYW5kUGFydCBvZiBjb21tYW5kUGFydHMpIHtcbiAgICAgIGlmIChjb21tYW5kUGFydCA9PSBcImNcIikgY29tbWFuZFBhcnQgPSBcImNvbnNvbGVcIlxuICAgICAgaWYgKGNvbW1hbmRQYXJ0ID09IFwiZFwiKSBjb21tYW5kUGFydCA9IFwiZGVzdHJveVwiXG4gICAgICBpZiAoY29tbWFuZFBhcnQgPT0gXCJnXCIpIGNvbW1hbmRQYXJ0ID0gXCJnZW5lcmF0ZVwiXG4gICAgICBpZiAoY29tbWFuZFBhcnQgPT0gXCJzXCIpIGNvbW1hbmRQYXJ0ID0gXCJzZXJ2ZXJcIlxuXG4gICAgICBwYXJzZWRDb21tYW5kUGFydHMucHVzaChjb21tYW5kUGFydClcbiAgICB9XG5cbiAgICBjb25zdCBDb21tYW5kQ2xhc3MgPSBhd2FpdCB0aGlzLmVudmlyb25tZW50SGFuZGxlci5yZXF1aXJlQ29tbWFuZCh7Y29tbWFuZFBhcnRzOiBwYXJzZWRDb21tYW5kUGFydHN9KVxuICAgIGNvbnN0IGNvbW1hbmRJbnN0YW5jZSA9IG5ldyBDb21tYW5kQ2xhc3Moe1xuICAgICAgYXJnczogT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5hcmdzLCB7cHJvY2Vzc0FyZ3N9KSxcbiAgICAgIGNsaTogdGhpc1xuICAgIH0pXG5cbiAgICBhd2FpdCBjb21tYW5kSW5zdGFuY2UuaW5pdGlhbGl6ZSgpXG5cbiAgICByZXR1cm4gYXdhaXQgY29tbWFuZEluc3RhbmNlLmV4ZWN1dGUoKVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgY29tbWFuZCBncm91cHMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZ1tdW10+fSAtIENvbW1hbmQgZ3JvdXBzIHdpdGggcHJvY2VzcyBhcmdzIGZvciBlYWNoIGNvbW1hbmQuXG4gICAqL1xuICBhc3luYyBjb21tYW5kR3JvdXBzKCkge1xuICAgIGNvbnN0IHByb2Nlc3NBcmdzID0gdGhpcy5hcmdzLnByb2Nlc3NBcmdzIHx8IFtdXG4gICAgY29uc3QgY29tbWFuZHMgPSBhd2FpdCB0aGlzLmVudmlyb25tZW50SGFuZGxlci5maW5kQ29tbWFuZHMoKVxuICAgIGNvbnN0IGNvbW1hbmROYW1lcyA9IG5ldyBTZXQoY29tbWFuZHMubWFwKChjb21tYW5kKSA9PiBjb21tYW5kLm5hbWUpKVxuICAgIC8qKlxuICAgICAqIEdyb3Vwcy5cbiAgICAgKiBAdHlwZSB7c3RyaW5nW11bXX0gKi9cbiAgICBjb25zdCBncm91cHMgPSBbXVxuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgZ3JvdXAuXG4gICAgICogQHR5cGUge3N0cmluZ1tdfSAqL1xuICAgIGxldCBjdXJyZW50R3JvdXAgPSBbXVxuICAgIGxldCBleHBlY3RzT3B0aW9uVmFsdWUgPSBmYWxzZVxuXG4gICAgZm9yIChjb25zdCBwcm9jZXNzQXJnIG9mIHByb2Nlc3NBcmdzKSB7XG4gICAgICBpZiAoY3VycmVudEdyb3VwLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgIGlmIChwcm9jZXNzQXJnLnN0YXJ0c1dpdGgoXCItXCIpKSBjb250aW51ZVxuXG4gICAgICAgIGN1cnJlbnRHcm91cCA9IFtwcm9jZXNzQXJnXVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBpZiAoZXhwZWN0c09wdGlvblZhbHVlKSB7XG4gICAgICAgIGN1cnJlbnRHcm91cC5wdXNoKHByb2Nlc3NBcmcpXG4gICAgICAgIGV4cGVjdHNPcHRpb25WYWx1ZSA9IGZhbHNlXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGlmICghcHJvY2Vzc0FyZy5zdGFydHNXaXRoKFwiLVwiKSAmJiBjb21tYW5kTmFtZXMuaGFzKHByb2Nlc3NBcmcpKSB7XG4gICAgICAgIGdyb3Vwcy5wdXNoKGN1cnJlbnRHcm91cClcbiAgICAgICAgY3VycmVudEdyb3VwID0gW3Byb2Nlc3NBcmddXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50R3JvdXAucHVzaChwcm9jZXNzQXJnKVxuICAgICAgICBleHBlY3RzT3B0aW9uVmFsdWUgPSBDT01NQU5EX1ZBTFVFX09QVElPTlMuaGFzKHByb2Nlc3NBcmcpXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGN1cnJlbnRHcm91cC5sZW5ndGggPiAwKSB7XG4gICAgICBncm91cHMucHVzaChjdXJyZW50R3JvdXApXG4gICAgfVxuXG4gICAgaWYgKGdyb3Vwcy5sZW5ndGggPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWlzc2luZyBjb21tYW5kIGFyZ3VtZW50XCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIGdyb3Vwc1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IGNvbmZpZ3VyYXRpb24uXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGdldENvbmZpZ3VyYXRpb24oKSB7IHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24gfVxuXG4gIC8qKlxuICAgKiBSdW5zIGhhcyBjdXJyZW50IGRhdGFiYXNlIGNvbm5lY3Rpb25zLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoZSBjdXJyZW50IGFzeW5jIGNvbnRleHQgYWxyZWFkeSBoYXMgZGF0YWJhc2UgY29ubmVjdGlvbnMuXG4gICAqL1xuICBoYXNDdXJyZW50RGF0YWJhc2VDb25uZWN0aW9ucygpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLmdldEN1cnJlbnRDb25uZWN0aW9ucygpKS5sZW5ndGggPiAwXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmIGVycm9yLm1lc3NhZ2Uuc3RhcnRzV2l0aChcIk5vIGRhdGFiYXNlIGNvbmZpZ3VyYXRpb24gZm9yIGVudmlyb25tZW50OlwiKSkgcmV0dXJuIGZhbHNlXG5cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZ2V0IHRlc3RpbmcuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgdGVzdGluZy5cbiAgICovXG4gIGdldFRlc3RpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXJncy50ZXN0aW5nIHx8IGZhbHNlXG4gIH1cbn1cbiJdfQ==
|