This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+9
View File
@@ -0,0 +1,9 @@
# The MIT License
Copyright 2022 Harminder Virk, contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+49
View File
@@ -0,0 +1,49 @@
<div align="center">
<img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1558612869/adonis-readme_zscycu.jpg" width="600px">
</div>
<br />
<div align="center">
<h3> Core Commands for building AdonisJS projects </h3>
<p>
Assembler contains a set of core commands to <strong>build and serve the AdonisJS typescript project</strong>, along with scaffolding <code>make</code> commands.
</p>
</div>
<br />
<div align="center">
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] [![synk-image]][synk-url]
</div>
<div align="center">
<h3>
<a href="https://adonisjs.com">
Website
</a>
<span> | </span>
<a href="https://docs.adonisjs.com/guides/installation">
Guides
</a>
<span> | </span>
<a href="CONTRIBUTING.md">
Contributing
</a>
</h3>
</div>
<div align="center">
<sub>Built with ❤︎ by <a href="https://twitter.com/AmanVirk1">Harminder Virk</a>
</div>
[gh-workflow-image]: https://img.shields.io/github/workflow/status/adonisjs/assembler/test?style=for-the-badge
[gh-workflow-url]: https://github.com/adonisjs/assembler/actions/workflows/test.yml "Github action"
[npm-image]: https://img.shields.io/npm/v/@adonisjs/assembler/latest.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/@adonisjs/assembler/v/latest "npm"
[synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs/assembler?label=Synk%20Vulnerabilities&style=for-the-badge
[synk-url]: https://snyk.io/test/github/adonisjs/assembler?targetFile=package.json "synk"
+521
View File
@@ -0,0 +1,521 @@
{
"commands": {
"build": {
"settings": {},
"commandPath": "./commands/Build",
"commandName": "build",
"description": "Compile project from Typescript to Javascript. Also compiles the frontend assets if using webpack encore",
"args": [],
"aliases": [],
"flags": [
{
"name": "production",
"propertyName": "production",
"type": "boolean",
"description": "Build for production",
"alias": "prod"
},
{
"name": "assets",
"propertyName": "assets",
"type": "boolean",
"description": "Build frontend assets when webpack encore is installed. Use --no-assets to disable"
},
{
"name": "ignore-ts-errors",
"propertyName": "ignoreTsErrors",
"type": "boolean",
"description": "Ignore typescript errors and complete the build process"
},
{
"name": "tsconfig",
"propertyName": "tsconfig",
"type": "string",
"description": "Path to the TypeScript project configuration file"
},
{
"name": "encore-args",
"propertyName": "encoreArgs",
"type": "array",
"description": "CLI options to pass to the encore command line"
},
{
"name": "client",
"propertyName": "client",
"type": "string",
"description": "Select the package manager to decide which lock file to copy to the build folder"
}
]
},
"configure": {
"settings": {},
"commandPath": "./commands/Invoke",
"commandName": "configure",
"description": "Configure one or more AdonisJS packages",
"args": [
{
"type": "spread",
"propertyName": "packages",
"name": "packages",
"required": true,
"description": "Name of the package(s) you want to configure"
}
],
"aliases": [
"invoke"
],
"flags": []
},
"make:command": {
"settings": {},
"commandPath": "./commands/Make/Command",
"commandName": "make:command",
"description": "Make a new ace command",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the command class"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the command with the exact name as provided",
"alias": "e"
}
]
},
"make:controller": {
"settings": {},
"commandPath": "./commands/Make/Controller",
"commandName": "make:controller",
"description": "Make a new HTTP controller",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the controller class"
}
],
"aliases": [],
"flags": [
{
"name": "resource",
"propertyName": "resource",
"type": "boolean",
"description": "Add resourceful methods to the controller class",
"alias": "r"
},
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the controller with the exact name as provided",
"alias": "e"
}
]
},
"make:exception": {
"settings": {},
"commandPath": "./commands/Make/Exception",
"commandName": "make:exception",
"description": "Make a new custom exception class",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the exception class"
}
],
"aliases": [],
"flags": [
{
"name": "self-handle",
"propertyName": "selfHandle",
"type": "boolean",
"description": "Add the handle method to self handle the exception"
},
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the exception class with the exact name as provided",
"alias": "e"
}
]
},
"make:listener": {
"settings": {},
"commandPath": "./commands/Make/Listener",
"commandName": "make:listener",
"description": "Make a new event listener class",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the event listener class"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the listener with the exact name as provided",
"alias": "e"
}
]
},
"make:middleware": {
"settings": {},
"commandPath": "./commands/Make/Middleware",
"commandName": "make:middleware",
"description": "Make a new middleware",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the middleware class"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the middleware with the exact name as provided",
"alias": "e"
}
]
},
"make:prldfile": {
"settings": {},
"commandPath": "./commands/Make/PreloadFile",
"commandName": "make:prldfile",
"description": "Make a new preload file",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the file"
}
],
"aliases": [],
"flags": [
{
"name": "environment",
"propertyName": "environment",
"type": "array",
"description": "Define the preload file environment. Accepted values \"console,web,repl,test\""
}
]
},
"make:provider": {
"settings": {},
"commandPath": "./commands/Make/Provider",
"commandName": "make:provider",
"description": "Make a new provider class",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the provider class"
}
],
"aliases": [],
"flags": [
{
"name": "ace",
"propertyName": "ace",
"type": "boolean",
"description": "Register provider under the ace providers array"
},
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the provider with the exact name as provided",
"alias": "e"
}
]
},
"make:suite": {
"settings": {},
"commandPath": "./commands/Make/Suite",
"commandName": "make:suite",
"description": "Create a new test suite",
"args": [
{
"type": "string",
"propertyName": "suite",
"name": "suite",
"required": true,
"description": "Name of the test suite"
},
{
"type": "string",
"propertyName": "location",
"name": "location",
"required": false,
"description": "Path to the test suite directory"
}
],
"aliases": [],
"flags": [
{
"name": "with-example-test",
"propertyName": "withExampleTest",
"type": "boolean",
"description": "Add a sample test file"
}
]
},
"make:test": {
"settings": {},
"commandPath": "./commands/Make/Test",
"commandName": "make:test",
"description": "Make a new test",
"args": [
{
"type": "string",
"propertyName": "suite",
"name": "suite",
"required": true,
"description": "Name of the test suite"
},
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the test file"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the test file with the exact name as provided",
"alias": "e"
}
]
},
"make:validator": {
"settings": {},
"commandPath": "./commands/Make/Validator",
"commandName": "make:validator",
"description": "Make a new validator",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the validator class"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the validator with the exact name as provided",
"alias": "e"
}
]
},
"make:view": {
"settings": {},
"commandPath": "./commands/Make/View",
"commandName": "make:view",
"description": "Make a new view template",
"args": [
{
"type": "string",
"propertyName": "name",
"name": "name",
"required": true,
"description": "Name of the view"
}
],
"aliases": [],
"flags": [
{
"name": "exact",
"propertyName": "exact",
"type": "boolean",
"description": "Create the template file with the exact name as provided",
"alias": "e"
}
]
},
"serve": {
"settings": {
"stayAlive": true
},
"commandPath": "./commands/Serve",
"commandName": "serve",
"description": "Start the AdonisJS HTTP server, along with the file watcher. Also starts the webpack dev server when webpack encore is installed",
"args": [],
"aliases": [],
"flags": [
{
"name": "assets",
"propertyName": "assets",
"type": "boolean",
"description": "Start webpack dev server when encore is installed. Use \"--no-assets\" to disable"
},
{
"name": "watch",
"propertyName": "watch",
"type": "boolean",
"description": "Watch for file changes and re-start the HTTP server on change",
"alias": "w"
},
{
"name": "poll",
"propertyName": "poll",
"type": "boolean",
"description": "Detect file changes by polling files instead of listening to filesystem events",
"alias": "p"
},
{
"name": "node-args",
"propertyName": "nodeArgs",
"type": "array",
"description": "CLI options to pass to the node command line"
},
{
"name": "encore-args",
"propertyName": "encoreArgs",
"type": "array",
"description": "CLI options to pass to the encore command line"
}
]
},
"test": {
"settings": {
"stayAlive": true
},
"commandPath": "./commands/Test",
"commandName": "test",
"description": "Run AdonisJS tests",
"args": [
{
"type": "spread",
"propertyName": "suites",
"name": "suites",
"required": false,
"description": "Run tests for only the specified suites"
}
],
"aliases": [],
"flags": [
{
"name": "files",
"propertyName": "files",
"type": "array",
"description": "Run tests for the mentioned files only"
},
{
"name": "watch",
"propertyName": "watch",
"type": "boolean",
"description": "Watch for file changes and re-run tests on file change",
"alias": "w"
},
{
"name": "poll",
"propertyName": "poll",
"type": "boolean",
"description": "Detect file changes by polling files instead of listening to filesystem events",
"alias": "p"
},
{
"name": "node-args",
"propertyName": "nodeArgs",
"type": "array",
"description": "CLI options to pass to the node command line"
},
{
"name": "tags",
"propertyName": "tags",
"type": "array",
"description": "Filter tests by tags"
},
{
"name": "ignore-tags",
"propertyName": "ignoreTags",
"type": "array",
"description": "Filter tests by ignoring tags"
},
{
"name": "tests",
"propertyName": "tests",
"type": "array",
"description": "Filter tests by title"
},
{
"name": "groups",
"propertyName": "groups",
"type": "array",
"description": "Filter tests by group title"
},
{
"name": "timeout",
"propertyName": "timeout",
"type": "number",
"description": "Customize tests timeout"
},
{
"name": "force-exit",
"propertyName": "forceExit",
"type": "boolean",
"description": "Force exit the tests runner process"
}
]
},
"type-check": {
"settings": {},
"commandPath": "./commands/TypeCheck",
"commandName": "type-check",
"description": "Type check TypeScript source without writing the compiled output on disk",
"args": [],
"aliases": [],
"flags": [
{
"name": "tsconfig",
"propertyName": "tsconfig",
"type": "string",
"description": "Path to the TypeScript project configuration file"
}
]
}
},
"aliases": {
"invoke": "configure"
}
}
+37
View File
@@ -0,0 +1,37 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Compile typescript project Javascript
*/
export default class Build extends BaseCommand {
static commandName: string;
static description: string;
/**
* Build for production
*/
production: boolean;
/**
* Bundle frontend assets. Defaults to true
*/
assets: boolean;
/**
* Ignore ts errors and complete the build process. Defaults to false
*/
ignoreTsErrors: boolean;
/**
* Path to the TypeScript project configuration file. Defaults to "tsconfig.json"
*/
tsconfig: string;
/**
* Arguments to pass to the `encore` binary
*/
encoreArgs: string[];
/**
* Select the client for deciding the lock file to copy to the
* build folder
*/
client: string;
/**
* Invoked automatically by ace
*/
run(): Promise<void>;
}
+138
View File
@@ -0,0 +1,138 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const has_yarn_1 = __importDefault(require("has-yarn"));
const standalone_1 = require("@adonisjs/core/build/standalone");
const paths_1 = require("../config/paths");
/**
* Compile typescript project Javascript
*/
class Build extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
/**
* Bundle frontend assets. Defaults to true
*/
this.assets = true;
/**
* Path to the TypeScript project configuration file. Defaults to "tsconfig.json"
*/
this.tsconfig = paths_1.TSCONFIG_FILE_NAME;
/**
* Arguments to pass to the `encore` binary
*/
this.encoreArgs = [];
}
/**
* Invoked automatically by ace
*/
async run() {
const { Compiler } = await Promise.resolve().then(() => __importStar(require('../src/Compiler')));
/**
* Deciding the client to use for installing dependencies
*/
this.client = this.client || (0, has_yarn_1.default)(this.application.appRoot) ? 'yarn' : 'npm';
if (this.client !== 'npm' && this.client !== 'yarn') {
this.logger.warning('--client must be set to "npm" or "yarn"');
this.exitCode = 1;
return;
}
/**
* Stop on error when "ignoreTsErrors" is not set
*/
const stopOnError = !this.ignoreTsErrors;
try {
const compiler = new Compiler(this.application.appRoot, this.encoreArgs, this.assets, this.logger, this.tsconfig);
const compiled = this.production
? await compiler.compileForProduction(stopOnError, this.client)
: await compiler.compile(stopOnError);
/**
* Set exitCode based upon the compiled status
*/
if (!compiled) {
this.exitCode = 1;
}
}
catch (error) {
this.logger.fatal(error);
this.exitCode = 1;
}
}
}
Build.commandName = 'build';
Build.description = 'Compile project from Typescript to Javascript. Also compiles the frontend assets if using webpack encore';
__decorate([
standalone_1.flags.boolean({ description: 'Build for production', alias: 'prod' }),
__metadata("design:type", Boolean)
], Build.prototype, "production", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Build frontend assets when webpack encore is installed. Use --no-assets to disable',
}),
__metadata("design:type", Boolean)
], Build.prototype, "assets", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Ignore typescript errors and complete the build process',
}),
__metadata("design:type", Boolean)
], Build.prototype, "ignoreTsErrors", void 0);
__decorate([
standalone_1.flags.string({
description: 'Path to the TypeScript project configuration file',
}),
__metadata("design:type", String)
], Build.prototype, "tsconfig", void 0);
__decorate([
standalone_1.flags.array({ description: 'CLI options to pass to the encore command line' }),
__metadata("design:type", Array)
], Build.prototype, "encoreArgs", void 0);
__decorate([
standalone_1.flags.string({
description: 'Select the package manager to decide which lock file to copy to the build folder',
}),
__metadata("design:type", String)
], Build.prototype, "client", void 0);
exports.default = Build;
+34
View File
@@ -0,0 +1,34 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Configure a package
*/
export default class Configure extends BaseCommand {
static commandName: string;
static description: string;
static aliases: string[];
private appType;
/**
* Use yarn when building for production to install dependencies
*/
packages: string[];
/**
* Returns package manager for installing dependencies
*/
private getPackageManager;
/**
* Configure encore
*/
private configureEncore;
/**
* Configure tests
*/
private configureTests;
/**
* Configure a give package
*/
private configurePackage;
/**
* Invoked automatically by ace
*/
run(): Promise<void>;
}
+234
View File
@@ -0,0 +1,234 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const sink_1 = require("@adonisjs/sink");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Manifest_1 = require("../src/Manifest");
/**
* Configure a package
*/
class Configure extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
this.appType = process.env['ADONIS_CREATE_APP_BOILERPLATE'] || 'web';
}
/**
* Returns package manager for installing dependencies
*/
getPackageManager() {
if (process.env['ADONIS_CREATE_APP_CLIENT']) {
return process.env['ADONIS_CREATE_APP_CLIENT'];
}
return sink_1.utils.getPackageManager(this.application.appRoot);
}
/**
* Configure encore
*/
async configureEncore() {
/**
* Create the webpack config file
*/
const webpackConfigFile = new sink_1.files.MustacheFile(this.application.appRoot, 'webpack.config.js', (0, path_1.join)(__dirname, '..', 'templates/webpack.config.txt'));
if (!webpackConfigFile.exists()) {
webpackConfigFile.apply({}).commit();
sink_1.logger.action('create').succeeded('webpack.config.js');
}
/**
* Create app.js entrypoint
*/
const entryPointFile = new sink_1.files.NewLineFile(this.application.appRoot, 'resources/js/app.js');
if (!entryPointFile.exists()) {
entryPointFile.add('// app entrypoint').commit();
sink_1.logger.action('create').succeeded('resources/js/app.js');
}
/**
* Install Encore
*/
const pkgFile = new sink_1.files.PackageJsonFile(this.application.appRoot);
pkgFile.install('@symfony/webpack-encore@4.1.1');
pkgFile.install('webpack@^5.72');
pkgFile.install('webpack-cli@^4.9.1');
pkgFile.install('@babel/core@^7.17.0');
pkgFile.install('@babel/preset-env@^7.16.0');
pkgFile.useClient(this.getPackageManager());
const spinner = sink_1.logger.await(sink_1.logger.colors.gray('configure @symfony/webpack-encore'));
try {
const response = await pkgFile.commitAsync();
if (response && response.status === 1) {
spinner.stop();
sink_1.logger.fatal({ message: 'Unable to configure encore', stack: response.stderr.toString() });
}
else {
spinner.stop();
sink_1.logger.success('Configured encore successfully');
}
}
catch (error) {
spinner.stop();
sink_1.logger.fatal(error);
}
}
/**
* Configure tests
*/
async configureTests() {
/**
* Create "test.ts" file
*/
const testsEntryPointFile = new sink_1.files.MustacheFile(this.application.appRoot, 'test.ts', (0, path_1.join)(__dirname, '..', 'templates/test-entrypoint.txt'));
if (!testsEntryPointFile.exists()) {
testsEntryPointFile.apply({}).commit();
sink_1.logger.action('create').succeeded('test.ts');
}
/**
* Create "tests/bootstrap.ts" file
*/
const testsBootstrapFile = new sink_1.files.MustacheFile(this.application.appRoot, 'tests/bootstrap.ts', (0, path_1.join)(__dirname, '..', 'templates/tests/bootstrap.txt'));
if (!testsBootstrapFile.exists()) {
testsBootstrapFile.apply({}).commit();
sink_1.logger.action('create').succeeded('tests/bootstrap.ts');
}
/**
* Create "tests/functional/hello_world.spec.ts" file
*/
const helloWorldTestFile = new sink_1.files.MustacheFile(this.application.appRoot, 'tests/functional/hello_world.spec.ts', (0, path_1.join)(__dirname, '..', `templates/tests/functional/hello_world_${this.appType}.spec.txt`));
if (!helloWorldTestFile.exists()) {
helloWorldTestFile.apply({}).commit();
sink_1.logger.action('create').succeeded('tests/functional/hello_world.spec.ts');
}
/**
* Create "contracts/tests.ts" file
*/
const testsContractsFile = new sink_1.files.MustacheFile(this.application.appRoot, 'contracts/tests.ts', (0, path_1.join)(__dirname, '..', 'templates/tests-contract.txt'));
if (!testsContractsFile.exists()) {
testsContractsFile.apply({}).commit();
sink_1.logger.action('create').succeeded('contracts/tests.ts');
}
/**
* Update AdonisRc file with test suites
*/
const rcFile = new sink_1.files.AdonisRcFile(this.application.appRoot);
rcFile.set('tests', {
suites: [
{
name: 'functional',
files: ['tests/functional/**/*.spec(.ts|.js)'],
timeout: 60 * 1000,
},
],
});
rcFile.addTestProvider('@japa/preset-adonis/TestsProvider');
rcFile.commit();
sink_1.logger.action('update').succeeded('.adonisrc.json');
/**
* Create ".env.test" file
*/
const testEnvFile = new sink_1.files.NewLineFile(this.application.appRoot, '.env.test');
if (!testEnvFile.exists()) {
testEnvFile.add('NODE_ENV=test');
/**
* Set additional .env variables for "web" boilerplate
*/
if (this.appType === 'web') {
testEnvFile.add(['ASSETS_DRIVER=fake', 'SESSION_DRIVER=memory']);
}
testEnvFile.commit();
sink_1.logger.action('create').succeeded('.env.test');
}
/**
* Update "tsconfig.json"
*/
const tsConfig = new sink_1.files.JsonFile(this.application.appRoot, 'tsconfig.json');
const existingTypes = tsConfig.get('compilerOptions.types') || [];
if (!existingTypes.includes('@japa/preset-adonis/build/adonis-typings')) {
existingTypes.push('@japa/preset-adonis/build/adonis-typings');
}
tsConfig.set('compilerOptions.types', existingTypes);
tsConfig.commit();
sink_1.logger.action('update').succeeded('tsconfig.json');
/**
* Set additional .env variables for "web" boilerplate
*/
if (this.appType === 'web') {
testEnvFile.add(['ASSETS_DRIVER=fake', 'SESSION_DRIVER=memory']);
}
testEnvFile.commit();
sink_1.logger.action('create').succeeded('.env.test');
/**
* Install required dependencies
*/
const pkgFile = new sink_1.files.PackageJsonFile(this.application.appRoot);
pkgFile.install('@japa/runner@2.5.1');
pkgFile.install('@japa/preset-adonis');
pkgFile.useClient(this.getPackageManager());
const spinner = sink_1.logger.await(sink_1.logger.colors.gray('installing @japa/runner, @japa/preset-adonis'));
try {
const response = await pkgFile.commitAsync();
if (response && response.status === 1) {
spinner.stop();
sink_1.logger.fatal({
message: 'Unable to configure tests runner',
stack: response.stderr.toString(),
});
}
else {
spinner.stop();
sink_1.logger.success('Configured tests runner successfully');
}
}
catch (error) {
spinner.stop();
sink_1.logger.fatal(error);
}
}
/**
* Configure a give package
*/
async configurePackage(name) {
if (name === 'encore') {
await this.configureEncore();
return;
}
if (name === 'tests') {
await this.configureTests();
return;
}
await new sink_1.tasks.Instructions(name, this.application.appRoot, this.application, true).execute();
await new Manifest_1.Manifest(this.application.appRoot, this.logger).generate();
}
/**
* Invoked automatically by ace
*/
async run() {
for (let name of this.packages) {
await this.configurePackage(name);
}
}
}
Configure.commandName = 'configure';
Configure.description = 'Configure one or more AdonisJS packages';
Configure.aliases = ['invoke'];
__decorate([
standalone_1.args.spread({
description: 'Name of the package(s) you want to configure',
}),
__metadata("design:type", Array)
], Configure.prototype, "packages", void 0);
exports.default = Configure;
+30
View File
@@ -0,0 +1,30 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Base class to generate framework entities
*/
export declare abstract class BaseGenerator extends BaseCommand {
protected abstract resourceName: string;
protected abstract createExact: boolean;
protected abstract getStub(): string;
protected abstract getDestinationPath(): string;
protected suffix?: string;
protected extname: string;
protected form?: 'singular' | 'plural';
protected pattern?: 'camelcase' | 'snakecase' | 'pascalcase';
protected formIgnoreList?: string[];
protected templateData(): any;
/**
* Returns path for a given namespace by replacing the base namespace
* with the defined directories map inside the `.adonisrc.json`
* file
*/
protected getPathForNamespace(namespaceFor: string): string | null;
/**
* Returns contents of the rcFile
*/
protected hasRcFile(cwd: string): Promise<boolean>;
/**
* Handle command
*/
generate(): Promise<import("@adonisjs/ace/build/src/Contracts").GeneratorFileContract | undefined>;
}
+75
View File
@@ -0,0 +1,75 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseGenerator = void 0;
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const standalone_1 = require("@adonisjs/core/build/standalone");
/**
* Base class to generate framework entities
*/
class BaseGenerator extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
this.extname = '.ts';
}
templateData() {
return {};
}
/**
* Returns path for a given namespace by replacing the base namespace
* with the defined directories map inside the `.adonisrc.json`
* file
*/
getPathForNamespace(namespaceFor) {
return this.application.resolveNamespaceDirectory(namespaceFor);
}
/**
* Returns contents of the rcFile
*/
async hasRcFile(cwd) {
const filePath = (0, path_1.join)(cwd, '.adonisrc.json');
return (0, fs_extra_1.pathExists)(filePath);
}
/**
* Handle command
*/
async generate() {
const hasRcFile = await this.hasRcFile(this.application.appRoot);
/**
* Ensure `.adonisrc.json` file exists
*/
if (!hasRcFile) {
this.logger.error('Make sure your project root has ".adonisrc.json" file');
return;
}
const transformations = this.createExact
? {
extname: this.extname,
}
: {
form: this.form,
suffix: this.suffix,
formIgnoreList: this.formIgnoreList,
pattern: this.pattern,
extname: this.extname,
};
const file = this.generator
.addFile(this.resourceName, transformations)
.stub(this.getStub())
.useMustache()
.destinationDir(this.getDestinationPath())
.appRoot(this.application.appRoot)
.apply(this.templateData());
await this.generator.run();
return file;
}
}
exports.BaseGenerator = BaseGenerator;
@@ -0,0 +1,35 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new command
*/
export default class MakeCommand extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
exact: boolean;
/**
* Returns the template stub based upon the `--resource`
* flag value
*/
protected getStub(): string;
/**
* Path to the commands directory
*/
protected getDestinationPath(): string;
/**
* Passed down to the template.
*/
protected templateData(): {
toCommandName: () => (filename: string, render: any) => string;
};
run(): Promise<void>;
}
+82
View File
@@ -0,0 +1,82 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const helpers_1 = require("@poppinss/utils/build/helpers");
const Base_1 = require("./Base");
/**
* Command to make a new command
*/
class MakeCommand extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.pattern = 'pascalcase';
}
/**
* Returns the template stub based upon the `--resource`
* flag value
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'command.txt');
}
/**
* Path to the commands directory
*/
getDestinationPath() {
return this.application.rcFile.directories.commands || 'commands';
}
/**
* Passed down to the template.
*/
templateData() {
return {
toCommandName: () => {
return function (filename, render) {
return helpers_1.string.snakeCase(render(filename)).replace(/_/, ':');
};
},
};
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeCommand.commandName = 'make:command';
MakeCommand.description = 'Make a new ace command';
__decorate([
standalone_1.args.string({ description: 'Name of the command class' }),
__metadata("design:type", String)
], MakeCommand.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the command with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeCommand.prototype, "exact", void 0);
exports.default = MakeCommand;
@@ -0,0 +1,37 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new HTTP Controller
*/
export default class MakeController extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected suffix: string;
protected form: "plural";
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Do not pluralize following controller names
*/
protected formIgnoreList: string[];
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
resource: boolean;
exact: boolean;
/**
* Returns the template stub based upon the `--resource`
* flag value
*/
protected getStub(): string;
/**
* Pull path from the `httpControllers` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Controllers/Http`
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
@@ -0,0 +1,89 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new HTTP Controller
*/
class MakeController extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.suffix = 'Controller';
this.form = 'plural';
this.pattern = 'pascalcase';
/**
* Do not pluralize following controller names
*/
this.formIgnoreList = [
'Home',
'Auth',
'Login',
'Authentication',
'Adonis',
'Dashboard',
'Signup',
'Api',
];
}
/**
* Returns the template stub based upon the `--resource`
* flag value
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', this.resource ? 'resource-controller.txt' : 'controller.txt');
}
/**
* Pull path from the `httpControllers` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Controllers/Http`
*/
getDestinationPath() {
return this.getPathForNamespace('httpControllers') || 'app/Controllers/Http';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeController.commandName = 'make:controller';
MakeController.description = 'Make a new HTTP controller';
__decorate([
standalone_1.args.string({ description: 'Name of the controller class' }),
__metadata("design:type", String)
], MakeController.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({ description: 'Add resourceful methods to the controller class', alias: 'r' }),
__metadata("design:type", Boolean)
], MakeController.prototype, "resource", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the controller with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeController.prototype, "exact", void 0);
exports.default = MakeController;
@@ -0,0 +1,32 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new event exceptions class
*/
export default class MakeException extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected form: "singular";
protected pattern: "pascalcase";
protected resourceName: string;
protected suffix: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
selfHandle: boolean;
exact: boolean;
/**
* Returns the template stub
*/
protected getStub(): string;
/**
* Pull path from the `exceptions` namespace declaration from
* the `.adonisrc.json` file or fallback to `app/Exceptions`
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
@@ -0,0 +1,75 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new event exceptions class
*/
class MakeException extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.form = 'singular';
this.pattern = 'pascalcase';
this.suffix = 'Exception';
}
/**
* Returns the template stub
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', this.selfHandle ? 'self-handle-exception.txt' : 'exception.txt');
}
/**
* Pull path from the `exceptions` namespace declaration from
* the `.adonisrc.json` file or fallback to `app/Exceptions`
*/
getDestinationPath() {
return this.getPathForNamespace('exceptions') || 'app/Exceptions';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeException.commandName = 'make:exception';
MakeException.description = 'Make a new custom exception class';
__decorate([
standalone_1.args.string({ description: 'Name of the exception class' }),
__metadata("design:type", String)
], MakeException.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({ description: 'Add the handle method to self handle the exception' }),
__metadata("design:type", Boolean)
], MakeException.prototype, "selfHandle", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the exception class with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeException.prototype, "exact", void 0);
exports.default = MakeException;
@@ -0,0 +1,30 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new event listener class
*/
export default class MakeListener extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected form: "singular";
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
exact: boolean;
/**
* Returns the template stub
*/
protected getStub(): string;
/**
* Pull path from the `listeners` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Listeners`
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
+70
View File
@@ -0,0 +1,70 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new event listener class
*/
class MakeListener extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.form = 'singular';
this.pattern = 'pascalcase';
}
/**
* Returns the template stub
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'event-listener.txt');
}
/**
* Pull path from the `listeners` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Listeners`
*/
getDestinationPath() {
return this.getPathForNamespace('eventListeners') || 'app/Listeners';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeListener.commandName = 'make:listener';
MakeListener.description = 'Make a new event listener class';
__decorate([
standalone_1.args.string({ description: 'Name of the event listener class' }),
__metadata("design:type", String)
], MakeListener.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the listener with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeListener.prototype, "exact", void 0);
exports.default = MakeListener;
@@ -0,0 +1,31 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new middleware
*/
export default class MakeMiddleware extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected suffix: string;
protected form: "singular";
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
exact: boolean;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* Middleware are always created inside `app/Middleware` directory.
* We can look into configuring it later.
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
@@ -0,0 +1,87 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new middleware
*/
class MakeMiddleware extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.suffix = '';
this.form = 'singular';
this.pattern = 'pascalcase';
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'middleware.txt');
}
/**
* Middleware are always created inside `app/Middleware` directory.
* We can look into configuring it later.
*/
getDestinationPath() {
return this.getPathForNamespace('middleware') || 'app/Middleware';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
const middlewareNamespace = this.application.rcFile.namespaces.middleware || 'App/Middleware';
const file = await super.generate();
if (!file) {
return;
}
const fileJSON = file.toJSON();
if (fileJSON.state === 'persisted') {
this.ui
.instructions()
.heading('Register middleware')
.add(`Open ${this.colors.cyan('start/kernel.ts')} file`)
.add(`Register the following function as a global or a named middleware`)
.add(this.colors
.cyan()
.underline(`() => import('${middlewareNamespace}/${fileJSON.filename}')`))
.render();
}
}
}
/**
* Command meta data
*/
MakeMiddleware.commandName = 'make:middleware';
MakeMiddleware.description = 'Make a new middleware';
__decorate([
standalone_1.args.string({ description: 'Name of the middleware class' }),
__metadata("design:type", String)
], MakeMiddleware.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the middleware with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeMiddleware.prototype, "exact", void 0);
exports.default = MakeMiddleware;
@@ -0,0 +1,38 @@
import { BaseGenerator } from './Base';
import type { AppEnvironments } from '@ioc:Adonis/Core/Application';
/**
* Command to make a new preloaded file
*/
export default class MakePreloadFile extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected resourceName: string;
protected createExact: boolean;
/**
* Command name
*/
static commandName: string;
/**
* Command description
*/
static description: string;
name: string;
environment: AppEnvironments[];
/**
* Check if the mentioned environments are valid
*/
private isValidEnviroment;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* Path to the start directory
*/
protected getDestinationPath(): string;
/**
* Run command
*/
run(): Promise<void>;
}
@@ -0,0 +1,157 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const slash_1 = __importDefault(require("slash"));
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
const ALLOWED_ENVIRONMENTS = ['console', 'web', 'repl', 'test'];
/**
* Command to make a new preloaded file
*/
class MakePreloadFile extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
this.createExact = true;
}
/**
* Check if the mentioned environments are valid
*/
isValidEnviroment(environment) {
return !environment.find((one) => !ALLOWED_ENVIRONMENTS.includes(one));
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'preload-file.txt');
}
/**
* Path to the start directory
*/
getDestinationPath() {
return this.application.rcFile.directories.start || 'start';
}
/**
* Run command
*/
async run() {
/**
* Ensure the environments are valid when provided via flag
*/
if (this.environment && this.environment.length && !this.isValidEnviroment(this.environment)) {
this.logger.error(`Invalid environment(s) "${this.environment}". Only "${ALLOWED_ENVIRONMENTS}" are allowed`);
return;
}
let environments = this.environment;
/**
* Prompt user to select one or more environments
*/
if (!environments) {
environments = await this.prompt.multiple('Select the environment(s) in which you want to load this file', [
{
name: 'all',
message: 'Load file in all environments',
},
{
name: 'console',
message: 'Environment for ace commands',
},
{
name: 'repl',
message: 'Environment for the REPL session',
},
{
name: 'web',
message: 'Environment for HTTP requests',
},
{
name: 'test',
message: 'Environment for the test process',
},
]);
}
/**
* Generate resource file
*/
this.resourceName = this.name;
const file = await super.generate();
if (!file) {
return;
}
/**
* Update preload file
*/
const { files } = await Promise.resolve().then(() => __importStar(require('@adonisjs/sink')));
const relativePath = file.toJSON().relativepath;
const rcFile = new files.AdonisRcFile(this.application.appRoot);
if (!environments || !environments.length || environments.includes('all')) {
rcFile.setPreload(`./${(0, slash_1.default)(relativePath).replace((0, path_1.extname)(relativePath), '')}`);
}
else {
rcFile.setPreload(`./${(0, slash_1.default)(relativePath).replace((0, path_1.extname)(relativePath), '')}`, environments);
}
rcFile.commit();
}
}
/**
* Command name
*/
MakePreloadFile.commandName = 'make:prldfile';
/**
* Command description
*/
MakePreloadFile.description = 'Make a new preload file';
__decorate([
standalone_1.args.string({ description: 'Name of the file' }),
__metadata("design:type", String)
], MakePreloadFile.prototype, "name", void 0);
__decorate([
standalone_1.flags.array({
description: `Define the preload file environment. Accepted values "${ALLOWED_ENVIRONMENTS}"`,
}),
__metadata("design:type", Array)
], MakePreloadFile.prototype, "environment", void 0);
exports.default = MakePreloadFile;
@@ -0,0 +1,31 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new provider
*/
export default class MakeProvider extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected suffix: string;
protected form: "singular";
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
ace: boolean;
exact: boolean;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* Path to the providers directory
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
+114
View File
@@ -0,0 +1,114 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const slash_1 = __importDefault(require("slash"));
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new provider
*/
class MakeProvider extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.suffix = 'Provider';
this.form = 'singular';
this.pattern = 'pascalcase';
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'provider.txt');
}
/**
* Path to the providers directory
*/
getDestinationPath() {
return this.application.rcFile.directories.providers || 'providers';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
const file = await super.generate();
if (!file) {
return;
}
const { files } = await Promise.resolve().then(() => __importStar(require('@adonisjs/sink')));
const relativePath = file.toJSON().relativepath;
const rcFile = new files.AdonisRcFile(this.application.appRoot);
if (this.ace) {
rcFile.addAceProvider(`./${(0, slash_1.default)(relativePath).replace((0, path_1.extname)(relativePath), '')}`);
}
else {
rcFile.addProvider(`./${(0, slash_1.default)(relativePath).replace((0, path_1.extname)(relativePath), '')}`);
}
rcFile.commit();
}
}
/**
* Command meta data
*/
MakeProvider.commandName = 'make:provider';
MakeProvider.description = 'Make a new provider class';
__decorate([
standalone_1.args.string({ description: 'Name of the provider class' }),
__metadata("design:type", String)
], MakeProvider.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({ description: 'Register provider under the ace providers array' }),
__metadata("design:type", Boolean)
], MakeProvider.prototype, "ace", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the provider with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeProvider.prototype, "exact", void 0);
exports.default = MakeProvider;
+41
View File
@@ -0,0 +1,41 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Create a new test suite
*/
export default class CreateSuite extends BaseCommand {
static commandName: string;
static description: string;
/**
* Name of the test suite to be created
*/
suite: string;
/**
* Glob pattern for the test suite, or only location to the test suite
*/
location: string;
/**
* Should add a sample test file
*/
withExampleTest: boolean;
/**
* Get the destination path for the sample test file
*/
private getExampleTestDestinationPath;
/**
* Generate suite glob pattern based on `location` argument
*/
private generateSuiteGlobPattern;
/**
* Check if the suite name is already defined in RcFile
*/
private checkIfSuiteExists;
/**
* Add the new test suite to the AdonisRC File and save it
*/
private addSuiteToRcFile;
/**
* Add a sample test file to the new suite folder
*/
private createSampleTestFile;
run(): Promise<void>;
}
+120
View File
@@ -0,0 +1,120 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const standalone_1 = require("@adonisjs/core/build/standalone");
const sink_1 = require("@adonisjs/sink");
const glob_parent_1 = __importDefault(require("glob-parent"));
const path_1 = require("path");
/**
* Create a new test suite
*/
class CreateSuite extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
/**
* Glob pattern for the test suite, or only location to the test suite
*/
this.location = '';
/**
* Should add a sample test file
*/
this.withExampleTest = true;
}
/**
* Get the destination path for the sample test file
*/
getExampleTestDestinationPath() {
return (0, glob_parent_1.default)(this.location) + '/test.spec.ts';
}
/**
* Generate suite glob pattern based on `location` argument
*/
generateSuiteGlobPattern() {
if (!this.location) {
this.location = `tests/${this.suite}`;
}
if (!['*', '.js', '.ts'].find((keyword) => this.location.includes(keyword))) {
this.location = `${this.location}/**/*.spec(.ts|.js)`;
}
}
/**
* Check if the suite name is already defined in RcFile
*/
checkIfSuiteExists(rcFile) {
const existingSuites = rcFile.get('tests.suites') || [];
const existingSuitesNames = existingSuites.map((suite) => suite.name);
return existingSuitesNames.includes(this.suite);
}
/**
* Add the new test suite to the AdonisRC File and save it
*/
async addSuiteToRcFile() {
const rcFile = new sink_1.files.AdonisRcFile(this.application.appRoot);
const existingSuites = rcFile.get('tests.suites') || [];
if (this.checkIfSuiteExists(rcFile)) {
return sink_1.logger.action('update').skipped(`Suite ${this.suite} already exists`);
}
rcFile.set('tests.suites', [
...existingSuites,
{
name: this.suite,
files: [this.location],
timeout: 60 * 1000,
},
]);
rcFile.commit();
sink_1.logger.action('update').succeeded('.adonisrc.json');
}
/**
* Add a sample test file to the new suite folder
*/
createSampleTestFile() {
const path = this.getExampleTestDestinationPath();
const testFile = new sink_1.files.MustacheFile(this.application.appRoot, path, (0, path_1.join)(__dirname, '../..', 'templates/test.txt'));
if (!testFile.exists()) {
testFile.apply({}).commit();
sink_1.logger.action('create').succeeded(path);
}
}
async run() {
this.generateSuiteGlobPattern();
await this.addSuiteToRcFile();
if (this.withExampleTest) {
this.createSampleTestFile();
}
}
}
CreateSuite.commandName = 'make:suite';
CreateSuite.description = 'Create a new test suite';
__decorate([
standalone_1.args.string({ description: 'Name of the test suite' }),
__metadata("design:type", String)
], CreateSuite.prototype, "suite", void 0);
__decorate([
standalone_1.args.string({ description: 'Path to the test suite directory', required: false }),
__metadata("design:type", String)
], CreateSuite.prototype, "location", void 0);
__decorate([
standalone_1.flags.boolean({ description: 'Add a sample test file' }),
__metadata("design:type", Boolean)
], CreateSuite.prototype, "withExampleTest", void 0);
exports.default = CreateSuite;
+35
View File
@@ -0,0 +1,35 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new test
*/
export default class MakeTest extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected extname: string;
protected form: "singular";
protected pattern: "snakecase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
suite: string;
name: string;
exact: boolean;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* The file is created inside the parent directory of the first
* glob pattern
*/
protected getDestinationPath(): string;
protected templateData(): {
name: string;
};
run(): Promise<void>;
}
+96
View File
@@ -0,0 +1,96 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const glob_parent_1 = __importDefault(require("glob-parent"));
const helpers_1 = require("@poppinss/utils/build/helpers");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new test
*/
class MakeTest extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.extname = '.spec.ts';
this.form = 'singular';
this.pattern = 'snakecase';
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'test.txt');
}
/**
* The file is created inside the parent directory of the first
* glob pattern
*/
getDestinationPath() {
const testSuites = this.application.rcFile.tests.suites;
const mentionedSuite = testSuites.find(({ name }) => this.suite === name);
const suiteGlob = Array.isArray(mentionedSuite.files)
? mentionedSuite.files[0]
: mentionedSuite.files;
return (0, glob_parent_1.default)(suiteGlob);
}
templateData() {
return {
name: helpers_1.string.sentenceCase(this.name),
};
}
async run() {
const testSuites = this.application.rcFile.tests.suites;
const mentionedSuite = testSuites.find(({ name }) => this.suite === name);
if (!mentionedSuite) {
this.logger.error(`Invalid suite "${this.suite}". Make sure the suite is registered inside the .adonisrc.json file`);
return;
}
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeTest.commandName = 'make:test';
MakeTest.description = 'Make a new test';
__decorate([
standalone_1.args.string({ description: 'Name of the test suite' }),
__metadata("design:type", String)
], MakeTest.prototype, "suite", void 0);
__decorate([
standalone_1.args.string({ description: 'Name of the test file' }),
__metadata("design:type", String)
], MakeTest.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the test file with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeTest.prototype, "exact", void 0);
exports.default = MakeTest;
@@ -0,0 +1,31 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new validator
*/
export default class MakeValidator extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected suffix: string;
protected form: "singular";
protected pattern: "pascalcase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
exact: boolean;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* Pull path for the `validators` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Validators`
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
@@ -0,0 +1,71 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new validator
*/
class MakeValidator extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.suffix = 'Validator';
this.form = 'singular';
this.pattern = 'pascalcase';
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'validator.txt');
}
/**
* Pull path for the `validators` directory declaration from
* the `.adonisrc.json` file or fallback to `app/Validators`
*/
getDestinationPath() {
return this.getPathForNamespace('validators') || 'app/Validators';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeValidator.commandName = 'make:validator';
MakeValidator.description = 'Make a new validator';
__decorate([
standalone_1.args.string({ description: 'Name of the validator class' }),
__metadata("design:type", String)
], MakeValidator.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the validator with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeValidator.prototype, "exact", void 0);
exports.default = MakeValidator;
+30
View File
@@ -0,0 +1,30 @@
import { BaseGenerator } from './Base';
/**
* Command to make a new view
*/
export default class MakeView extends BaseGenerator {
/**
* Required by BaseGenerator
*/
protected suffix: string;
protected extname: string;
protected pattern: "snakecase";
protected resourceName: string;
protected createExact: boolean;
/**
* Command meta data
*/
static commandName: string;
static description: string;
name: string;
exact: boolean;
/**
* Returns the template stub path
*/
protected getStub(): string;
/**
* Path to the providers directory
*/
protected getDestinationPath(): string;
run(): Promise<void>;
}
+70
View File
@@ -0,0 +1,70 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const standalone_1 = require("@adonisjs/core/build/standalone");
const Base_1 = require("./Base");
/**
* Command to make a new view
*/
class MakeView extends Base_1.BaseGenerator {
constructor() {
super(...arguments);
/**
* Required by BaseGenerator
*/
this.suffix = '';
this.extname = '.edge';
this.pattern = 'snakecase';
}
/**
* Returns the template stub path
*/
getStub() {
return (0, path_1.join)(__dirname, '..', '..', 'templates', 'view.txt');
}
/**
* Path to the providers directory
*/
getDestinationPath() {
return this.application.rcFile.directories.views || 'resources/views';
}
async run() {
this.resourceName = this.name;
this.createExact = this.exact;
await super.generate();
}
}
/**
* Command meta data
*/
MakeView.commandName = 'make:view';
MakeView.description = 'Make a new view template';
__decorate([
standalone_1.args.string({ description: 'Name of the view' }),
__metadata("design:type", String)
], MakeView.prototype, "name", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Create the template file with the exact name as provided',
alias: 'e',
}),
__metadata("design:type", Boolean)
], MakeView.prototype, "exact", void 0);
exports.default = MakeView;
+33
View File
@@ -0,0 +1,33 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Compile typescript project to Javascript and start
* the HTTP server
*/
export default class Serve extends BaseCommand {
static commandName: string;
static description: string;
static settings: {
stayAlive: boolean;
};
/**
* Bundle frontend assets. Defaults to true
*/
assets: boolean;
/**
* Allows watching for file changes
*/
watch: boolean;
/**
* Detect changes by polling files
*/
poll: boolean;
/**
* Arguments to pass to the `node` binary
*/
nodeArgs: string[];
/**
* Arguments to pass to the `encore` binary
*/
encoreArgs: string[];
run(): Promise<void>;
}
+112
View File
@@ -0,0 +1,112 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const standalone_1 = require("@adonisjs/core/build/standalone");
/**
* Compile typescript project to Javascript and start
* the HTTP server
*/
class Serve extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
/**
* Bundle frontend assets. Defaults to true
*/
this.assets = true;
/**
* Arguments to pass to the `node` binary
*/
this.nodeArgs = [];
/**
* Arguments to pass to the `encore` binary
*/
this.encoreArgs = [];
}
async run() {
const { DevServer } = await Promise.resolve().then(() => __importStar(require('../src/DevServer')));
try {
if (this.watch) {
await new DevServer(this.application.appRoot, this.nodeArgs, this.encoreArgs, this.assets, this.logger).watch(this.poll);
}
else {
await new DevServer(this.application.appRoot, this.nodeArgs, this.encoreArgs, this.assets, this.logger).start();
}
}
catch (error) {
this.logger.fatal(error);
}
}
}
Serve.commandName = 'serve';
Serve.description = 'Start the AdonisJS HTTP server, along with the file watcher. Also starts the webpack dev server when webpack encore is installed';
Serve.settings = {
stayAlive: true,
};
__decorate([
standalone_1.flags.boolean({
description: 'Start webpack dev server when encore is installed. Use "--no-assets" to disable',
}),
__metadata("design:type", Boolean)
], Serve.prototype, "assets", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Watch for file changes and re-start the HTTP server on change',
alias: 'w',
}),
__metadata("design:type", Boolean)
], Serve.prototype, "watch", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Detect file changes by polling files instead of listening to filesystem events',
alias: 'p',
}),
__metadata("design:type", Boolean)
], Serve.prototype, "poll", void 0);
__decorate([
standalone_1.flags.array({ description: 'CLI options to pass to the node command line' }),
__metadata("design:type", Array)
], Serve.prototype, "nodeArgs", void 0);
__decorate([
standalone_1.flags.array({ description: 'CLI options to pass to the encore command line' }),
__metadata("design:type", Array)
], Serve.prototype, "encoreArgs", void 0);
exports.default = Serve;
+57
View File
@@ -0,0 +1,57 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* Run tests
*/
export default class Test extends BaseCommand {
static commandName: string;
static description: string;
static settings: {
stayAlive: boolean;
};
suites: string[];
/**
* Allows watching for file changes
*/
files: string[];
/**
* Allows watching for file changes
*/
watch: boolean;
/**
* Detect changes by polling files
*/
poll: boolean;
/**
* Arguments to pass to the `node` binary
*/
nodeArgs: string[];
/**
* Filter by tags
*/
tags: string[];
/**
* Filter by tags
*/
ignoreTags: string[];
/**
* Filter by test title
*/
tests: string[];
/**
* Filter by group title
*/
groups: string[];
/**
* Customize tests timeout
*/
timeout: number;
/**
* Force exit the tests runner
*/
forceExit: boolean;
/**
* Convert command flags to test filters
*/
private getTestFilters;
run(): Promise<void>;
}
+159
View File
@@ -0,0 +1,159 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const standalone_1 = require("@adonisjs/core/build/standalone");
/**
* Run tests
*/
class Test extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
/**
* Arguments to pass to the `node` binary
*/
this.nodeArgs = [];
}
/**
* Convert command flags to test filters
*/
getTestFilters() {
const filters = {};
if (this.forceExit) {
filters['--force-exit'] = true;
}
if (this.files) {
filters['--files'] = this.files;
}
if (this.timeout !== undefined) {
filters['--timeout'] = this.timeout;
}
if (this.tags) {
filters['--tags'] = this.tags;
}
if (this.suites) {
filters._ = this.suites;
}
if (this.ignoreTags) {
filters['--ignore-tags'] = this.ignoreTags;
}
if (this.tests) {
filters['--tests'] = this.tests;
}
if (this.groups) {
filters['--groups'] = this.groups;
}
return filters;
}
async run() {
const { TestsServer } = await Promise.resolve().then(() => __importStar(require('../src/Test')));
try {
if (this.watch) {
await new TestsServer(this.application.appRoot, this.getTestFilters(), this.nodeArgs, this.logger).watch();
}
else {
await new TestsServer(this.application.appRoot, this.getTestFilters(), this.nodeArgs, this.logger).run();
}
}
catch (error) {
this.exitCode = 1;
this.logger.fatal(error);
}
}
}
Test.commandName = 'test';
Test.description = 'Run AdonisJS tests';
Test.settings = {
stayAlive: true,
};
__decorate([
standalone_1.args.spread({ description: 'Run tests for only the specified suites', required: false }),
__metadata("design:type", Array)
], Test.prototype, "suites", void 0);
__decorate([
standalone_1.flags.array({
description: 'Run tests for the mentioned files only',
}),
__metadata("design:type", Array)
], Test.prototype, "files", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Watch for file changes and re-run tests on file change',
alias: 'w',
}),
__metadata("design:type", Boolean)
], Test.prototype, "watch", void 0);
__decorate([
standalone_1.flags.boolean({
description: 'Detect file changes by polling files instead of listening to filesystem events',
alias: 'p',
}),
__metadata("design:type", Boolean)
], Test.prototype, "poll", void 0);
__decorate([
standalone_1.flags.array({ description: 'CLI options to pass to the node command line' }),
__metadata("design:type", Array)
], Test.prototype, "nodeArgs", void 0);
__decorate([
standalone_1.flags.array({ description: 'Filter tests by tags' }),
__metadata("design:type", Array)
], Test.prototype, "tags", void 0);
__decorate([
standalone_1.flags.array({ description: 'Filter tests by ignoring tags' }),
__metadata("design:type", Array)
], Test.prototype, "ignoreTags", void 0);
__decorate([
standalone_1.flags.array({ description: 'Filter tests by title' }),
__metadata("design:type", Array)
], Test.prototype, "tests", void 0);
__decorate([
standalone_1.flags.array({ description: 'Filter tests by group title' }),
__metadata("design:type", Array)
], Test.prototype, "groups", void 0);
__decorate([
standalone_1.flags.number({ description: 'Customize tests timeout' }),
__metadata("design:type", Number)
], Test.prototype, "timeout", void 0);
__decorate([
standalone_1.flags.boolean({ description: 'Force exit the tests runner process' }),
__metadata("design:type", Boolean)
], Test.prototype, "forceExit", void 0);
exports.default = Test;
+16
View File
@@ -0,0 +1,16 @@
import { BaseCommand } from '@adonisjs/core/build/standalone';
/**
* TypeCheck project without writing the compiled output to the disk
*/
export default class TypeCheck extends BaseCommand {
static commandName: string;
static description: string;
/**
* Path to the TypeScript project configuration file. Defaults to "tsconfig.json"
*/
tsconfig: string;
/**
* Invoked automatically by ace
*/
run(): Promise<void>;
}
+85
View File
@@ -0,0 +1,85 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
const standalone_1 = require("@adonisjs/core/build/standalone");
const paths_1 = require("../config/paths");
/**
* TypeCheck project without writing the compiled output to the disk
*/
class TypeCheck extends standalone_1.BaseCommand {
constructor() {
super(...arguments);
/**
* Path to the TypeScript project configuration file. Defaults to "tsconfig.json"
*/
this.tsconfig = paths_1.TSCONFIG_FILE_NAME;
}
/**
* Invoked automatically by ace
*/
async run() {
const { Compiler } = await Promise.resolve().then(() => __importStar(require('../src/Compiler')));
try {
const compiler = new Compiler(this.application.appRoot, [], false, this.logger, this.tsconfig);
const success = await compiler.typeCheck();
/**
* Set exitCode based upon the typecheck status
*/
if (!success) {
this.exitCode = 1;
}
}
catch (error) {
this.logger.fatal(error);
this.exitCode = 1;
}
}
}
TypeCheck.commandName = 'type-check';
TypeCheck.description = 'Type check TypeScript source without writing the compiled output on disk';
__decorate([
standalone_1.flags.string({
description: 'Path to the TypeScript project configuration file',
}),
__metadata("design:type", String)
], TypeCheck.prototype, "tsconfig", void 0);
exports.default = TypeCheck;
+7
View File
@@ -0,0 +1,7 @@
export declare const ACE_FILE_NAME = "ace";
export declare const DEFAULT_BUILD_DIR = "build";
export declare const RCFILE_NAME = ".adonisrc.json";
export declare const ENV_FILES: string[];
export declare const SERVER_ENTRY_FILE = "server.ts";
export declare const TESTS_ENTRY_FILE = "test.ts";
export declare const TSCONFIG_FILE_NAME = "tsconfig.json";
+18
View File
@@ -0,0 +1,18 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TSCONFIG_FILE_NAME = exports.TESTS_ENTRY_FILE = exports.SERVER_ENTRY_FILE = exports.ENV_FILES = exports.RCFILE_NAME = exports.DEFAULT_BUILD_DIR = exports.ACE_FILE_NAME = void 0;
exports.ACE_FILE_NAME = 'ace';
exports.DEFAULT_BUILD_DIR = 'build';
exports.RCFILE_NAME = '.adonisrc.json';
exports.ENV_FILES = ['.env', '.env.testing'];
exports.SERVER_ENTRY_FILE = 'server.ts';
exports.TESTS_ENTRY_FILE = 'test.ts';
exports.TSCONFIG_FILE_NAME = 'tsconfig.json';
+1
View File
@@ -0,0 +1 @@
export {};
+15
View File
@@ -0,0 +1,15 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const requireHook_1 = __importDefault(require("./src/requireHook"));
(0, requireHook_1.default)(process.env.ADONIS_ACE_CWD || process.cwd());
@@ -0,0 +1,76 @@
import Emittery from 'emittery';
import { logger as uiLogger } from '@poppinss/cliui';
export type DevServerResponse = {
state: 'not-installed' | 'no-assets';
} | {
state: 'running';
port: string;
host: string;
};
/**
* Assets bundler uses webpack encore to build frontend dependencies
*/
export declare class AssetsBundler extends Emittery {
private projectRoot;
private buildAssets;
private logger;
private env;
/**
* Binary to execute
*/
private binaryName;
private encoreArgs;
/**
* Options passed to spawn a child process
*/
private execaOptions;
constructor(projectRoot: string, encoreArgs: string[] | undefined, buildAssets: boolean, logger: typeof uiLogger, env?: {
[key: string]: string;
});
/**
* Find if encore is installed
*/
private isEncoreInstalled;
/**
* Notify user that we are about use encore
*/
private notifyAboutEncore;
/**
* Logs the line to stdout
*/
private log;
/**
* Logs the line to stderr
*/
private logError;
/**
* Returns the custom port defined using the `--port` flag in encore
* flags
*/
private findCustomPort;
/**
* Returns the custom host defined using the `--host` flag in encore
* flags
*/
private findCustomHost;
/**
* Execute command
*/
private exec;
/**
* Build assets using encore
*/
build(): Promise<{
hasErrors: boolean;
}>;
/**
* Build assets for production
*/
buildForProduction(): Promise<{
hasErrors: boolean;
}>;
/**
* Start the webpack dev server
*/
startDevServer(): Promise<DevServerResponse>;
}
+216
View File
@@ -0,0 +1,216 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetsBundler = void 0;
const execa_1 = __importDefault(require("execa"));
const get_port_1 = __importDefault(require("get-port"));
const emittery_1 = __importDefault(require("emittery"));
const helpers_1 = require("@poppinss/utils/build/helpers");
/**
* Assets bundler uses webpack encore to build frontend dependencies
*/
class AssetsBundler extends emittery_1.default {
constructor(projectRoot, encoreArgs = [], buildAssets = true, logger, env = {}) {
super();
this.projectRoot = projectRoot;
this.buildAssets = buildAssets;
this.logger = logger;
this.env = env;
/**
* Binary to execute
*/
this.binaryName = 'encore';
this.encoreArgs = [];
/**
* Options passed to spawn a child process
*/
this.execaOptions = {
preferLocal: true,
buffer: false,
stdio: 'pipe',
localDir: this.projectRoot,
cwd: this.projectRoot,
windowsHide: false,
env: {
FORCE_COLOR: 'true',
...this.env,
},
};
this.encoreArgs = encoreArgs.reduce((result, arg) => {
result = result.concat(arg.split(' '));
return result;
}, []);
}
/**
* Find if encore is installed
*/
isEncoreInstalled() {
try {
(0, helpers_1.resolveDir)(this.projectRoot, '@symfony/webpack-encore');
return true;
}
catch {
return false;
}
}
/**
* Notify user that we are about use encore
*/
notifyAboutEncore() {
this.logger.info(`detected { ${this.logger.colors.dim().yellow('@symfony/webpack-encore')} }`);
this.logger.info(`building frontend assets. Use { ${this.logger.colors
.dim()
.yellow('--no-assets')} } to disable`);
}
/**
* Logs the line to stdout
*/
log(line) {
line = line.toString().trim();
if (!line.length) {
return;
}
console.log(`[ ${this.logger.colors.cyan('encore')} ] ${line}`);
}
/**
* Logs the line to stderr
*/
logError(line) {
line = line.toString().trim();
if (!line.length) {
return;
}
console.error(`[ ${this.logger.colors.cyan('encore')} ] ${line}`);
}
/**
* Returns the custom port defined using the `--port` flag in encore
* flags
*/
findCustomPort() {
let portIndex = this.encoreArgs.findIndex((arg) => arg === '--port');
if (portIndex > -1) {
return this.encoreArgs[portIndex + 1];
}
portIndex = this.encoreArgs.findIndex((arg) => arg.includes('--port'));
if (portIndex > -1) {
const tokens = this.encoreArgs[portIndex].split('=');
return tokens[1] && tokens[1].trim();
}
}
/**
* Returns the custom host defined using the `--host` flag in encore
* flags
*/
findCustomHost() {
let hostIndex = this.encoreArgs.findIndex((arg) => arg === '--host');
if (hostIndex > -1) {
return this.encoreArgs[hostIndex + 1];
}
hostIndex = this.encoreArgs.findIndex((arg) => arg.includes('--host'));
if (hostIndex > -1) {
const tokens = this.encoreArgs[hostIndex].split('=');
return tokens[1] && tokens[1].trim();
}
}
/**
* Execute command
*/
exec(args) {
return new Promise((resolve, reject) => {
const childProcess = (0, execa_1.default)(this.binaryName, args, this.execaOptions);
childProcess.stdout?.on('data', (line) => this.log(line));
childProcess.stderr?.on('data', (line) => this.logError(line));
childProcess.on('error', (error) => reject(error));
childProcess.on('close', (code) => {
if (code && code !== 0) {
reject(`Process exited with code ${code}`);
}
else {
resolve();
}
});
});
}
/**
* Build assets using encore
*/
async build() {
if (!this.buildAssets) {
return { hasErrors: false };
}
if (!this.isEncoreInstalled()) {
return { hasErrors: false };
}
this.notifyAboutEncore();
try {
await this.exec(['dev'].concat(this.encoreArgs));
return { hasErrors: false };
}
catch (error) {
return { hasErrors: true };
}
}
/**
* Build assets for production
*/
async buildForProduction() {
if (!this.buildAssets) {
return { hasErrors: false };
}
if (!this.isEncoreInstalled()) {
return { hasErrors: false };
}
this.notifyAboutEncore();
try {
await this.exec(['production'].concat(this.encoreArgs));
return { hasErrors: false };
}
catch (error) {
return { hasErrors: true };
}
}
/**
* Start the webpack dev server
*/
async startDevServer() {
if (!this.isEncoreInstalled()) {
return { state: 'not-installed' };
}
if (!this.buildAssets) {
return { state: 'no-assets' };
}
const customHost = this.findCustomHost() || 'localhost';
/**
* Define a random port when the "--port" flag is not passed.
*
* Encore anyways doesn't allow defining port inside the webpack.config.js
* file for generating the manifest and entrypoints file.
*
* @see
* https://github.com/symfony/webpack-encore/issues/941#issuecomment-787568811
*/
let customPort = this.findCustomPort();
if (!customPort) {
const randomPort = await (0, get_port_1.default)({ port: 8080, host: 'localhost' });
customPort = String(randomPort);
this.encoreArgs.push('--port', customPort);
}
const childProcess = (0, execa_1.default)(this.binaryName, ['dev-server'].concat(this.encoreArgs), this.execaOptions);
childProcess.stdout?.on('data', (line) => this.log(line));
childProcess.stderr?.on('data', (line) => this.logError(line));
childProcess.on('close', (code, signal) => this.emit('close', { code, signal }));
childProcess.on('exit', (code, signal) => this.emit('exit', { code, signal }));
return { state: 'running', port: customPort, host: customHost };
}
}
exports.AssetsBundler = AssetsBundler;
+62
View File
@@ -0,0 +1,62 @@
import { logger as uiLogger } from '@poppinss/cliui';
/**
* Exposes the API to build the AdonisJs project for development or
* production. The production build has it's own set of node_modules
*/
export declare class Compiler {
appRoot: string;
private encoreArgs;
private buildAssets;
private logger;
/**
* Reference to typescript compiler
*/
private ts;
/**
* Reference to rc File
*/
private rcFile;
constructor(appRoot: string, encoreArgs: string[], buildAssets: boolean, logger?: typeof uiLogger, tsconfig?: string);
/**
* Returns relative unix path from the project root. Used for
* display only
*/
private getRelativeUnixPath;
/**
* Cleans up the build directory
*/
private cleanupBuildDirectory;
/**
* Copies .adonisrc.json file to the destination
*/
private copyAdonisRcFile;
/**
* Copy all meta files to the build directory
*/
private copyMetaFiles;
/**
* Copy files to destination directory
*/
private copyFiles;
/**
* Build typescript source files
*/
private buildTypescriptSource;
/**
* Log the message that ts build and failed
*/
private logTsBuildFailed;
/**
* Typecheck the project without emit
*/
typeCheck(): Promise<boolean>;
/**
* Compile project. See [[Compiler.compileForProduction]] for
* production build
*/
compile(stopOnError?: boolean, extraFiles?: string[]): Promise<boolean>;
/**
* Compile project. See [[Compiler.compile]] for development build
*/
compileForProduction(stopOnError: boolean | undefined, client: 'npm' | 'yarn'): Promise<boolean>;
}
+287
View File
@@ -0,0 +1,287 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Compiler = void 0;
const slash_1 = __importDefault(require("slash"));
const cpy_1 = __importDefault(require("cpy"));
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const ioc_transformer_1 = require("@adonisjs/ioc-transformer");
const cliui_1 = require("@poppinss/cliui");
const Ts_1 = require("../Ts");
const RcFile_1 = require("../RcFile");
const Manifest_1 = require("../Manifest");
const paths_1 = require("../../config/paths");
const AssetsBundler_1 = require("../AssetsBundler");
/**
* Exposes the API to build the AdonisJs project for development or
* production. The production build has it's own set of node_modules
*/
class Compiler {
constructor(appRoot, encoreArgs, buildAssets, logger = cliui_1.logger, tsconfig) {
this.appRoot = appRoot;
this.encoreArgs = encoreArgs;
this.buildAssets = buildAssets;
this.logger = logger;
/**
* Reference to rc File
*/
this.rcFile = new RcFile_1.RcFile(this.appRoot);
this.ts = new Ts_1.Ts(this.appRoot, this.logger, tsconfig);
this.ts.tsCompiler.use(() => {
return (0, ioc_transformer_1.iocTransformer)(this.ts.tsCompiler.ts, this.rcFile.application.rcFile);
}, 'after');
}
/**
* Returns relative unix path from the project root. Used for
* display only
*/
getRelativeUnixPath(absPath) {
return (0, slash_1.default)((0, path_1.relative)(this.appRoot, absPath));
}
/**
* Cleans up the build directory
*/
async cleanupBuildDirectory(outDir) {
this.getRelativeUnixPath(outDir);
this.logger.info(`cleaning up ${this.logger.colors
.dim()
.yellow(`"./${this.getRelativeUnixPath(outDir)}"`)} directory`);
await (0, fs_extra_1.remove)(outDir);
}
/**
* Copies .adonisrc.json file to the destination
*/
async copyAdonisRcFile(outDir) {
this.logger.info(`copy { ${this.logger.colors
.dim()
.yellow(`${paths_1.RCFILE_NAME} => ${this.getRelativeUnixPath(outDir)}`)} }`);
await (0, fs_extra_1.outputJSON)((0, path_1.join)(outDir, paths_1.RCFILE_NAME), Object.assign({}, this.rcFile.getDiskContents(), {
typescript: false,
lastCompiledAt: new Date().toISOString(),
}), { spaces: 2 });
}
/**
* Copy all meta files to the build directory
*/
async copyMetaFiles(outDir, extraFiles) {
const metaFiles = this.rcFile.getMetaFilesGlob().concat(extraFiles || []);
this.logger.info(`copy { ${this.logger.colors
.dim()
.yellow(`${metaFiles.join(',')} => ${this.getRelativeUnixPath(outDir)}`)} }`);
await this.copyFiles(metaFiles, outDir);
}
/**
* Copy files to destination directory
*/
async copyFiles(files, outDir) {
try {
await (0, cpy_1.default)(files, outDir, { cwd: this.appRoot, parents: true });
}
catch (error) {
if (!error.message.includes("the file doesn't exist")) {
throw error;
}
}
}
/**
* Build typescript source files
*/
buildTypescriptSource(config) {
this.logger.info('compiling typescript source files');
const builder = this.ts.tsCompiler.builder(config);
const { skipped, diagnostics } = builder.build();
if (skipped) {
this.logger.warning('typescript emit skipped');
}
if (diagnostics.length) {
this.logger.error('typescript compiler errors');
this.ts.renderDiagnostics(diagnostics, builder.host);
}
return {
skipped,
hasErrors: diagnostics.length > 0,
};
}
/**
* Log the message that ts build and failed
*/
logTsBuildFailed() {
this.logger.logError('');
this.logger.logError(this.logger.colors.bgRed(`Cannot complete the build process as there are typescript errors. Use "--ignore-ts-errors" flag to ignore Typescript errors`));
}
/**
* Typecheck the project without emit
*/
async typeCheck() {
const config = this.ts.parseConfig();
if (!config) {
return false;
}
this.logger.info('type checking typescript source files');
config.options.noEmit = true;
const builder = this.ts.tsCompiler.builder(config);
const { diagnostics } = builder.build();
if (diagnostics.length) {
this.logger.error('typescript compiler errors');
this.ts.renderDiagnostics(diagnostics, builder.host);
return false;
}
this.logger.success('built successfully');
return true;
}
/**
* Compile project. See [[Compiler.compileForProduction]] for
* production build
*/
async compile(stopOnError = true, extraFiles) {
const config = this.ts.parseConfig();
if (!config) {
return false;
}
/**
* Bundle frontend assets when encore is installed
*/
const encore = await new AssetsBundler_1.AssetsBundler(this.appRoot, this.encoreArgs, this.buildAssets, this.logger).build();
/**
* Skipped, coz of frontend errors
*/
if (encore.hasErrors) {
return false;
}
/**
* Always cleanup the out directory
*/
await this.cleanupBuildDirectory(config.options.outDir);
/**
* Build typescript source
*/
const ts = this.buildTypescriptSource(config);
/**
* Do not continue when output was skipped
*/
if (ts.skipped) {
return false;
}
/**
* Do not continue when has errors and "stopOnError" is true
*/
if (stopOnError && ts.hasErrors) {
this.logTsBuildFailed();
await this.cleanupBuildDirectory(config.options.outDir);
return false;
}
/**
* Begin by copying meta files
*/
await this.copyMetaFiles(config.options.outDir, extraFiles);
/**
* Copy `.adonisrc.json` file
*/
await this.copyAdonisRcFile(config.options.outDir);
/**
* Manifest instance to generate ace manifest file
*/
const manifest = new Manifest_1.Manifest(config.options.outDir, this.logger);
const created = await manifest.generate();
/**
* Do not continue when unable to generate the manifest file as commands
* won't be available
*/
if (!created) {
await this.cleanupBuildDirectory(config.options.outDir);
return false;
}
this.logger.success('built successfully');
return true;
}
/**
* Compile project. See [[Compiler.compile]] for development build
*/
async compileForProduction(stopOnError = true, client) {
const config = this.ts.parseConfig();
if (!config) {
return false;
}
/**
* Bundle frontend assets when encore is installed
*/
const encore = await new AssetsBundler_1.AssetsBundler(this.appRoot, this.encoreArgs, this.buildAssets, this.logger).buildForProduction();
/**
* Skipped, coz of frontend errors
*/
if (encore.hasErrors) {
return false;
}
const pkgFiles = client === 'npm' ? ['package.json', 'package-lock.json'] : ['package.json', 'yarn.lock'];
/**
* Always cleanup the out directory
*/
await this.cleanupBuildDirectory(config.options.outDir);
/**
* Build typescript source
*/
const { skipped, hasErrors } = this.buildTypescriptSource(config);
/**
* Do not continue when output was skipped
*/
if (skipped) {
return false;
}
/**
* Do not continue when has errors and "stopOnError" is true and cleanup
* the build directory
*/
if (stopOnError && hasErrors) {
this.logTsBuildFailed();
await this.cleanupBuildDirectory(config.options.outDir);
return false;
}
/**
* Begin by copying meta files
*/
await this.copyMetaFiles(config.options.outDir, pkgFiles);
/**
* Copy `.adonisrc.json` file
*/
await this.copyAdonisRcFile(config.options.outDir);
/**
* Generate commands manifest
*/
const manifest = new Manifest_1.Manifest(config.options.outDir, this.logger);
const created = await manifest.generate();
/**
* Do not continue when unable to generate the manifest file as commands
* won't be available
*/
if (!created) {
await this.cleanupBuildDirectory(config.options.outDir);
return false;
}
/**
* Print usage instructions
*/
const installCommand = client === 'npm' ? 'npm ci --production' : 'yarn install --production';
const relativeBuildPath = this.getRelativeUnixPath(config.options.outDir);
this.logger.success('built successfully');
this.logger.log('');
(0, cliui_1.instructions)()
.heading('Run the following commands to start the server in production')
.add(this.logger.colors.cyan(`cd ${relativeBuildPath}`))
.add(this.logger.colors.cyan(installCommand))
.add(this.logger.colors.cyan('node server.js'))
.render();
return true;
}
}
exports.Compiler = Compiler;
@@ -0,0 +1,8 @@
export type JapaFlags = Partial<{
'_': string[];
'--tags': string[];
'--ignore-tags': string[];
'--files': string[];
'--timeout': number;
'--force-exit': boolean;
}>;
+10
View File
@@ -0,0 +1,10 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
+70
View File
@@ -0,0 +1,70 @@
import { logger as uiLogger } from '@poppinss/cliui';
/**
* Exposes the API to watch project for compilition changes.
*/
export declare class DevServer {
private appRoot;
private nodeArgs;
private encoreArgs;
private buildAssets;
private logger;
private httpServer;
/**
* HTTP server port
*/
private serverPort?;
/**
* HTTP server host
*/
private serverHost?;
/**
* Encore dev server host
*/
private encoreDevServerResponse;
/**
* A boolean to know if we are watching for filesystem
*/
private watchingFileSystem;
/**
* Watcher state
*/
private watcherState;
/**
* Reference to the typescript compiler
*/
private ts;
/**
* Reference to the RCFile
*/
private rcFile;
/**
* Manifest instance to generate ace manifest file
*/
private manifest;
/**
* Require-ts watch helpers
*/
private watchHelpers;
constructor(appRoot: string, nodeArgs: string[], encoreArgs: string[], buildAssets: boolean, logger?: typeof uiLogger);
/**
* Kill current process
*/
private kill;
/**
* Create the http server
*/
private createHttpServer;
/**
* Renders box to notify about the server state
*/
private renderServerIsReady;
/**
* Start the dev server. Use [[watch]] to also watch for file
* changes
*/
start(): Promise<void>;
/**
* Build and watch for file changes
*/
watch(poll?: boolean): Promise<void>;
}
+306
View File
@@ -0,0 +1,306 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DevServer = void 0;
const get_port_1 = __importDefault(require("get-port"));
const require_ts_1 = require("@adonisjs/require-ts");
const cliui_1 = require("@poppinss/cliui");
const Ts_1 = require("../Ts");
const RcFile_1 = require("../RcFile");
const Manifest_1 = require("../Manifest");
const EnvParser_1 = require("../EnvParser");
const HttpServer_1 = require("../HttpServer");
const paths_1 = require("../../config/paths");
const AssetsBundler_1 = require("../AssetsBundler");
/**
* Exposes the API to watch project for compilition changes.
*/
class DevServer {
constructor(appRoot, nodeArgs = [], encoreArgs, buildAssets, logger = cliui_1.logger) {
this.appRoot = appRoot;
this.nodeArgs = nodeArgs;
this.encoreArgs = encoreArgs;
this.buildAssets = buildAssets;
this.logger = logger;
/**
* A boolean to know if we are watching for filesystem
*/
this.watchingFileSystem = false;
/**
* Watcher state
*/
this.watcherState = 'pending';
/**
* Reference to the typescript compiler
*/
this.ts = new Ts_1.Ts(this.appRoot, this.logger);
/**
* Reference to the RCFile
*/
this.rcFile = new RcFile_1.RcFile(this.appRoot);
/**
* Manifest instance to generate ace manifest file
*/
this.manifest = new Manifest_1.Manifest(this.appRoot, this.logger);
/**
* Require-ts watch helpers
*/
this.watchHelpers = (0, require_ts_1.getWatcherHelpers)(this.appRoot);
}
/**
* Kill current process
*/
kill() {
this.logger.info('shutting down');
process.exit();
}
/**
* Create the http server
*/
async createHttpServer() {
if (this.httpServer) {
return;
}
const envParser = new EnvParser_1.EnvParser();
await envParser.parse(this.appRoot);
const envOptions = envParser.asEnvObject(['PORT', 'TZ', 'HOST']);
const HOST = process.env.HOST || envOptions.HOST || '0.0.0.0';
let PORT = process.env.PORT || envOptions.PORT || '3333';
/**
* Obtains a random port by giving preference to the one defined inside
* the `.env` file. This eases the process of running the application
* without manually changing ports inside the `.env` file when
* original port is in use.
*/
if (!isNaN(Number(PORT))) {
PORT = String(await (0, get_port_1.default)({
port: [Number(PORT)],
host: HOST,
}));
}
this.httpServer = new HttpServer_1.HttpServer(paths_1.SERVER_ENTRY_FILE, this.appRoot, this.nodeArgs, this.logger, {
PORT,
HOST,
TZ: envOptions.TZ,
});
}
/**
* Renders box to notify about the server state
*/
renderServerIsReady() {
if (!this.serverHost || !this.serverPort) {
return;
}
if (this.watchingFileSystem && this.watcherState === 'pending') {
return;
}
const stickerInstance = (0, cliui_1.sticker)();
stickerInstance
.add(`Server address: ${this.logger.colors.cyan(`http://${this.serverHost === '0.0.0.0' ? '127.0.0.1' : this.serverHost}:${this.serverPort}`)}`)
.add(`Watching filesystem for changes: ${this.logger.colors.cyan(this.watchingFileSystem ? 'YES' : 'NO')}`);
/**
* Running the encore dev server
*/
if (this.encoreDevServerResponse.state === 'running') {
stickerInstance.add(`Encore server address: ${this.logger.colors.cyan(`http://${this.encoreDevServerResponse.host}:${this.encoreDevServerResponse.port}`)}`);
}
stickerInstance.render();
}
/**
* Start the dev server. Use [[watch]] to also watch for file
* changes
*/
async start() {
/**
* Log getting ready
*/
this.logger.info('building project...');
/**
* Start the HTTP server right away
*/
await this.createHttpServer();
this.httpServer.start();
/**
* Notify that the http server has died
*/
this.httpServer.on('exit', ({ code }) => {
this.logger.warning(`Underlying HTTP server died with "${code} code"`);
});
/**
* Notify that the http server is running
*/
this.httpServer.on('ready', ({ port, host }) => {
this.serverPort = port;
this.serverHost = host;
this.renderServerIsReady();
});
const encore = new AssetsBundler_1.AssetsBundler(this.appRoot, this.encoreArgs, this.buildAssets, this.logger);
encore.on('exit', ({ code }) => {
this.logger.warning(`Underlying encore dev server died with "${code} code"`);
});
this.encoreDevServerResponse = await encore.startDevServer();
}
/**
* Build and watch for file changes
*/
async watch(poll = false) {
this.watchingFileSystem = true;
/**
* Clear require-ts cache
*/
this.watchHelpers.clear();
/**
* Start HTTP server
*/
await this.start();
/**
* Parse config to find the files excluded inside
* tsconfig file
*/
const config = this.ts.parseConfig();
if (!config) {
this.logger.warning('Cannot start watcher because of errors in the config file');
this.watcherState = 'error';
this.renderServerIsReady();
return;
}
/**
* Stick file watcher
*/
const watcher = this.ts.tsCompiler.watcher(config, 'raw');
/**
* Watcher is ready after first compile
*/
watcher.on('watcher:ready', () => {
this.logger.info('watching file system for changes');
this.watcherState = 'ready';
this.renderServerIsReady();
});
/**
* Source file removed
*/
watcher.on('source:unlink', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
this.logger.action('delete').succeeded(relativePath);
/**
* Generate manifest when filePath is a commands path
*/
if (this.rcFile.isCommandsPath(relativePath)) {
this.manifest.generate();
}
this.httpServer.restart();
});
/**
* Source file added
*/
watcher.on('source:add', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
this.logger.action('add').succeeded(relativePath);
/**
* Generate manifest when filePath if file is in commands path
*/
if (this.rcFile.isCommandsPath(relativePath)) {
this.manifest.generate();
}
this.httpServer.restart();
});
/**
* Source file changed
*/
watcher.on('source:change', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
this.logger.action('update').succeeded(relativePath);
/**
* Generate manifest when filePath is a commands path
*/
if (this.rcFile.isCommandsPath(relativePath)) {
this.manifest.generate();
}
this.httpServer.restart();
});
/**
* New file added
*/
watcher.on('add', async ({ relativePath }) => {
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('create').succeeded(relativePath);
this.httpServer.restart();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
this.logger.action('create').succeeded(relativePath);
if (metaData.reload) {
this.httpServer.restart();
}
});
/**
* File changed
*/
watcher.on('change', async ({ relativePath }) => {
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('update').succeeded(relativePath);
this.httpServer.restart();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
this.logger.action('update').succeeded(relativePath);
if (metaData.reload || metaData.rcFile) {
this.httpServer.restart();
}
});
/**
* File removed
*/
watcher.on('unlink', async ({ relativePath }) => {
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('delete').succeeded(relativePath);
this.httpServer.restart();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
if (metaData.rcFile) {
this.logger.info('cannot continue after deletion of .adonisrc.json file');
watcher.chokidar.close();
this.kill();
return;
}
this.logger.action('delete').succeeded(relativePath);
if (metaData.reload) {
this.httpServer.restart();
}
});
/**
* Start the watcher
*/
watcher.watch(['.'], {
usePolling: poll,
});
/**
* Kill when watcher recieves an error
*/
watcher.chokidar.on('error', (error) => {
this.logger.fatal(error);
this.kill();
});
}
}
exports.DevServer = DevServer;
+21
View File
@@ -0,0 +1,21 @@
/**
* Parses the env file inside the project root.
*/
export declare class EnvParser {
private envContents;
constructor();
/**
* Parse .env file contents
*/
parse(rootDir: string): Promise<void>;
/**
* Returns value for a key inside the `.env` file
*/
get(key: string): string | undefined;
/**
* Returns an env object for the keys that has defined values
*/
asEnvObject(keys: string[]): {
[key: string]: string;
};
}
+48
View File
@@ -0,0 +1,48 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnvParser = void 0;
const env_1 = require("@adonisjs/env");
/**
* Parses the env file inside the project root.
*/
class EnvParser {
constructor() {
this.envContents = {};
}
/**
* Parse .env file contents
*/
async parse(rootDir) {
const { envContents, testEnvContent } = (0, env_1.envLoader)(rootDir);
const envVars = new env_1.EnvParser(true).parse(envContents);
const testEnvVars = new env_1.EnvParser(true).parse(testEnvContent);
this.envContents = { ...envVars, ...testEnvVars };
}
/**
* Returns value for a key inside the `.env` file
*/
get(key) {
return this.envContents[key];
}
/**
* Returns an env object for the keys that has defined values
*/
asEnvObject(keys) {
return keys.reduce((result, key) => {
const value = this.get(key);
if (value !== undefined) {
result[key] = value;
}
return result;
}, {});
}
}
exports.EnvParser = EnvParser;
+34
View File
@@ -0,0 +1,34 @@
import Emittery from 'emittery';
import { logger as uiLogger } from '@poppinss/cliui';
/**
* Exposes the API to start Node.js HTTP server as a child process. The
* child process is full managed and cleans up when parent process
* dies.
*/
export declare class HttpServer extends Emittery {
private sourceFile;
private projectRoot;
private logger;
private env;
private childProcess?;
private nodeArgs;
constructor(sourceFile: string, projectRoot: string, nodeArgs: string[] | undefined, logger: typeof uiLogger, env?: {
[key: string]: string;
});
/**
* Whether or not the underlying process is connected
*/
get isConnected(): boolean | undefined;
/**
* Start the HTTP server as a child process.
*/
start(): void;
/**
* Stop the underlying process
*/
stop(): void;
/**
* Restart the server by killing the old one
*/
restart(): void;
}
+87
View File
@@ -0,0 +1,87 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpServer = void 0;
const execa_1 = __importDefault(require("execa"));
const emittery_1 = __importDefault(require("emittery"));
/**
* Exposes the API to start Node.js HTTP server as a child process. The
* child process is full managed and cleans up when parent process
* dies.
*/
class HttpServer extends emittery_1.default {
constructor(sourceFile, projectRoot, nodeArgs = [], logger, env = {}) {
super();
this.sourceFile = sourceFile;
this.projectRoot = projectRoot;
this.logger = logger;
this.env = env;
this.nodeArgs = [];
this.nodeArgs = nodeArgs.reduce((result, arg) => {
result = result.concat(arg.split(' '));
return result;
}, []);
}
/**
* Whether or not the underlying process is connected
*/
get isConnected() {
return this.childProcess && this.childProcess.connected && !this.childProcess.killed;
}
/**
* Start the HTTP server as a child process.
*/
start() {
if (this.isConnected) {
throw new Error('Http server is already connected. Call restart instead');
}
this.logger.info(this.childProcess ? 're-starting http server...' : 'starting http server...');
this.childProcess = execa_1.default.node(this.sourceFile, [], {
buffer: false,
stdio: 'inherit',
cwd: this.projectRoot,
env: {
FORCE_COLOR: 'true',
...this.env,
},
nodeOptions: ['-r', '@adonisjs/assembler/build/register'].concat(this.nodeArgs),
});
/**
* Notify about server events
*/
this.childProcess.on('message', (message) => {
if (message && message['isAdonisJS'] && message['environment'] === 'web') {
this.emit('ready', message);
}
});
this.childProcess.on('close', (code, signal) => this.emit('close', { code, signal }));
this.childProcess.on('exit', (code, signal) => this.emit('exit', { code, signal }));
}
/**
* Stop the underlying process
*/
stop() {
if (this.childProcess) {
this.childProcess.removeAllListeners();
this.childProcess.kill('SIGKILL');
}
}
/**
* Restart the server by killing the old one
*/
restart() {
this.stop();
this.start();
}
}
exports.HttpServer = HttpServer;
+32
View File
@@ -0,0 +1,32 @@
import { logger as uiLogger } from '@poppinss/cliui';
/**
* Exposes the API to execute generate manifest file
*/
export declare class Manifest {
private appRoot;
private logger;
/**
* The maximum number of times we should attempt to generate
* the manifest file before giving up.
*
* This number may sound too big, but in real world scanerio, we
* have seen encountered malformed JSON between 10-12 times.
*
* The JSON gets malformed, when a parallel process (node ace serve --watch)
* is trying to update it.
*/
private maxAttempts;
private attempts;
constructor(appRoot: string, logger: typeof uiLogger);
/**
* Returns a boolean telling if the error message is pointing
* towards invalid or empty JSON file read attempt.
*/
private isMalformedJSONError;
/**
* Generates the manifest file. We ignore `generate:manifest` errors for
* now, since it's a secondary task for us and one should run it
* in seperate process to find the actual errors.
*/
generate(): Promise<boolean>;
}
+88
View File
@@ -0,0 +1,88 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Manifest = void 0;
const execa_1 = __importDefault(require("execa"));
const WARN_MESSAGE = [
'Unable to generate manifest file.',
'Check the following error for more info',
].join(' ');
/**
* Exposes the API to execute generate manifest file
*/
class Manifest {
constructor(appRoot, logger) {
this.appRoot = appRoot;
this.logger = logger;
/**
* The maximum number of times we should attempt to generate
* the manifest file before giving up.
*
* This number may sound too big, but in real world scanerio, we
* have seen encountered malformed JSON between 10-12 times.
*
* The JSON gets malformed, when a parallel process (node ace serve --watch)
* is trying to update it.
*/
this.maxAttempts = 15;
this.attempts = 0;
}
/**
* Returns a boolean telling if the error message is pointing
* towards invalid or empty JSON file read attempt.
*/
isMalformedJSONError(error) {
return error.includes('Unexpected end of JSON input');
}
/**
* Generates the manifest file. We ignore `generate:manifest` errors for
* now, since it's a secondary task for us and one should run it
* in seperate process to find the actual errors.
*/
async generate() {
try {
const response = await (0, execa_1.default)(process.execPath, ['ace', 'generate:manifest'], {
buffer: true,
cwd: this.appRoot,
env: {
FORCE_COLOR: 'true',
},
});
/**
* Log success
*/
if (response.stdout) {
this.logger.log(response.stdout);
}
return true;
}
catch (error) {
if (this.isMalformedJSONError(error.stderr) && this.attempts < this.maxAttempts) {
this.attempts++;
return this.generate();
}
/**
* Print warning on error
*/
this.logger.warning(WARN_MESSAGE);
if (error.stderr) {
this.logger.logError(error.stderr);
}
if (error.stdout) {
this.logger.logError(error.stdout);
}
return false;
}
}
}
exports.Manifest = Manifest;
+72
View File
@@ -0,0 +1,72 @@
import { Application } from '@adonisjs/application';
/**
* Exposes the API to pull meta files from the `.adonisrc.json` file and
* also match relative file paths against the defined globs.
*/
export declare class RcFile {
private appRoot;
rcFilePath: string;
/**
* Raw rcfile contents
*/
raw: any;
/**
* Reference to application
*/
application: Application;
/**
* A matcher to know if a file is part of the meta files globs
*/
isMetaFile: (filePath: string) => boolean;
/**
* A matcher to know if file is a test file or not
*/
isTestsFile: (filePath: string) => boolean;
/**
* A matcher to know if a file is part of the restart server files globs
*/
isRestartServerFile: (filePath: string) => boolean;
/**
* Commands match to know, if file path is part of the commands paths defined
* inside `.adonisrc.json` file
*/
isCommandsPath: (filePath: string) => boolean;
constructor(appRoot: string);
/**
* Returns an array of globs for the meta files that has `reloadServer`
* set to true
*/
private getRestartServerFilesGlob;
/**
* Returns the commands glob for registered commands. We convert the
* command paths to glob pattern
*/
private commandsGlob;
/**
* Returns true when file is `.adonisrc.json` itself
*/
private isRcFile;
/**
* Returns an array of globs for the meta files
* to be copied
*/
getMetaFilesGlob(): string[];
/**
* Returns an array of globs for the test files
*/
getTestsFileGlob(): string[];
/**
* Reloads the rcfile.json
*/
getDiskContents(): any;
/**
* Returns metadata for a given file path. The metadata can
* be used to execute certain actions during file watch.
*/
getMetaData(filePath: string): {
reload: boolean;
rcFile: boolean;
metaFile: boolean;
testFile: boolean;
};
}
+174
View File
@@ -0,0 +1,174 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RcFile = void 0;
const slash_1 = __importDefault(require("slash"));
const picomatch_1 = __importDefault(require("picomatch"));
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const application_1 = require("@adonisjs/application");
const helpers_1 = require("@poppinss/utils/build/helpers");
const paths_1 = require("../../config/paths");
/**
* Exposes the API to pull meta files from the `.adonisrc.json` file and
* also match relative file paths against the defined globs.
*/
class RcFile {
constructor(appRoot) {
this.appRoot = appRoot;
this.rcFilePath = (0, helpers_1.resolveFrom)(this.appRoot, `./${paths_1.RCFILE_NAME}`);
/**
* Raw rcfile contents
*/
this.raw = this.getDiskContents();
/**
* Reference to application
*/
this.application = new application_1.Application(this.appRoot, 'console', this.raw);
/**
* A matcher to know if a file is part of the meta files globs
*/
this.isMetaFile = (0, picomatch_1.default)(this.getMetaFilesGlob());
/**
* A matcher to know if file is a test file or not
*/
this.isTestsFile = (0, picomatch_1.default)(this.getTestsFileGlob());
/**
* A matcher to know if a file is part of the restart server files globs
*/
this.isRestartServerFile = (0, picomatch_1.default)(this.getRestartServerFilesGlob());
/**
* Commands match to know, if file path is part of the commands paths defined
* inside `.adonisrc.json` file
*/
this.isCommandsPath = (0, picomatch_1.default)(this.commandsGlob());
}
/**
* Returns an array of globs for the meta files that has `reloadServer`
* set to true
*/
getRestartServerFilesGlob() {
return this.application.rcFile.metaFiles
.filter(({ reloadServer, pattern }) => {
return reloadServer === true && ![paths_1.RCFILE_NAME, paths_1.ACE_FILE_NAME].includes(pattern);
})
.map(({ pattern }) => pattern);
}
/**
* Returns the commands glob for registered commands. We convert the
* command paths to glob pattern
*/
commandsGlob() {
const commands = this.application.rcFile.commands.reduce((result, commandPath) => {
if (/^(.){1,2}\//.test(commandPath)) {
commandPath = (0, slash_1.default)((0, path_1.relative)(this.appRoot, (0, path_1.join)(this.appRoot, commandPath)));
result = result.concat([`${commandPath}.*`, `${commandPath}/**/*`]);
}
return result;
}, []);
return commands;
}
/**
* Returns true when file is `.adonisrc.json` itself
*/
isRcFile(filePath) {
return filePath === paths_1.RCFILE_NAME;
}
/**
* Returns an array of globs for the meta files
* to be copied
*/
getMetaFilesGlob() {
return this.application.rcFile.metaFiles
.filter(({ pattern }) => ![paths_1.RCFILE_NAME, paths_1.ACE_FILE_NAME].includes(pattern))
.map(({ pattern }) => pattern)
.concat([paths_1.ACE_FILE_NAME]);
}
/**
* Returns an array of globs for the test files
*/
getTestsFileGlob() {
return this.application.rcFile.tests.suites.reduce((result, suite) => {
if (suite.files) {
result = result.concat(suite.files);
}
return result;
}, []);
}
/**
* Reloads the rcfile.json
*/
getDiskContents() {
return (0, fs_extra_1.readJSONSync)(this.rcFilePath);
}
/**
* Returns metadata for a given file path. The metadata can
* be used to execute certain actions during file watch.
*/
getMetaData(filePath) {
/**
* File path === '.adonisrc.json'
*/
if (this.isRcFile(filePath)) {
return {
reload: true,
rcFile: true,
metaFile: true,
testFile: false,
};
}
/**
* File is part of `reloadServer` metadata file globs
*/
if (this.isRestartServerFile(filePath)) {
return {
reload: true,
rcFile: false,
metaFile: true,
testFile: false,
};
}
/**
* File is part of metadata file globs, but reload = false
*/
if (this.isMetaFile(filePath)) {
return {
reload: false,
rcFile: false,
metaFile: true,
testFile: false,
};
}
/**
* File is part of one of the tests suite
*/
if (this.isTestsFile(filePath)) {
return {
reload: false,
rcFile: false,
metaFile: false,
testFile: true,
};
}
/**
* Out of scope
*/
return {
reload: false,
rcFile: false,
metaFile: false,
testFile: false,
};
}
}
exports.RcFile = RcFile;
+75
View File
@@ -0,0 +1,75 @@
import { logger as uiLogger } from '@poppinss/cliui';
import { JapaFlags } from '../Contracts';
/**
* Exposes the API to watch project for compilition changes and
* run/re-run tests
*/
export declare class TestsServer {
private appRoot;
private filters;
private nodeArgs;
private logger;
/**
* A boolean to know if we are watching for filesystem
*/
private watchingFileSystem;
/**
* Boolean to hold the current state of tests. This is avoid
* re-running the tests when one run is in progress
*/
private busy;
/**
* Reference to the typescript compiler
*/
private ts;
/**
* Reference to the RCFile
*/
private rcFile;
/**
* Manifest instance to generate ace manifest file
*/
private manifest;
/**
* Require-ts watch helpers
*/
private watchHelpers;
/**
* A method to know if the file is part of the selected suites
* or not
*/
private isTestSuiteFile;
/**
* Find if the test file part of the applied file filters
*/
private isTestFile;
constructor(appRoot: string, filters: JapaFlags, nodeArgs?: string[], logger?: typeof uiLogger);
/**
* Clear terminal screen
*/
private clearScreen;
/**
* Returns the glob paths for test suites. Returns all if no
* filter is applied. Otherwise only the filtered suites
* are picked.
*/
private getFilesForSelectedSuites;
/**
* Kill current process
*/
private kill;
/**
* Returns the HOST and the PORT environment variables
* for the HTTP server
*/
private getEnvironmentVariables;
/**
* Run tests. Use [[watch]] to also watch for file
* changes
*/
run(filePath?: string): Promise<void>;
/**
* Build and watch for file changes
*/
watch(poll?: boolean): Promise<void>;
}
+346
View File
@@ -0,0 +1,346 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestsServer = void 0;
const path_1 = require("path");
const picomatch_1 = __importDefault(require("picomatch"));
const cliui_1 = require("@poppinss/cliui");
const require_ts_1 = require("@adonisjs/require-ts");
const Ts_1 = require("../Ts");
const RcFile_1 = require("../RcFile");
const Manifest_1 = require("../Manifest");
const process_1 = require("./process");
const paths_1 = require("../../config/paths");
const EnvParser_1 = require("../EnvParser");
const get_port_1 = __importDefault(require("get-port"));
/**
* Exposes the API to watch project for compilition changes and
* run/re-run tests
*/
class TestsServer {
constructor(appRoot, filters, nodeArgs = [], logger = cliui_1.logger) {
this.appRoot = appRoot;
this.filters = filters;
this.nodeArgs = nodeArgs;
this.logger = logger;
/**
* A boolean to know if we are watching for filesystem
*/
this.watchingFileSystem = false;
/**
* Boolean to hold the current state of tests. This is avoid
* re-running the tests when one run is in progress
*/
this.busy = false;
/**
* Reference to the typescript compiler
*/
this.ts = new Ts_1.Ts(this.appRoot, this.logger);
/**
* Reference to the RCFile
*/
this.rcFile = new RcFile_1.RcFile(this.appRoot);
/**
* Manifest instance to generate ace manifest file
*/
this.manifest = new Manifest_1.Manifest(this.appRoot, this.logger);
/**
* Require-ts watch helpers
*/
this.watchHelpers = (0, require_ts_1.getWatcherHelpers)(this.appRoot);
/**
* A method to know if the file is part of the selected suites
* or not
*/
this.isTestSuiteFile = (0, picomatch_1.default)(this.getFilesForSelectedSuites());
/**
* Find if the test file part of the applied file filters
*/
this.isTestFile = (filePath) => {
if (!this.filters['--files']) {
return true;
}
const fileName = filePath.replace((0, path_1.extname)(filePath), '');
return !!this.filters['--files'].find((filter) => {
if (filePath.endsWith(filter)) {
return true;
}
return fileName.endsWith(filter) || fileName.endsWith(`${filter}.spec`);
});
};
}
/**
* Clear terminal screen
*/
clearScreen() {
process.stdout.write('\u001Bc');
}
/**
* Returns the glob paths for test suites. Returns all if no
* filter is applied. Otherwise only the filtered suites
* are picked.
*/
getFilesForSelectedSuites() {
return this.rcFile.application.rcFile.tests.suites.reduce((result, suite) => {
if (!suite.files) {
return result;
}
if (!this.filters['--suites'] || this.filters['--suites'].includes(suite.name)) {
result = result.concat(suite.files);
}
return result;
}, []);
}
/**
* Kill current process
*/
kill() {
process.exit();
}
/**
* Returns the HOST and the PORT environment variables
* for the HTTP server
*/
async getEnvironmentVariables() {
const envParser = new EnvParser_1.EnvParser();
await envParser.parse(this.appRoot);
const envOptions = envParser.asEnvObject(['PORT', 'TZ', 'HOST']);
const HOST = process.env.HOST || envOptions.HOST || '0.0.0.0';
let PORT = Number(process.env.PORT || envOptions.PORT);
/**
* Use the port defined inside ".env.test" file or use
* a random port
*/
PORT = await (0, get_port_1.default)({
port: !isNaN(PORT) ? [PORT] : [],
host: HOST,
});
return { HOST, PORT: String(PORT) };
}
/**
* Run tests. Use [[watch]] to also watch for file
* changes
*/
async run(filePath) {
if (this.busy) {
return;
}
this.clearScreen();
const filters = { ...this.filters };
/**
* Overwrite files filter when a specific file path
* is mentioned
*/
if (filePath) {
filters['--files'] = [filePath.replace(/\\/g, '/')];
}
this.busy = true;
const { hasErrors } = await new process_1.TestProcess(paths_1.TESTS_ENTRY_FILE, this.appRoot, filters, this.nodeArgs, this.logger, await this.getEnvironmentVariables()).run();
this.busy = false;
if (!this.watchingFileSystem) {
if (hasErrors) {
process.exitCode = 1;
}
this.kill();
}
}
/**
* Build and watch for file changes
*/
async watch(poll = false) {
this.watchingFileSystem = true;
/**
* Clear require-ts cache
*/
this.watchHelpers.clear();
/**
* Run tests
*/
await this.run();
/**
* Parse config to find the files excluded inside
* tsconfig file
*/
const config = this.ts.parseConfig();
if (!config) {
this.logger.warning('Cannot start watcher because of errors in the tsconfig file');
return;
}
/**
* Stick file watcher
*/
const watcher = this.ts.tsCompiler.watcher(config, 'raw');
/**
* Watcher is ready after first compile
*/
watcher.on('watcher:ready', () => {
this.logger.info('watching file system for changes');
});
/**
* Source file removed
*/
watcher.on('source:unlink', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
if (this.busy) {
return;
}
this.logger.action('delete').succeeded(relativePath);
/**
* Generate manifest when filePath is a commands path
*/
if (this.rcFile.isCommandsPath(relativePath)) {
this.manifest.generate();
}
/**
* Run all tests when any of the source, except the
* test file changes
*/
if (!this.rcFile.isTestsFile(relativePath)) {
await this.run();
}
});
/**
* Source file added
*/
watcher.on('source:add', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
if (this.busy) {
return;
}
this.logger.action('add').succeeded(relativePath);
/**
* Run all tests when any of the source, except the
* test file changes
*/
if (!this.rcFile.isTestsFile(relativePath)) {
await this.run();
return;
}
/**
* Run only the changed file if it part of the test
* suites (respecting filters)
*/
if (this.isTestSuiteFile(relativePath) && this.isTestFile(relativePath)) {
await this.run(relativePath);
}
});
/**
* Source file changed
*/
watcher.on('source:change', async ({ absPath, relativePath }) => {
this.watchHelpers.clear(absPath);
if (this.busy) {
return;
}
this.logger.action('update').succeeded(relativePath);
/**
* Generate manifest when filePath is a commands path
*/
if (this.rcFile.isCommandsPath(relativePath)) {
this.manifest.generate();
}
/**
* Run all tests when any of the source, except the
* test file changes
*/
if (!this.rcFile.isTestsFile(relativePath)) {
await this.run();
return;
}
/**
* Run only the changed file if it part of the test
* suites (respecting filters)
*/
if (this.isTestSuiteFile(relativePath) && this.isTestFile(relativePath)) {
await this.run(relativePath);
}
});
/**
* New file added
*/
watcher.on('add', async ({ relativePath }) => {
if (this.busy) {
return;
}
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('create').succeeded(relativePath);
await this.run();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
this.logger.action('create').succeeded(relativePath);
await this.run();
});
/**
* File changed
*/
watcher.on('change', async ({ relativePath }) => {
if (this.busy) {
return;
}
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('update').succeeded(relativePath);
await this.run();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
this.logger.action('update').succeeded(relativePath);
await this.run();
});
/**
* File removed
*/
watcher.on('unlink', async ({ relativePath }) => {
if (this.busy) {
return;
}
if (paths_1.ENV_FILES.includes(relativePath)) {
this.logger.action('delete').succeeded(relativePath);
await this.run();
return;
}
const metaData = this.rcFile.getMetaData(relativePath);
if (!metaData.metaFile) {
return;
}
if (metaData.rcFile) {
this.logger.info('cannot continue after deletion of .adonisrc.json file');
watcher.chokidar.close();
this.kill();
return;
}
this.logger.action('delete').succeeded(relativePath);
await this.run();
});
/**
* Start the watcher
*/
watcher.watch(['.'], {
usePolling: poll,
});
/**
* Kill when watcher recieves an error
*/
watcher.chokidar.on('error', (error) => {
this.logger.fatal(error);
this.kill();
});
}
}
exports.TestsServer = TestsServer;
+22
View File
@@ -0,0 +1,22 @@
import { logger as uiLogger } from '@poppinss/cliui';
import { JapaFlags } from '../Contracts';
/**
* Exposes the API to run tests as a child process.
*/
export declare class TestProcess {
private sourceFile;
private projectRoot;
private filters;
private logger;
private env;
private nodeArgs;
constructor(sourceFile: string, projectRoot: string, filters: JapaFlags, nodeArgs: string[] | undefined, logger: typeof uiLogger, env?: {
[key: string]: string;
});
/**
* Start the HTTP server as a child process.
*/
run(): Promise<{
hasErrors: boolean;
}>;
}
+68
View File
@@ -0,0 +1,68 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestProcess = void 0;
const execa_1 = __importDefault(require("execa"));
/**
* Exposes the API to run tests as a child process.
*/
class TestProcess {
constructor(sourceFile, projectRoot, filters, nodeArgs = [], logger, env = {}) {
this.sourceFile = sourceFile;
this.projectRoot = projectRoot;
this.filters = filters;
this.logger = logger;
this.env = env;
this.nodeArgs = nodeArgs.reduce((result, arg) => {
result = result.concat(arg.split(' '));
return result;
}, []);
}
/**
* Start the HTTP server as a child process.
*/
async run() {
this.logger.info('running tests...');
const filters = Object.keys(this.filters).reduce((result, filter) => {
const value = this.filters[filter];
if (filter === '_') {
result.push(...value);
return result;
}
result.push(filter);
if (Array.isArray(value)) {
result.push(value.join(','));
}
else {
result.push(value);
}
return result;
}, []);
try {
await execa_1.default.node(this.sourceFile, filters, {
stdio: 'inherit',
cwd: this.projectRoot,
env: {
FORCE_COLOR: 'true',
...this.env,
},
nodeOptions: ['-r', '@adonisjs/assembler/build/register'].concat(this.nodeArgs),
});
return { hasErrors: false };
}
catch {
return { hasErrors: true };
}
}
}
exports.TestProcess = TestProcess;
+24
View File
@@ -0,0 +1,24 @@
import tsStatic from 'typescript';
import { logger as uiLogger } from '@poppinss/cliui';
import { TypescriptCompiler } from '@poppinss/chokidar-ts';
/**
* Exposes the API to work with the Typescript compiler API
*/
export declare class Ts {
private appRoot;
private logger;
private tsconfig;
/**
* Reference to the typescript compiler
*/
tsCompiler: TypescriptCompiler;
constructor(appRoot: string, logger: typeof uiLogger, tsconfig?: string);
/**
* Render ts diagnostics
*/
renderDiagnostics(diagnostics: tsStatic.Diagnostic[], host: tsStatic.CompilerHost): void;
/**
* Parses the tsconfig file
*/
parseConfig(): undefined | tsStatic.ParsedCommandLine;
}
+55
View File
@@ -0,0 +1,55 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ts = void 0;
const path_1 = require("path");
const chokidar_ts_1 = require("@poppinss/chokidar-ts");
const helpers_1 = require("@poppinss/utils/build/helpers");
const paths_1 = require("../../config/paths");
/**
* Exposes the API to work with the Typescript compiler API
*/
class Ts {
constructor(appRoot, logger, tsconfig = paths_1.TSCONFIG_FILE_NAME) {
this.appRoot = appRoot;
this.logger = logger;
this.tsconfig = tsconfig;
/**
* Reference to the typescript compiler
*/
this.tsCompiler = new chokidar_ts_1.TypescriptCompiler(this.appRoot, this.tsconfig, require((0, helpers_1.resolveFrom)(this.appRoot, 'typescript/lib/typescript')));
}
/**
* Render ts diagnostics
*/
renderDiagnostics(diagnostics, host) {
console.error(this.tsCompiler.ts.formatDiagnosticsWithColorAndContext(diagnostics, host));
}
/**
* Parses the tsconfig file
*/
parseConfig() {
const { error, config } = this.tsCompiler.configParser().parse();
if (error) {
this.logger.error(`unable to parse ${this.tsconfig}`);
this.renderDiagnostics([error], this.tsCompiler.ts.createCompilerHost({}));
return;
}
if (config && config.errors.length) {
this.logger.error(`unable to parse ${this.tsconfig}`);
this.renderDiagnostics(config.errors, this.tsCompiler.ts.createCompilerHost(config.options));
return;
}
config.options.rootDir = config.options.rootDir || this.appRoot;
config.options.outDir = config.options.outDir || (0, path_1.join)(this.appRoot, paths_1.DEFAULT_BUILD_DIR);
return config;
}
}
exports.Ts = Ts;
@@ -0,0 +1,5 @@
/**
* Exports the function to be used for registering require hook
* for AdonisJS applications
*/
export default function registerForAdonis(appRoot: string): void;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const require_ts_1 = require("@adonisjs/require-ts");
/**
* Exports the function to be used for registering require hook
* for AdonisJS applications
*/
function registerForAdonis(appRoot) {
return (0, require_ts_1.register)(appRoot, {
cache: true,
transformers: {
after: [
{
transform: '@adonisjs/assembler/build/src/requireHook/ioc-transformer',
},
],
},
});
}
exports.default = registerForAdonis;
@@ -0,0 +1,6 @@
import type tsStatic from 'typescript';
/**
* Transformer to transform AdonisJS IoC container import
* statements
*/
export default function (ts: typeof tsStatic, appRoot: string): (ctx: tsStatic.TransformationContext) => (sourceFile: tsStatic.SourceFile) => tsStatic.SourceFile;
@@ -0,0 +1,21 @@
"use strict";
/*
* @adonisjs/assembler
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const application_1 = require("@adonisjs/application");
const ioc_transformer_1 = require("@adonisjs/ioc-transformer");
/**
* Transformer to transform AdonisJS IoC container import
* statements
*/
function default_1(ts, appRoot) {
return (0, ioc_transformer_1.iocTransformer)(ts, application_1.rcParser.parse(require((0, path_1.join)(appRoot, '.adonisrc.json'))));
}
exports.default = default_1;
+33
View File
@@ -0,0 +1,33 @@
import { BaseCommand } from '@adonisjs/core/build/standalone'
export default class {{ filename }} extends BaseCommand {
/**
* Command name is used to run the command
*/
public static commandName = '{{#toCommandName}}{{ filename }}{{/toCommandName}}'
/**
* Command description is displayed in the "help" output
*/
public static description = ''
public static settings = {
/**
* Set the following value to true, if you want to load the application
* before running the command. Don't forget to call `node ace generate:manifest`
* afterwards.
*/
loadApp: false,
/**
* Set the following value to true, if you want this command to keep running until
* you manually decide to exit the process. Don't forget to call
* `node ace generate:manifest` afterwards.
*/
stayAlive: false,
}
public async run() {
this.logger.info('Hello world!')
}
}
@@ -0,0 +1,3 @@
// import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class {{ filename }} {}
@@ -0,0 +1,3 @@
import type { EventsList } from '@ioc:Adonis/Core/Event'
export default class {{ filename }} {}
+15
View File
@@ -0,0 +1,15 @@
import { Exception } from '@adonisjs/core/build/standalone'
/*
|--------------------------------------------------------------------------
| Exception
|--------------------------------------------------------------------------
|
| The Exception class imported from `@adonisjs/core` allows defining
| a status code and error code for every exception.
|
| @example
| new {{ filename }}('message', 500, 'E_RUNTIME_EXCEPTION')
|
*/
export default class {{ filename }} extends Exception {}
@@ -0,0 +1,8 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class {{ filename }} {
public async handle({}: HttpContextContract, next: () => Promise<void>) {
// code for middleware goes here. ABOVE THE NEXT CALL
await next()
}
}
@@ -0,0 +1,9 @@
/*
|--------------------------------------------------------------------------
| Preloaded File
|--------------------------------------------------------------------------
|
| Any code written inside this file will be executed during the application
| boot.
|
*/
+40
View File
@@ -0,0 +1,40 @@
import type { ApplicationContract } from '@ioc:Adonis/Core/Application'
/*
|--------------------------------------------------------------------------
| Provider
|--------------------------------------------------------------------------
|
| Your application is not ready when this file is loaded by the framework.
| Hence, the top level imports relying on the IoC container will not work.
| You must import them inside the life-cycle methods defined inside
| the provider class.
|
| @example:
|
| public async ready () {
| const Database = this.app.container.resolveBinding('Adonis/Lucid/Database')
| const Event = this.app.container.resolveBinding('Adonis/Core/Event')
| Event.on('db:query', Database.prettyPrint)
| }
|
*/
export default class {{ filename }} {
constructor(protected app: ApplicationContract) {}
public register() {
// Register your own bindings
}
public async boot() {
// All bindings are ready, feel free to use them
}
public async ready() {
// App is ready
}
public async shutdown() {
// Cleanup, since app is going down
}
}
@@ -0,0 +1,17 @@
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class {{ filename }} {
public async index({}: HttpContextContract) {}
public async create({}: HttpContextContract) {}
public async store({}: HttpContextContract) {}
public async show({}: HttpContextContract) {}
public async edit({}: HttpContextContract) {}
public async update({}: HttpContextContract) {}
public async destroy({}: HttpContextContract) {}
}
@@ -0,0 +1,32 @@
import { Exception } from '@adonisjs/core/build/standalone'
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
/*
|--------------------------------------------------------------------------
| Exception
|--------------------------------------------------------------------------
|
| The Exception class imported from `@adonisjs/core` allows defining
| a status code and error code for every exception.
|
| @example
| new {{ filename }}('message', 500, 'E_RUNTIME_EXCEPTION')
|
*/
export default class {{ filename }} extends Exception {
/**
* The handle method allows you to self handle the exception and
* return an HTTP response.
*
* This is how it works under the hood.
*
* - You raise this exception
* - The exception goes uncatched/unhandled through out the entire HTTP request cycle.
* - Just before making the response. AdonisJS will call the `handle` method.
* Giving you a chance to convert the exception to response.
*
*/
public async handle(error: this, ctx: HttpContextContract) {
ctx.response.status(error.status || 500).send(error.message)
}
}
@@ -0,0 +1,45 @@
/*
|--------------------------------------------------------------------------
| Tests
|--------------------------------------------------------------------------
|
| The contents in this file boots the AdonisJS application and configures
| the Japa tests runner.
|
| For the most part you will never edit this file. The configuration
| for the tests can be controlled via ".adonisrc.json" and
| "tests/bootstrap.ts" files.
|
*/
process.env.NODE_ENV = 'test'
import 'reflect-metadata'
import sourceMapSupport from 'source-map-support'
import { Ignitor } from '@adonisjs/core/build/standalone'
import { configure, processCliArgs, run, RunnerHooksHandler } from '@japa/runner'
sourceMapSupport.install({ handleUncaughtExceptions: false })
const kernel = new Ignitor(__dirname).kernel('test')
kernel
.boot()
.then(() => import('./tests/bootstrap'))
.then(({ runnerHooks, ...config }) => {
const app: RunnerHooksHandler[] = [() => kernel.start()]
configure({
...kernel.application.rcFile.tests,
...processCliArgs(process.argv.slice(2)),
...config,
...{
importer: (filePath) => import(filePath),
setup: app.concat(runnerHooks.setup),
teardown: runnerHooks.teardown,
},
cwd: kernel.application.appRoot
})
run()
})
+5
View File
@@ -0,0 +1,5 @@
import { test } from '@japa/runner'
test.group('{{ name }}', () => {
// Write your test here
})
@@ -0,0 +1,18 @@
/**
* Contract source: https://bit.ly/3DP1ypf
*
* Feel free to let us know via PR, if you find something broken in this contract
* file.
*/
import '@japa/runner'
declare module '@japa/runner' {
interface TestContext {
// Extend context
}
interface Test<TestData> {
// Extend test
}
}
@@ -0,0 +1,69 @@
/**
* File source: https://bit.ly/3ukaHTz
*
* Feel free to let us know via PR, if you find something broken in this contract
* file.
*/
import type { Config } from '@japa/runner'
import TestUtils from '@ioc:Adonis/Core/TestUtils'
import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis'
/*
|--------------------------------------------------------------------------
| Japa Plugins
|--------------------------------------------------------------------------
|
| Japa plugins allows you to add additional features to Japa. By default
| we register the assertion plugin.
|
| Feel free to remove existing plugins or add more.
|
*/
export const plugins: Required<Config>['plugins'] = [assert(), runFailedTests(), apiClient()]
/*
|--------------------------------------------------------------------------
| Japa Reporters
|--------------------------------------------------------------------------
|
| Japa reporters displays/saves the progress of tests as they are executed.
| By default, we register the spec reporter to show a detailed report
| of tests on the terminal.
|
*/
export const reporters: Required<Config>['reporters'] = [specReporter()]
/*
|--------------------------------------------------------------------------
| Runner hooks
|--------------------------------------------------------------------------
|
| Runner hooks are executed after booting the AdonisJS app and
| before the test files are imported.
|
| You can perform actions like starting the HTTP server or running migrations
| within the runner hooks
|
*/
export const runnerHooks: Pick<Required<Config>, 'setup' | 'teardown'> = {
setup: [() => TestUtils.ace().loadCommands()],
teardown: [],
}
/*
|--------------------------------------------------------------------------
| Configure individual suites
|--------------------------------------------------------------------------
|
| The configureSuite method gets called for every test suite registered
| within ".adonisrc.json" file.
|
| You can use this method to configure suites. For example: Only start
| the HTTP server when it is a functional suite.
*/
export const configureSuite: Required<Config>['configureSuite'] = (suite) => {
if (suite.name === 'functional') {
suite.setup(() => TestUtils.httpServer().start())
}
}
@@ -0,0 +1,8 @@
import { test } from '@japa/runner'
test('display welcome page', async ({ client }) => {
const response = await client.get('/')
response.assertStatus(200)
response.assertBodyContains({ hello: 'world' })
})
@@ -0,0 +1,8 @@
import { test } from '@japa/runner'
test('display welcome page', async ({ client }) => {
const response = await client.get('/')
response.assertStatus(200)
response.assertTextIncludes('Hello world')
})
@@ -0,0 +1,8 @@
import { test } from '@japa/runner'
test('display welcome page', async ({ client }) => {
const response = await client.get('/')
response.assertStatus(200)
response.assertTextIncludes('<h1 class="title"> It Works! </h1>')
})
+40
View File
@@ -0,0 +1,40 @@
import { schema, CustomMessages } from '@ioc:Adonis/Core/Validator'
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class {{ filename }} {
constructor(protected ctx: HttpContextContract) {}
/*
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
*
* For example:
* 1. The username must be of data type string. But then also, it should
* not contain special characters or numbers.
* ```
* schema.string([ rules.alpha() ])
* ```
*
* 2. The email must be of data type string, formatted as a valid
* email. But also, not used by any other user.
* ```
* schema.string([
* rules.email(),
* rules.unique({ table: 'users', column: 'email' }),
* ])
* ```
*/
public schema = schema.create({})
/**
* Custom messages for validation failures. You can make use of dot notation `(.)`
* for targeting nested fields and array expressions `(*)` for targeting all
* children of an array. For example:
*
* {
* 'profile.username.required': 'Username is required',
* 'scores.*.number': 'Define scores as valid numbers'
* }
*
*/
public messages: CustomMessages = {}
}
View File
@@ -0,0 +1,214 @@
const { join } = require('path')
const Encore = require('@symfony/webpack-encore')
/*
|--------------------------------------------------------------------------
| Encore runtime environment
|--------------------------------------------------------------------------
*/
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev')
}
/*
|--------------------------------------------------------------------------
| Output path
|--------------------------------------------------------------------------
|
| The output path for writing the compiled files. It should always
| be inside the public directory, so that AdonisJS can serve it.
|
*/
Encore.setOutputPath('./public/assets')
/*
|--------------------------------------------------------------------------
| Public URI
|--------------------------------------------------------------------------
|
| The public URI to access the static files. It should always be
| relative from the "public" directory.
|
*/
Encore.setPublicPath('/assets')
/*
|--------------------------------------------------------------------------
| Entrypoints
|--------------------------------------------------------------------------
|
| Entrypoints are script files that boots your frontend application. Ideally
| a single entrypoint is used by majority of applications. However, feel
| free to add more (if required).
|
| Also, make sure to read the docs on "Assets bundler" to learn more about
| entrypoints.
|
*/
Encore.addEntry('app', './resources/js/app.js')
/*
|--------------------------------------------------------------------------
| Copy assets
|--------------------------------------------------------------------------
|
| Since the edge templates are not part of the Webpack compile lifecycle, any
| images referenced by it will not be processed by Webpack automatically. Hence
| we must copy them manually.
|
*/
// Encore.copyFiles({
// from: './resources/images',
// to: 'images/[path][name].[hash:8].[ext]',
// })
/*
|--------------------------------------------------------------------------
| Split shared code
|--------------------------------------------------------------------------
|
| Instead of bundling duplicate code in all the bundles, generate a separate
| bundle for the shared code.
|
| https://symfony.com/doc/current/frontend/encore/split-chunks.html
| https://webpack.js.org/plugins/split-chunks-plugin/
|
*/
// Encore.splitEntryChunks()
/*
|--------------------------------------------------------------------------
| Isolated entrypoints
|--------------------------------------------------------------------------
|
| Treat each entry point and its dependencies as its own isolated module.
|
*/
Encore.disableSingleRuntimeChunk()
/*
|--------------------------------------------------------------------------
| Cleanup output folder
|--------------------------------------------------------------------------
|
| It is always nice to cleanup the build output before creating a build. It
| will ensure that all unused files from the previous build are removed.
|
*/
Encore.cleanupOutputBeforeBuild()
/*
|--------------------------------------------------------------------------
| Source maps
|--------------------------------------------------------------------------
|
| Enable source maps in production
|
*/
Encore.enableSourceMaps(!Encore.isProduction())
/*
|--------------------------------------------------------------------------
| Assets versioning
|--------------------------------------------------------------------------
|
| Enable assets versioning to leverage lifetime browser and CDN cache
|
*/
Encore.enableVersioning(Encore.isProduction())
/*
|--------------------------------------------------------------------------
| Configure dev server
|--------------------------------------------------------------------------
|
| Here we configure the dev server to enable live reloading for edge templates.
| Remember edge templates are not processed by Webpack and hence we need
| to watch them explicitly and livereload the browser.
|
*/
Encore.configureDevServerOptions((options) => {
/**
* Normalize "options.static" property to an array
*/
if (!options.static) {
options.static = []
} else if (!Array.isArray(options.static)) {
options.static = [options.static]
}
/**
* Enable live reload and add views directory
*/
options.liveReload = true
options.static.push({
directory: join(__dirname, './resources/views'),
watch: true,
})
})
/*
|--------------------------------------------------------------------------
| CSS precompilers support
|--------------------------------------------------------------------------
|
| Uncomment one of the following lines of code to enable support for your
| favorite CSS precompiler
|
*/
// Encore.enableSassLoader()
// Encore.enableLessLoader()
// Encore.enableStylusLoader()
/*
|--------------------------------------------------------------------------
| CSS loaders
|--------------------------------------------------------------------------
|
| Uncomment one of the following line of code to enable support for
| PostCSS or CSS.
|
*/
// Encore.enablePostCssLoader()
// Encore.configureCssLoader(() => {})
/*
|--------------------------------------------------------------------------
| Enable Vue loader
|--------------------------------------------------------------------------
|
| Uncomment the following lines of code to enable support for vue. Also make
| sure to install the required dependencies.
|
*/
// Encore.enableVueLoader(() => {}, {
// version: 3,
// runtimeCompilerBuild: false,
// useJsx: false
// })
/*
|--------------------------------------------------------------------------
| Configure logging
|--------------------------------------------------------------------------
|
| To keep the terminal clean from unnecessary info statements , we only
| log warnings and errors. If you want all the logs, you can change
| the level to "info".
|
*/
const config = Encore.getWebpackConfig()
config.infrastructureLogging = {
level: 'warn',
}
config.stats = 'errors-warnings'
/*
|--------------------------------------------------------------------------
| Export config
|--------------------------------------------------------------------------
|
| Export config for webpack to do its job
|
*/
module.exports = config
+166
View File
@@ -0,0 +1,166 @@
{
"name": "@adonisjs/assembler",
"version": "5.9.6",
"description": "Core commands to compiler and build AdonisJs project",
"main": "build/ace-manifest.json",
"engines": {
"node": ">=14.0.0"
},
"files": [
"build/commands",
"build/config",
"build/templates",
"build/src",
"build/register.js",
"build/register.d.ts",
"build/ace-manifest.json"
],
"scripts": {
"mrm": "mrm --preset=@adonisjs/mrm-preset",
"pretest": "npm run lint",
"test": "cross-env FORCE_COLOR=true node -r @adonisjs/require-ts/build/register ./bin/test.ts",
"lint": "eslint . --ext=.ts",
"clean": "del-cli build",
"compile": "npm run lint && npm run clean && tsc",
"build": "npm run compile && node build/bin/index.js && copyfiles \"templates/**\" build",
"commit": "git-cz",
"release": "np --message=\"chore(release): %s\"",
"version": "npm run build",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs/assembler",
"format": "prettier --write .",
"prepublishOnly": "npm run build"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/adonisjs/assembler.git"
},
"keywords": [
"adonisjs",
"boot",
"build",
"ts"
],
"author": "virk,adonisjs",
"license": "MIT",
"bugs": {
"url": "https://github.com/adonisjs/assembler/issues"
},
"homepage": "https://github.com/adonisjs/assembler#readme",
"devDependencies": {
"@adonisjs/ace": "^11.3.1",
"@adonisjs/core": "^5.8.9",
"@adonisjs/mrm-preset": "^5.0.3",
"@japa/assert": "^1.3.6",
"@japa/run-failed-tests": "^1.1.0",
"@japa/runner": "^2.2.2",
"@japa/spec-reporter": "^1.3.2",
"@poppinss/dev-utils": "^2.0.3",
"@types/node": "^18.15.1",
"commitizen": "^4.2.5",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0",
"del-cli": "^5.0.0",
"eslint": "^8.27.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-adonis": "^2.1.1",
"eslint-plugin-prettier": "^4.2.1",
"github-label-sync": "^2.2.0",
"husky": "^8.0.2",
"mrm": "^4.1.13",
"np": "^8.0.2",
"prettier": "^2.7.1",
"typescript": "^4.9.3"
},
"nyc": {
"exclude": [
"test"
],
"extension": [
".ts"
]
},
"husky": {
"hooks": {
"commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js"
}
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"np": {
"contents": ".",
"anyBranch": false
},
"dependencies": {
"@adonisjs/application": "^5.2.5",
"@adonisjs/env": "^3.0.9",
"@adonisjs/ioc-transformer": "^2.3.4",
"@adonisjs/require-ts": "^2.0.13",
"@adonisjs/sink": "^5.4.2",
"@poppinss/chokidar-ts": "^3.3.5",
"@poppinss/cliui": "^3.0.5",
"@poppinss/utils": "^5.0.0",
"cpy": "^8.1.2",
"emittery": "^0.13.1",
"execa": "^5.1.1",
"fs-extra": "^10.1.0",
"get-port": "^5.1.1",
"glob-parent": "^6.0.2",
"has-yarn": "^2.1.0",
"picomatch": "^2.3.1",
"slash": "^3.0.0"
},
"peerDependencies": {
"@adonisjs/core": "^5.1.0"
},
"publishConfig": {
"access": "public",
"tag": "latest"
},
"mrmConfig": {
"core": true,
"license": "MIT",
"services": [
"github-actions"
],
"minNodeVersion": "14.15.4",
"probotApps": [
"stale",
"lock"
],
"runGhActionsOnWindows": true
},
"eslintConfig": {
"extends": [
"plugin:adonis/typescriptPackage",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
},
"eslintIgnore": [
"build"
],
"prettier": {
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"useTabs": false,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 100
}
}