@adonisjs/assembler 6.1.3-8 → 7.0.0-0

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.
@@ -1,142 +0,0 @@
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 getRandomPort from 'get-port';
10
- import { fileURLToPath } from 'node:url';
11
- import { execaNode, execa } from 'execa';
12
- import { EnvLoader, EnvParser } from '@adonisjs/env';
13
- import { ConfigParser, Watcher } from '@poppinss/chokidar-ts';
14
- /**
15
- * Default set of args to pass in order to run TypeScript
16
- * source. Used by "run" and "runNode" scripts
17
- */
18
- const DEFAULT_NODE_ARGS = [
19
- // Use ts-node/esm loader. The project must install it
20
- '--loader=ts-node/esm',
21
- // Disable annonying warnings
22
- '--no-warnings',
23
- // Enable expiremental meta resolve for cases where someone uses magic import string
24
- '--experimental-import-meta-resolve',
25
- ];
26
- /**
27
- * Parses tsconfig.json and prints errors using typescript compiler
28
- * host
29
- */
30
- export function parseConfig(cwd, ts) {
31
- const { config, error } = new ConfigParser(cwd, 'tsconfig.json', ts).parse();
32
- if (error) {
33
- const compilerHost = ts.createCompilerHost({});
34
- console.log(ts.formatDiagnosticsWithColorAndContext([error], compilerHost));
35
- return;
36
- }
37
- if (config.errors.length) {
38
- const compilerHost = ts.createCompilerHost({});
39
- console.log(ts.formatDiagnosticsWithColorAndContext(config.errors, compilerHost));
40
- return;
41
- }
42
- return config;
43
- }
44
- /**
45
- * Runs a Node.js script as a child process and inherits the stdio streams
46
- */
47
- export function runNode(cwd, options) {
48
- const childProcess = execaNode(options.script, options.scriptArgs, {
49
- nodeOptions: DEFAULT_NODE_ARGS.concat(options.nodeArgs),
50
- preferLocal: true,
51
- windowsHide: false,
52
- localDir: cwd,
53
- cwd,
54
- buffer: false,
55
- stdio: options.stdio || 'inherit',
56
- env: {
57
- ...(options.stdio === 'pipe' ? { FORCE_COLOR: 'true' } : {}),
58
- ...options.env,
59
- },
60
- });
61
- return childProcess;
62
- }
63
- /**
64
- * Runs a script as a child process and inherits the stdio streams
65
- */
66
- export function run(cwd, options) {
67
- const childProcess = execa(options.script, options.scriptArgs, {
68
- preferLocal: true,
69
- windowsHide: false,
70
- localDir: cwd,
71
- cwd,
72
- buffer: false,
73
- stdio: options.stdio || 'inherit',
74
- env: {
75
- ...(options.stdio === 'pipe' ? { FORCE_COLOR: 'true' } : {}),
76
- ...options.env,
77
- },
78
- });
79
- return childProcess;
80
- }
81
- /**
82
- * Watches the file system using tsconfig file
83
- */
84
- export function watch(cwd, ts, options) {
85
- const config = parseConfig(cwd, ts);
86
- if (!config) {
87
- return;
88
- }
89
- const watcher = new Watcher(typeof cwd === 'string' ? cwd : fileURLToPath(cwd), config);
90
- const chokidar = watcher.watch(['.'], { usePolling: options.poll });
91
- return { watcher, chokidar };
92
- }
93
- /**
94
- * Check if file is an .env file
95
- */
96
- export function isDotEnvFile(filePath) {
97
- if (filePath === '.env') {
98
- return true;
99
- }
100
- return filePath.includes('.env.');
101
- }
102
- /**
103
- * Check if file is .adonisrc.json file
104
- */
105
- export function isRcFile(filePath) {
106
- return filePath === '.adonisrc.json';
107
- }
108
- /**
109
- * Returns the port to use after inspect the dot-env files inside
110
- * a given directory.
111
- *
112
- * A random port is used when the specified port is in use. Following
113
- * is the logic for finding a specified port.
114
- *
115
- * - The "process.env.PORT" value is used if exists.
116
- * - The dot-env files are loaded using the "EnvLoader" and the PORT
117
- * value is by iterating over all the loaded files. The iteration
118
- * stops after first find.
119
- */
120
- export async function getPort(cwd) {
121
- /**
122
- * Use existing port if exists
123
- */
124
- if (process.env.PORT) {
125
- return getRandomPort({ port: Number(process.env.PORT) });
126
- }
127
- /**
128
- * Loop over files and use the port from their contents. Stops
129
- * after first match
130
- */
131
- const files = await new EnvLoader(cwd).load();
132
- for (let file of files) {
133
- const envVariables = new EnvParser(file.contents).parse();
134
- if (envVariables.PORT) {
135
- return getRandomPort({ port: Number(envVariables.PORT) });
136
- }
137
- }
138
- /**
139
- * Use 3333 as the port
140
- */
141
- return getRandomPort({ port: 3333 });
142
- }
@@ -1,273 +0,0 @@
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 picomatch from 'picomatch';
10
- import { cliui } from '@poppinss/cliui';
11
- import { AssetsDevServer } from './assets_dev_server.js';
12
- import { getPort, isDotEnvFile, runNode, watch } from './helpers.js';
13
- /**
14
- * Instance of CLIUI
15
- */
16
- const ui = cliui();
17
- /**
18
- * Exposes the API to start the development. Optionally, the watch API can be
19
- * used to watch for file changes and restart the development server.
20
- *
21
- * The Dev server performs the following actions
22
- *
23
- * - Assigns a random PORT, when PORT inside .env file is in use
24
- * - Uses tsconfig.json file to collect a list of files to watch.
25
- * - Uses metaFiles from .adonisrc.json file to collect a list of files to watch.
26
- * - Restart HTTP server on every file change.
27
- */
28
- export class TestRunner {
29
- #cwd;
30
- #logger = ui.logger;
31
- #options;
32
- #scriptFile = 'bin/test.js';
33
- #isMetaFile;
34
- #isTestFile;
35
- /**
36
- * In watch mode, after a file is changed, we wait for the current
37
- * set of tests to finish before triggering a re-run. Therefore,
38
- * we use this flag to know if we are already busy in running
39
- * tests and ignore file-changes.
40
- */
41
- #isBusy = false;
42
- #onError;
43
- #onClose;
44
- #testScript;
45
- #watcher;
46
- #assetsServer;
47
- /**
48
- * Getting reference to colors library from logger
49
- */
50
- get #colors() {
51
- return this.#logger.getColors();
52
- }
53
- constructor(cwd, options) {
54
- this.#cwd = cwd;
55
- this.#options = options;
56
- this.#isMetaFile = picomatch((this.#options.metaFiles || []).map(({ pattern }) => pattern));
57
- this.#isTestFile = picomatch(this.#options.suites
58
- .filter((suite) => {
59
- if (this.#options.filters.suites) {
60
- this.#options.filters.suites.includes(suite.name);
61
- }
62
- return true;
63
- })
64
- .map((suite) => suite.files)
65
- .flat(1));
66
- }
67
- /**
68
- * Converts all known filters to CLI args.
69
- *
70
- * The following code snippet may seem like repetitive code. But, it
71
- * is done intentionally to have visibility around how each filter
72
- * is converted to an arg.
73
- */
74
- #convertFiltersToArgs(filters) {
75
- const args = [];
76
- if (filters.suites) {
77
- args.push(...filters.suites);
78
- }
79
- if (filters.files) {
80
- args.push('--files');
81
- args.push(filters.files.join(','));
82
- }
83
- if (filters.groups) {
84
- args.push('--groups');
85
- args.push(filters.groups.join(','));
86
- }
87
- if (filters.tags) {
88
- args.push('--tags');
89
- args.push(filters.tags.join(','));
90
- }
91
- if (filters.ignoreTags) {
92
- args.push('--ignore-tags');
93
- args.push(filters.ignoreTags.join(','));
94
- }
95
- if (filters.tests) {
96
- args.push('--ignore-tests');
97
- args.push(filters.tests.join(','));
98
- }
99
- return args;
100
- }
101
- /**
102
- * Conditionally clear the terminal screen
103
- */
104
- #clearScreen() {
105
- if (this.#options.clearScreen) {
106
- process.stdout.write('\u001Bc');
107
- }
108
- }
109
- /**
110
- * Runs tests
111
- */
112
- #runTests(port, filtersArgs, mode) {
113
- this.#isBusy = true;
114
- this.#testScript = runNode(this.#cwd, {
115
- script: this.#scriptFile,
116
- env: { PORT: port, ...this.#options.env },
117
- nodeArgs: this.#options.nodeArgs,
118
- scriptArgs: filtersArgs.concat(this.#options.scriptArgs),
119
- });
120
- this.#testScript
121
- .then((result) => {
122
- if (mode === 'nonblocking') {
123
- this.#onClose?.(result.exitCode);
124
- this.#watcher?.close();
125
- this.#assetsServer?.stop();
126
- }
127
- })
128
- .catch((error) => {
129
- /**
130
- * Since the tests runner set the `process.exitCode = 1`, execa will
131
- * throw an exception. However, we should ignore it and keep the
132
- * watcher on.
133
- */
134
- if (mode === 'nonblocking') {
135
- this.#onError?.(error);
136
- this.#watcher?.close();
137
- this.#assetsServer?.stop();
138
- }
139
- })
140
- .finally(() => {
141
- this.#isBusy = false;
142
- });
143
- }
144
- /**
145
- * Starts the assets server
146
- */
147
- #startAssetsServer() {
148
- this.#assetsServer = new AssetsDevServer(this.#cwd, this.#options.assets);
149
- this.#assetsServer.setLogger(this.#logger);
150
- this.#assetsServer.start();
151
- }
152
- /**
153
- * Handles a non TypeScript file change
154
- */
155
- #handleFileChange(action, port, filters, relativePath) {
156
- if (this.#isBusy) {
157
- return;
158
- }
159
- if (isDotEnvFile(relativePath) || this.#isMetaFile(relativePath)) {
160
- this.#clearScreen();
161
- this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
162
- this.#runTests(port, filters, 'blocking');
163
- }
164
- }
165
- /**
166
- * Handles TypeScript source file change
167
- */
168
- #handleSourceFileChange(action, port, filters, relativePath) {
169
- if (this.#isBusy) {
170
- return;
171
- }
172
- this.#clearScreen();
173
- this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
174
- /**
175
- * If changed file is a test file after considering the initial filters,
176
- * then only run that file
177
- */
178
- if (this.#isTestFile(relativePath)) {
179
- this.#runTests(port, this.#convertFiltersToArgs({
180
- ...this.#options.filters,
181
- files: [relativePath],
182
- }), 'blocking');
183
- return;
184
- }
185
- this.#runTests(port, filters, 'blocking');
186
- }
187
- /**
188
- * Set a custom CLI UI logger
189
- */
190
- setLogger(logger) {
191
- this.#logger = logger;
192
- this.#assetsServer?.setLogger(logger);
193
- return this;
194
- }
195
- /**
196
- * Add listener to get notified when dev server is
197
- * closed
198
- */
199
- onClose(callback) {
200
- this.#onClose = callback;
201
- return this;
202
- }
203
- /**
204
- * Add listener to get notified when dev server exists
205
- * with an error
206
- */
207
- onError(callback) {
208
- this.#onError = callback;
209
- return this;
210
- }
211
- /**
212
- * Runs tests
213
- */
214
- async run() {
215
- const port = String(await getPort(this.#cwd));
216
- const initialFilters = this.#convertFiltersToArgs(this.#options.filters);
217
- this.#clearScreen();
218
- this.#startAssetsServer();
219
- this.#logger.info('booting application to run tests...');
220
- this.#runTests(port, initialFilters, 'nonblocking');
221
- }
222
- /**
223
- * Run tests in watch mode
224
- */
225
- async runAndWatch(ts, options) {
226
- const port = String(await getPort(this.#cwd));
227
- const initialFilters = this.#convertFiltersToArgs(this.#options.filters);
228
- this.#clearScreen();
229
- this.#startAssetsServer();
230
- this.#logger.info('booting application to run tests...');
231
- this.#runTests(port, initialFilters, 'blocking');
232
- /**
233
- * Create watcher using tsconfig.json file
234
- */
235
- const output = watch(this.#cwd, ts, options || {});
236
- if (!output) {
237
- this.#onClose?.(1);
238
- return;
239
- }
240
- /**
241
- * Storing reference to watcher, so that we can close it
242
- * when HTTP server exists with error
243
- */
244
- this.#watcher = output.chokidar;
245
- /**
246
- * Notify the watcher is ready
247
- */
248
- output.watcher.on('watcher:ready', () => {
249
- this.#logger.info('watching file system for changes...');
250
- });
251
- /**
252
- * Cleanup when watcher dies
253
- */
254
- output.chokidar.on('error', (error) => {
255
- this.#logger.warning('file system watcher failure');
256
- this.#logger.fatal(error);
257
- this.#onError?.(error);
258
- output.chokidar.close();
259
- });
260
- /**
261
- * Changes in TypeScript source file
262
- */
263
- output.watcher.on('source:add', ({ relativePath }) => this.#handleSourceFileChange('add', port, initialFilters, relativePath));
264
- output.watcher.on('source:change', ({ relativePath }) => this.#handleSourceFileChange('update', port, initialFilters, relativePath));
265
- output.watcher.on('source:unlink', ({ relativePath }) => this.#handleSourceFileChange('delete', port, initialFilters, relativePath));
266
- /**
267
- * Changes in non-TypeScript source files
268
- */
269
- output.watcher.on('add', ({ relativePath }) => this.#handleFileChange('add', port, initialFilters, relativePath));
270
- output.watcher.on('change', ({ relativePath }) => this.#handleFileChange('update', port, initialFilters, relativePath));
271
- output.watcher.on('unlink', ({ relativePath }) => this.#handleFileChange('delete', port, initialFilters, relativePath));
272
- }
273
- }
@@ -1,9 +0,0 @@
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
- export {};