@adonisjs/assembler 6.1.3-2 → 6.1.3-20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +3 -6
- package/build/index.d.ts +1 -0
- package/build/index.js +9 -0
- package/build/src/assets_dev_server.d.ts +32 -0
- package/build/src/assets_dev_server.js +158 -0
- package/build/src/bundler.d.ts +9 -0
- package/build/src/bundler.js +75 -5
- package/build/src/code_transformer/main.d.ts +28 -0
- package/build/src/code_transformer/main.js +201 -0
- package/build/src/code_transformer/rc_file_transformer.d.ts +43 -0
- package/build/src/code_transformer/rc_file_transformer.js +272 -0
- package/build/src/debug.d.ts +3 -0
- package/build/src/debug.js +10 -0
- package/build/src/dev_server.d.ts +32 -0
- package/build/src/dev_server.js +146 -179
- package/build/src/helpers.d.ts +50 -0
- package/build/src/helpers.js +183 -0
- package/build/src/test_runner.d.ts +47 -0
- package/build/src/test_runner.js +310 -0
- package/build/src/types.d.ts +102 -0
- package/build/src/types.js +8 -0
- package/package.json +52 -66
- package/build/src/parse_config.d.ts +0 -3
- package/build/src/parse_config.js +0 -15
- package/build/src/run.d.ts +0 -4
- package/build/src/run.js +0 -37
- package/build/src/watch.d.ts +0 -8
- package/build/src/watch.js +0 -12
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2023
|
|
3
|
+
Copyright (c) 2023 Harminder Virk
|
|
4
4
|
|
|
5
5
|
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:
|
|
6
6
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<br />
|
|
4
4
|
|
|
5
|
-
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
|
|
5
|
+
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
|
|
6
6
|
|
|
7
7
|
## Introduction
|
|
8
8
|
Assembler exports the API for starting the **AdonisJS development server**, **building project for production** and **running tests** in watch mode. Assembler must be used during development only.
|
|
@@ -21,8 +21,8 @@ In order to ensure that the AdonisJS community is welcoming to all, please revie
|
|
|
21
21
|
## License
|
|
22
22
|
AdonisJS Assembler is open-sourced software licensed under the [MIT license](LICENSE.md).
|
|
23
23
|
|
|
24
|
-
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/assembler/
|
|
25
|
-
[gh-workflow-url]: https://github.com/adonisjs/assembler/actions/workflows/
|
|
24
|
+
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/assembler/checks.yml?style=for-the-badge
|
|
25
|
+
[gh-workflow-url]: https://github.com/adonisjs/assembler/actions/workflows/checks.yml "Github action"
|
|
26
26
|
|
|
27
27
|
[npm-image]: https://img.shields.io/npm/v/@adonisjs/assembler/latest.svg?style=for-the-badge&logo=npm
|
|
28
28
|
[npm-url]: https://npmjs.org/package/@adonisjs/assembler/v/latest "npm"
|
|
@@ -31,6 +31,3 @@ AdonisJS Assembler is open-sourced software licensed under the [MIT license](LIC
|
|
|
31
31
|
|
|
32
32
|
[license-url]: LICENSE.md
|
|
33
33
|
[license-image]: https://img.shields.io/github/license/adonisjs/ace?style=for-the-badge
|
|
34
|
-
|
|
35
|
-
[synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs/assembler?label=Synk%20Vulnerabilities&style=for-the-badge
|
|
36
|
-
[synk-url]: https://snyk.io/test/github/adonisjs/assembler?targetFile=package.json "synk"
|
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/assembler
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
1
9
|
export { Bundler } from './src/bundler.js';
|
|
2
10
|
export { DevServer } from './src/dev_server.js';
|
|
11
|
+
export { TestRunner } from './src/test_runner.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { type Logger } from '@poppinss/cliui';
|
|
3
|
+
import type { AssetsBundlerOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Exposes the API to start the development server for processing assets during
|
|
6
|
+
* development.
|
|
7
|
+
*
|
|
8
|
+
* - Here we are running the assets dev server in a child process.
|
|
9
|
+
* - Piping the output from the child process and reformatting it before writing it to
|
|
10
|
+
* process streams.
|
|
11
|
+
*
|
|
12
|
+
* AssetsDevServer is agnostic and can run any assets dev server. Be it Vite or Encore or
|
|
13
|
+
* even Webpack directly.
|
|
14
|
+
*/
|
|
15
|
+
export declare class AssetsDevServer {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(cwd: URL, options?: AssetsBundlerOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Set a custom CLI UI logger
|
|
20
|
+
*/
|
|
21
|
+
setLogger(logger: Logger): this;
|
|
22
|
+
/**
|
|
23
|
+
* Starts the assets bundler server. The assets bundler server process is
|
|
24
|
+
* considered as the secondary process and therefore we do not perform
|
|
25
|
+
* any cleanup if it dies.
|
|
26
|
+
*/
|
|
27
|
+
start(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Stop the dev server
|
|
30
|
+
*/
|
|
31
|
+
stop(): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/core
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { cliui } from '@poppinss/cliui';
|
|
10
|
+
import { run } from './helpers.js';
|
|
11
|
+
/**
|
|
12
|
+
* Instance of CLIUI
|
|
13
|
+
*/
|
|
14
|
+
const ui = cliui();
|
|
15
|
+
/**
|
|
16
|
+
* Exposes the API to start the development server for processing assets during
|
|
17
|
+
* development.
|
|
18
|
+
*
|
|
19
|
+
* - Here we are running the assets dev server in a child process.
|
|
20
|
+
* - Piping the output from the child process and reformatting it before writing it to
|
|
21
|
+
* process streams.
|
|
22
|
+
*
|
|
23
|
+
* AssetsDevServer is agnostic and can run any assets dev server. Be it Vite or Encore or
|
|
24
|
+
* even Webpack directly.
|
|
25
|
+
*/
|
|
26
|
+
export class AssetsDevServer {
|
|
27
|
+
#cwd;
|
|
28
|
+
#logger = ui.logger;
|
|
29
|
+
#options;
|
|
30
|
+
#devServer;
|
|
31
|
+
/**
|
|
32
|
+
* Getting reference to colors library from logger
|
|
33
|
+
*/
|
|
34
|
+
get #colors() {
|
|
35
|
+
return this.#logger.getColors();
|
|
36
|
+
}
|
|
37
|
+
constructor(cwd, options) {
|
|
38
|
+
this.#cwd = cwd;
|
|
39
|
+
this.#options = options;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Logs messages from vite dev server stdout and stderr
|
|
43
|
+
*/
|
|
44
|
+
#logViteDevServerMessage(data) {
|
|
45
|
+
const dataString = data.toString();
|
|
46
|
+
const lines = dataString.split('\n');
|
|
47
|
+
/**
|
|
48
|
+
* Logging VITE ready in message with proper
|
|
49
|
+
* spaces and newlines
|
|
50
|
+
*/
|
|
51
|
+
if (dataString.includes('ready in')) {
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log(dataString.trim());
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Put a wrapper around vite network address log
|
|
58
|
+
*/
|
|
59
|
+
if (dataString.includes('Local') && dataString.includes('Network')) {
|
|
60
|
+
const sticker = ui.sticker().useColors(this.#colors).useRenderer(this.#logger.getRenderer());
|
|
61
|
+
lines.forEach((line) => {
|
|
62
|
+
if (line.trim()) {
|
|
63
|
+
sticker.add(line);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
sticker.render();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Log rest of the lines
|
|
71
|
+
*/
|
|
72
|
+
lines.forEach((line) => {
|
|
73
|
+
if (line.trim()) {
|
|
74
|
+
console.log(line);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Logs messages from assets dev server stdout and stderr
|
|
80
|
+
*/
|
|
81
|
+
#logAssetsDevServerMessage(data) {
|
|
82
|
+
const dataString = data.toString();
|
|
83
|
+
const lines = dataString.split('\n');
|
|
84
|
+
lines.forEach((line) => {
|
|
85
|
+
if (line.trim()) {
|
|
86
|
+
console.log(line);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Set a custom CLI UI logger
|
|
92
|
+
*/
|
|
93
|
+
setLogger(logger) {
|
|
94
|
+
this.#logger = logger;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Starts the assets bundler server. The assets bundler server process is
|
|
99
|
+
* considered as the secondary process and therefore we do not perform
|
|
100
|
+
* any cleanup if it dies.
|
|
101
|
+
*/
|
|
102
|
+
start() {
|
|
103
|
+
if (!this.#options?.serve) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this.#logger.info(`starting "${this.#options.driver}" dev server...`);
|
|
107
|
+
/**
|
|
108
|
+
* Create child process
|
|
109
|
+
*/
|
|
110
|
+
this.#devServer = run(this.#cwd, {
|
|
111
|
+
script: this.#options.cmd,
|
|
112
|
+
/**
|
|
113
|
+
* We do not inherit the stdio for vite and encore, because in
|
|
114
|
+
* inherit mode they own the stdin and interrupts the
|
|
115
|
+
* `Ctrl + C` command.
|
|
116
|
+
*/
|
|
117
|
+
stdio: 'pipe',
|
|
118
|
+
scriptArgs: this.#options.args,
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* Log child process messages
|
|
122
|
+
*/
|
|
123
|
+
this.#devServer.stdout?.on('data', (data) => {
|
|
124
|
+
if (this.#options.driver === 'vite') {
|
|
125
|
+
this.#logViteDevServerMessage(data);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
this.#logAssetsDevServerMessage(data);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
this.#devServer.stderr?.on('data', (data) => {
|
|
132
|
+
if (this.#options.driver === 'vite') {
|
|
133
|
+
this.#logViteDevServerMessage(data);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.#logAssetsDevServerMessage(data);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.#devServer
|
|
140
|
+
.then((result) => {
|
|
141
|
+
this.#logger.warning(`"${this.#options.driver}" dev server closed with status code "${result.exitCode}"`);
|
|
142
|
+
})
|
|
143
|
+
.catch((error) => {
|
|
144
|
+
this.#logger.warning(`unable to connect to "${this.#options.driver}" dev server`);
|
|
145
|
+
this.#logger.fatal(error);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Stop the dev server
|
|
150
|
+
*/
|
|
151
|
+
stop() {
|
|
152
|
+
if (this.#devServer) {
|
|
153
|
+
this.#devServer.removeAllListeners();
|
|
154
|
+
this.#devServer.kill('SIGKILL');
|
|
155
|
+
this.#devServer = undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
package/build/src/bundler.d.ts
CHANGED
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
import type tsStatic from 'typescript';
|
|
3
3
|
import { type Logger } from '@poppinss/cliui';
|
|
4
4
|
import type { BundlerOptions } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* The bundler class exposes the API to build an AdonisJS project.
|
|
7
|
+
*/
|
|
5
8
|
export declare class Bundler {
|
|
6
9
|
#private;
|
|
7
10
|
constructor(cwd: URL, ts: typeof tsStatic, options: BundlerOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Set a custom CLI UI logger
|
|
13
|
+
*/
|
|
8
14
|
setLogger(logger: Logger): this;
|
|
15
|
+
/**
|
|
16
|
+
* Bundles the application to be run in production
|
|
17
|
+
*/
|
|
9
18
|
bundle(stopOnError?: boolean, client?: 'npm' | 'yarn' | 'pnpm'): Promise<boolean>;
|
|
10
19
|
}
|
package/build/src/bundler.js
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/assembler
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
1
9
|
import slash from 'slash';
|
|
2
|
-
import copyfiles from 'cpy';
|
|
3
10
|
import fs from 'node:fs/promises';
|
|
4
11
|
import { fileURLToPath } from 'node:url';
|
|
5
12
|
import { join, relative } from 'node:path';
|
|
6
13
|
import { cliui } from '@poppinss/cliui';
|
|
7
|
-
import { run } from './
|
|
8
|
-
|
|
14
|
+
import { run, parseConfig, copyFiles } from './helpers.js';
|
|
15
|
+
/**
|
|
16
|
+
* Instance of CLIUI
|
|
17
|
+
*/
|
|
9
18
|
const ui = cliui();
|
|
19
|
+
/**
|
|
20
|
+
* The bundler class exposes the API to build an AdonisJS project.
|
|
21
|
+
*/
|
|
10
22
|
export class Bundler {
|
|
11
23
|
#cwd;
|
|
12
24
|
#cwdPath;
|
|
13
25
|
#ts;
|
|
14
26
|
#logger = ui.logger;
|
|
15
27
|
#options;
|
|
28
|
+
/**
|
|
29
|
+
* Getting reference to colors library from logger
|
|
30
|
+
*/
|
|
16
31
|
get #colors() {
|
|
17
32
|
return this.#logger.getColors();
|
|
18
33
|
}
|
|
@@ -25,9 +40,15 @@ export class Bundler {
|
|
|
25
40
|
#getRelativeName(filePath) {
|
|
26
41
|
return slash(relative(this.#cwdPath, filePath));
|
|
27
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Cleans up the build directory
|
|
45
|
+
*/
|
|
28
46
|
async #cleanupBuildDirectory(outDir) {
|
|
29
47
|
await fs.rm(outDir, { recursive: true, force: true, maxRetries: 5 });
|
|
30
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Runs assets bundler command to build assets.
|
|
51
|
+
*/
|
|
31
52
|
async #buildAssets() {
|
|
32
53
|
const assetsBundler = this.#options.assets;
|
|
33
54
|
if (!assetsBundler?.serve) {
|
|
@@ -38,7 +59,7 @@ export class Bundler {
|
|
|
38
59
|
await run(this.#cwd, {
|
|
39
60
|
stdio: 'inherit',
|
|
40
61
|
script: assetsBundler.cmd,
|
|
41
|
-
scriptArgs:
|
|
62
|
+
scriptArgs: assetsBundler.args,
|
|
42
63
|
});
|
|
43
64
|
return true;
|
|
44
65
|
}
|
|
@@ -46,6 +67,9 @@ export class Bundler {
|
|
|
46
67
|
return false;
|
|
47
68
|
}
|
|
48
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Runs tsc command to build the source.
|
|
72
|
+
*/
|
|
49
73
|
async #runTsc(outDir) {
|
|
50
74
|
try {
|
|
51
75
|
await run(this.#cwd, {
|
|
@@ -59,9 +83,12 @@ export class Bundler {
|
|
|
59
83
|
return false;
|
|
60
84
|
}
|
|
61
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Copy files to destination directory
|
|
88
|
+
*/
|
|
62
89
|
async #copyFiles(files, outDir) {
|
|
63
90
|
try {
|
|
64
|
-
await
|
|
91
|
+
await copyFiles(files, this.#cwdPath, outDir);
|
|
65
92
|
}
|
|
66
93
|
catch (error) {
|
|
67
94
|
if (!error.message.includes("the file doesn't exist")) {
|
|
@@ -69,12 +96,18 @@ export class Bundler {
|
|
|
69
96
|
}
|
|
70
97
|
}
|
|
71
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Copy meta files to the output directory
|
|
101
|
+
*/
|
|
72
102
|
async #copyMetaFiles(outDir, additionalFilesToCopy) {
|
|
73
103
|
const metaFiles = (this.#options.metaFiles || [])
|
|
74
104
|
.map((file) => file.pattern)
|
|
75
105
|
.concat(additionalFilesToCopy);
|
|
76
106
|
await this.#copyFiles(metaFiles, outDir);
|
|
77
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Copies .adonisrc.json file to the destination
|
|
110
|
+
*/
|
|
78
111
|
async #copyAdonisRcFile(outDir) {
|
|
79
112
|
const existingContents = JSON.parse(await fs.readFile(join(this.#cwdPath, '.adonisrc.json'), 'utf-8'));
|
|
80
113
|
const compiledContents = Object.assign({}, existingContents, {
|
|
@@ -84,6 +117,9 @@ export class Bundler {
|
|
|
84
117
|
await fs.mkdir(outDir, { recursive: true });
|
|
85
118
|
await fs.writeFile(join(outDir, '.adonisrc.json'), JSON.stringify(compiledContents, null, 2) + '\n');
|
|
86
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns the lock file name for a given packages client
|
|
122
|
+
*/
|
|
87
123
|
#getClientLockFile(client) {
|
|
88
124
|
switch (client) {
|
|
89
125
|
case 'npm':
|
|
@@ -94,6 +130,9 @@ export class Bundler {
|
|
|
94
130
|
return 'pnpm-lock.yaml';
|
|
95
131
|
}
|
|
96
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Returns the installation command for a given packages client
|
|
135
|
+
*/
|
|
97
136
|
#getClientInstallCommand(client) {
|
|
98
137
|
switch (client) {
|
|
99
138
|
case 'npm':
|
|
@@ -104,24 +143,46 @@ export class Bundler {
|
|
|
104
143
|
return 'pnpm i --prod';
|
|
105
144
|
}
|
|
106
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Set a custom CLI UI logger
|
|
148
|
+
*/
|
|
107
149
|
setLogger(logger) {
|
|
108
150
|
this.#logger = logger;
|
|
109
151
|
return this;
|
|
110
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Bundles the application to be run in production
|
|
155
|
+
*/
|
|
111
156
|
async bundle(stopOnError = true, client = 'npm') {
|
|
157
|
+
/**
|
|
158
|
+
* Step 1: Parse config file to get the build output directory
|
|
159
|
+
*/
|
|
112
160
|
const config = parseConfig(this.#cwd, this.#ts);
|
|
113
161
|
if (!config) {
|
|
114
162
|
return false;
|
|
115
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Step 2: Cleanup existing build directory (if any)
|
|
166
|
+
*/
|
|
116
167
|
const outDir = config.options.outDir || fileURLToPath(new URL('build/', this.#cwd));
|
|
117
168
|
this.#logger.info('cleaning up output directory', { suffix: this.#getRelativeName(outDir) });
|
|
118
169
|
await this.#cleanupBuildDirectory(outDir);
|
|
170
|
+
/**
|
|
171
|
+
* Step 3: Build frontend assets
|
|
172
|
+
*/
|
|
119
173
|
if (!(await this.#buildAssets())) {
|
|
120
174
|
return false;
|
|
121
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Step 4: Build typescript source code
|
|
178
|
+
*/
|
|
122
179
|
this.#logger.info('compiling typescript source', { suffix: 'tsc' });
|
|
123
180
|
const buildCompleted = await this.#runTsc(outDir);
|
|
124
181
|
await this.#copyFiles(['ace.js'], outDir);
|
|
182
|
+
/**
|
|
183
|
+
* Remove incomplete build directory when tsc build
|
|
184
|
+
* failed and stopOnError is set to true.
|
|
185
|
+
*/
|
|
125
186
|
if (!buildCompleted && stopOnError) {
|
|
126
187
|
await this.#cleanupBuildDirectory(outDir);
|
|
127
188
|
const instructions = ui
|
|
@@ -133,13 +194,22 @@ export class Bundler {
|
|
|
133
194
|
this.#logger.logError(instructions.prepare());
|
|
134
195
|
return false;
|
|
135
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Step 5: Copy meta files to the build directory
|
|
199
|
+
*/
|
|
136
200
|
const pkgFiles = ['package.json', this.#getClientLockFile(client)];
|
|
137
201
|
this.#logger.info('copying meta files to the output directory');
|
|
138
202
|
await this.#copyMetaFiles(outDir, pkgFiles);
|
|
203
|
+
/**
|
|
204
|
+
* Step 6: Copy .adonisrc.json file to the build directory
|
|
205
|
+
*/
|
|
139
206
|
this.#logger.info('copying .adonisrc.json file to the output directory');
|
|
140
207
|
await this.#copyAdonisRcFile(outDir);
|
|
141
208
|
this.#logger.success('build completed');
|
|
142
209
|
this.#logger.log('');
|
|
210
|
+
/**
|
|
211
|
+
* Next steps
|
|
212
|
+
*/
|
|
143
213
|
ui.instructions()
|
|
144
214
|
.useRenderer(this.#logger.getRenderer())
|
|
145
215
|
.heading('Run the following commands to start the server in production')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { RcFileTransformer } from './rc_file_transformer.js';
|
|
3
|
+
import type { AddMiddlewareEntry, EnvValidationDefinition } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* This class is responsible for updating
|
|
6
|
+
*/
|
|
7
|
+
export declare class CodeTransformer {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(cwd: URL);
|
|
10
|
+
/**
|
|
11
|
+
* Update the `adonisrc.ts` file
|
|
12
|
+
*/
|
|
13
|
+
updateRcFile(callback: (transformer: RcFileTransformer) => void): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Define new middlewares inside the `start/kernel.ts`
|
|
16
|
+
* file
|
|
17
|
+
*
|
|
18
|
+
* This function is highly based on some assumptions
|
|
19
|
+
* and will not work if you significantly tweaked
|
|
20
|
+
* your `start/kernel.ts` file.
|
|
21
|
+
*/
|
|
22
|
+
addMiddlewareToStack(stack: 'server' | 'router' | 'named', middleware: AddMiddlewareEntry[]): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Add new env variable validation in the
|
|
25
|
+
* `env.ts` file
|
|
26
|
+
*/
|
|
27
|
+
defineEnvValidations(definition: EnvValidationDefinition): Promise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/assembler
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { Node, Project, SyntaxKind } from 'ts-morph';
|
|
12
|
+
import { RcFileTransformer } from './rc_file_transformer.js';
|
|
13
|
+
/**
|
|
14
|
+
* This class is responsible for updating
|
|
15
|
+
*/
|
|
16
|
+
export class CodeTransformer {
|
|
17
|
+
/**
|
|
18
|
+
* Directory of the adonisjs project
|
|
19
|
+
*/
|
|
20
|
+
#cwd;
|
|
21
|
+
/**
|
|
22
|
+
* The TsMorph project
|
|
23
|
+
*/
|
|
24
|
+
#project;
|
|
25
|
+
/**
|
|
26
|
+
* Settings to use when persisting files
|
|
27
|
+
*/
|
|
28
|
+
#editorSettings = {
|
|
29
|
+
indentSize: 2,
|
|
30
|
+
convertTabsToSpaces: true,
|
|
31
|
+
trimTrailingWhitespace: true,
|
|
32
|
+
};
|
|
33
|
+
constructor(cwd) {
|
|
34
|
+
this.#cwd = cwd;
|
|
35
|
+
this.#project = new Project({
|
|
36
|
+
tsConfigFilePath: join(fileURLToPath(this.#cwd), 'tsconfig.json'),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Update the `adonisrc.ts` file
|
|
41
|
+
*/
|
|
42
|
+
async updateRcFile(callback) {
|
|
43
|
+
const rcFileTransformer = new RcFileTransformer(this.#cwd, this.#project);
|
|
44
|
+
callback(rcFileTransformer);
|
|
45
|
+
await rcFileTransformer.save();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Add a new middleware to the middleware array of the
|
|
49
|
+
* given file
|
|
50
|
+
*/
|
|
51
|
+
#addToMiddlewareArray(file, target, middlewareEntry) {
|
|
52
|
+
const callExpressions = file
|
|
53
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
54
|
+
.filter((statement) => statement.getExpression().getText() === target);
|
|
55
|
+
if (!callExpressions.length) {
|
|
56
|
+
throw new Error(`Cannot find ${target} statement in the file.`);
|
|
57
|
+
}
|
|
58
|
+
const arrayLiteralExpression = callExpressions[0].getArguments()[0];
|
|
59
|
+
if (!arrayLiteralExpression || !Node.isArrayLiteralExpression(arrayLiteralExpression)) {
|
|
60
|
+
throw new Error(`Cannot find middleware array in ${target} statement.`);
|
|
61
|
+
}
|
|
62
|
+
const middleware = `() => import('${middlewareEntry.path}')`;
|
|
63
|
+
/**
|
|
64
|
+
* Delete the existing middleware if it exists
|
|
65
|
+
*/
|
|
66
|
+
const existingMiddleware = arrayLiteralExpression
|
|
67
|
+
.getElements()
|
|
68
|
+
.findIndex((element) => element.getText() === middleware);
|
|
69
|
+
if (existingMiddleware !== -1) {
|
|
70
|
+
arrayLiteralExpression.removeElement(existingMiddleware);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Add the middleware to the top or bottom of the array
|
|
74
|
+
*/
|
|
75
|
+
if (middlewareEntry.position === 'before') {
|
|
76
|
+
arrayLiteralExpression.insertElement(0, middleware);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
arrayLiteralExpression.addElement(middleware);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Add a new middleware to the named middleware of the given file
|
|
84
|
+
*/
|
|
85
|
+
#addToNamedMiddleware(file, middlewareEntry) {
|
|
86
|
+
if (!middlewareEntry.name)
|
|
87
|
+
throw new Error('Named middleware requires a name.');
|
|
88
|
+
const callArguments = file
|
|
89
|
+
.getVariableDeclarationOrThrow('middleware')
|
|
90
|
+
.getInitializerIfKindOrThrow(SyntaxKind.CallExpression)
|
|
91
|
+
.getArguments();
|
|
92
|
+
if (callArguments.length === 0) {
|
|
93
|
+
throw new Error('Named middleware call has no arguments.');
|
|
94
|
+
}
|
|
95
|
+
const namedMiddlewareObject = callArguments[0];
|
|
96
|
+
if (!Node.isObjectLiteralExpression(namedMiddlewareObject)) {
|
|
97
|
+
throw new Error('The argument of the named middleware call is not an object literal.');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if property is already defined. If so, remove it
|
|
101
|
+
*/
|
|
102
|
+
const existingProperty = namedMiddlewareObject.getProperty(middlewareEntry.name);
|
|
103
|
+
if (existingProperty)
|
|
104
|
+
existingProperty.remove();
|
|
105
|
+
/**
|
|
106
|
+
* Add the named middleware
|
|
107
|
+
*/
|
|
108
|
+
const middleware = `${middlewareEntry.name}: () => import('${middlewareEntry.path}')`;
|
|
109
|
+
namedMiddlewareObject.insertProperty(0, middleware);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Write a leading comment
|
|
113
|
+
*/
|
|
114
|
+
#addLeadingComment(writer, comment) {
|
|
115
|
+
if (!comment)
|
|
116
|
+
return writer.blankLine();
|
|
117
|
+
return writer
|
|
118
|
+
.blankLine()
|
|
119
|
+
.writeLine('/*')
|
|
120
|
+
.writeLine(`|----------------------------------------------------------`)
|
|
121
|
+
.writeLine(`| ${comment}`)
|
|
122
|
+
.writeLine(`|----------------------------------------------------------`)
|
|
123
|
+
.writeLine(`*/`);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Define new middlewares inside the `start/kernel.ts`
|
|
127
|
+
* file
|
|
128
|
+
*
|
|
129
|
+
* This function is highly based on some assumptions
|
|
130
|
+
* and will not work if you significantly tweaked
|
|
131
|
+
* your `start/kernel.ts` file.
|
|
132
|
+
*/
|
|
133
|
+
async addMiddlewareToStack(stack, middleware) {
|
|
134
|
+
/**
|
|
135
|
+
* Get the `start/kernel.ts` source file
|
|
136
|
+
*/
|
|
137
|
+
const kernelUrl = fileURLToPath(new URL('./start/kernel.ts', this.#cwd));
|
|
138
|
+
const file = this.#project.getSourceFileOrThrow(kernelUrl);
|
|
139
|
+
/**
|
|
140
|
+
* Process each middleware entry
|
|
141
|
+
*/
|
|
142
|
+
for (const middlewareEntry of middleware) {
|
|
143
|
+
if (stack === 'named') {
|
|
144
|
+
this.#addToNamedMiddleware(file, middlewareEntry);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.#addToMiddlewareArray(file, `${stack}.use`, middlewareEntry);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
file.formatText(this.#editorSettings);
|
|
151
|
+
await file.save();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Add new env variable validation in the
|
|
155
|
+
* `env.ts` file
|
|
156
|
+
*/
|
|
157
|
+
async defineEnvValidations(definition) {
|
|
158
|
+
/**
|
|
159
|
+
* Get the `start/env.ts` source file
|
|
160
|
+
*/
|
|
161
|
+
const kernelUrl = fileURLToPath(new URL('./start/env.ts', this.#cwd));
|
|
162
|
+
const file = this.#project.getSourceFileOrThrow(kernelUrl);
|
|
163
|
+
/**
|
|
164
|
+
* Get the `Env.create` call expression
|
|
165
|
+
*/
|
|
166
|
+
const callExpressions = file
|
|
167
|
+
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
168
|
+
.filter((statement) => statement.getExpression().getText() === 'Env.create');
|
|
169
|
+
if (!callExpressions.length) {
|
|
170
|
+
throw new Error(`Cannot find Env.create statement in the file.`);
|
|
171
|
+
}
|
|
172
|
+
const objectLiteralExpression = callExpressions[0].getArguments()[1];
|
|
173
|
+
if (!Node.isObjectLiteralExpression(objectLiteralExpression)) {
|
|
174
|
+
throw new Error(`The second argument of Env.create is not an object literal.`);
|
|
175
|
+
}
|
|
176
|
+
let firstAdded = false;
|
|
177
|
+
/**
|
|
178
|
+
* Add each variable validation
|
|
179
|
+
*/
|
|
180
|
+
for (const [variable, validation] of Object.entries(definition.variables)) {
|
|
181
|
+
/**
|
|
182
|
+
* Check if the variable is already defined. If so, remove it
|
|
183
|
+
*/
|
|
184
|
+
const existingProperty = objectLiteralExpression.getProperty(variable);
|
|
185
|
+
if (existingProperty)
|
|
186
|
+
existingProperty.remove();
|
|
187
|
+
objectLiteralExpression.addPropertyAssignment({
|
|
188
|
+
name: variable,
|
|
189
|
+
initializer: validation,
|
|
190
|
+
leadingTrivia: (writer) => {
|
|
191
|
+
if (firstAdded)
|
|
192
|
+
return;
|
|
193
|
+
firstAdded = true;
|
|
194
|
+
return this.#addLeadingComment(writer, definition.leadingComment);
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
file.formatText(this.#editorSettings);
|
|
199
|
+
await file.save();
|
|
200
|
+
}
|
|
201
|
+
}
|