-
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Manifest file improves the speed drastically by caching the metadata of commands and lazy loading only the executed command.
- Loading branch information
1 parent
ebf98b4
commit dae9a53
Showing
10 changed files
with
333 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* @adonisjs/ace | ||
* | ||
* (c) Harminder Virk <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { Exception } from '@poppinss/utils' | ||
|
||
/** | ||
* CommandValidationException is used when validating a command before | ||
* registering it with Ace. | ||
*/ | ||
export class CommandValidationException extends Exception { | ||
public static invalidManifestExport (commandPath: string) { | ||
return new this(`make sure to have a default export from {${commandPath}}`) | ||
} | ||
|
||
public static missingCommandName (className: string) { | ||
return new this(`missing command name for {${className}} class`) | ||
} | ||
|
||
public static invalidSpreadArgOrder (arg: string) { | ||
return new this(`spread argument {${arg}} must be at last position`) | ||
} | ||
|
||
public static invalidOptionalArgOrder (optionalArg: string, currentArg: string) { | ||
return new this(`optional argument {${optionalArg}} must be after required argument {${currentArg}}`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* @adonisjs/cli | ||
* | ||
* (c) Harminder Virk <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { join } from 'path' | ||
import { esmRequire } from '@poppinss/utils' | ||
import { writeFile, readFile } from 'fs' | ||
|
||
import { CommandValidationException } from '../Exceptions/CommandValidationException' | ||
import { validateCommand } from '../utils/validateCommand' | ||
import { ManifestNode, CommandConstructorContract } from '../Contracts' | ||
|
||
/** | ||
* Manifest class drastically improves the commands performance, by generating | ||
* a manifest file for all the commands and lazy load only the executed | ||
* command. | ||
*/ | ||
export class Manifest { | ||
constructor (private _appRoot: string) { | ||
} | ||
|
||
/** | ||
* Require and return command | ||
*/ | ||
private _getCommand (commandPath: string): CommandConstructorContract { | ||
const command = esmRequire(join(this._appRoot, commandPath)) | ||
if (!command.name) { | ||
throw CommandValidationException.invalidManifestExport(commandPath) | ||
} | ||
|
||
validateCommand(command) | ||
return command | ||
} | ||
|
||
/** | ||
* Write file to the disk | ||
*/ | ||
private _writeManifest (manifest: ManifestNode): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
writeFile(join(this._appRoot, 'ace-manifest.json'), JSON.stringify(manifest), (error) => { | ||
if (error) { | ||
reject(error) | ||
} else { | ||
resolve() | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Generates the manifest file for the given command paths | ||
*/ | ||
public async generate (commandPaths: string[]) { | ||
const manifest = commandPaths.reduce((manifest: ManifestNode, commandPath) => { | ||
const command = this._getCommand(commandPath) | ||
|
||
manifest[command.commandName] = { | ||
commandPath: commandPath, | ||
commandName: command.commandName, | ||
description: command.description, | ||
args: command.args, | ||
flags: command.flags, | ||
} | ||
|
||
return manifest | ||
}, {}) | ||
|
||
await this._writeManifest(manifest) | ||
} | ||
|
||
/** | ||
* Load the manifest file from the disk. An exception is raised | ||
* when `manifest` file is missing. So the consumer must ensure | ||
* that file exists before calling this method. | ||
*/ | ||
public load (): Promise<ManifestNode> { | ||
return new Promise((resolve, reject) => { | ||
readFile(join(this._appRoot, 'ace-manifest.json'), 'utf-8', (error, contents) => { | ||
if (error) { | ||
reject(error) | ||
} else { | ||
resolve(JSON.parse(contents)) | ||
} | ||
}) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* @adonisjs/ace | ||
* | ||
* (c) Harminder Virk <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
import { CommandConstructorContract, CommandArg } from '../Contracts' | ||
import { CommandValidationException } from '../Exceptions/CommandValidationException' | ||
|
||
/** | ||
* Validates the command static properties to ensure that all the | ||
* values are correctly defined for a command to be executed. | ||
*/ | ||
export function validateCommand (command: CommandConstructorContract) { | ||
/** | ||
* Ensure command has a name | ||
*/ | ||
if (!command.commandName) { | ||
throw CommandValidationException.missingCommandName(command.name) | ||
} | ||
|
||
let optionalArg: CommandArg | ||
|
||
command.args.forEach((arg, index) => { | ||
/** | ||
* Ensure optional arguments comes after required | ||
* arguments | ||
*/ | ||
if (optionalArg && arg.required) { | ||
throw CommandValidationException.invalidOptionalArgOrder(optionalArg.name, arg.name) | ||
} | ||
|
||
/** | ||
* Ensure spread arg is the last arg | ||
*/ | ||
if (arg.type === 'spread' && command.args.length > index + 1) { | ||
throw CommandValidationException.invalidSpreadArgOrder(arg.name) | ||
} | ||
|
||
if (!arg.required) { | ||
optionalArg = arg | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.