Skip to content

Commit 607b351

Browse files
authored
Abstract REPL setup complexity in new @seedcompany/nest library (#2915)
1 parent daa879e commit 607b351

File tree

3 files changed

+79
-100
lines changed

3 files changed

+79
-100
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@patarapolw/prettyprint": "^1.0.3",
4545
"@seedcompany/common": ">=0.11 <1",
4646
"@seedcompany/data-loader": "^0.5.4",
47+
"@seedcompany/nest": ">=0.1 <1",
4748
"@seedcompany/nestjs-email": "^3.3.2",
4849
"@seedcompany/scripture": "^0.3.0",
4950
"argon2": "^0.31.1",

src/repl.ts

Lines changed: 41 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
1-
import { clc } from '@nestjs/common/utils/cli-colors.util.js';
2-
import { NestFactory } from '@nestjs/core';
3-
import { assignToObject } from '@nestjs/core/repl/assign-to-object.util.js';
4-
import { ReplContext } from '@nestjs/core/repl/repl-context.js';
5-
import { bufferFromStream } from '@seedcompany/common';
1+
import { runRepl } from '@seedcompany/nest';
62
import * as fs from 'fs';
7-
import { mkdir } from 'fs/promises';
83
// eslint-disable-next-line no-restricted-imports
94
import * as lodash from 'lodash';
105
import { DateTime, Duration, Interval } from 'luxon';
11-
import { promisify } from 'util';
12-
import { createContext, runInContext } from 'vm';
136
import {
147
CalendarDate,
158
DateInterval,
@@ -22,75 +15,44 @@ import {
2215
import * as common from '~/common';
2316
import './polyfills';
2417

25-
/**
26-
* This does the same thing as {@link import('@nestjs/core').repl}
27-
* Just that we use our own logger & add more to the global context
28-
*/
29-
async function bootstrap() {
30-
// Ensure src files are initialized here were init errors can be caught
31-
const { AppModule } = await import('./app.module');
32-
const { bootstrapLogger, ConfigService, ResourcesHost } = await import(
33-
'~/core'
34-
);
35-
const { AuthenticationService } = await import('./components/authentication');
36-
const { Pnp } = await import('./components/pnp');
37-
38-
const app = await NestFactory.createApplicationContext(AppModule, {
39-
abortOnError: false,
40-
logger: bootstrapLogger,
41-
});
42-
await app.init();
43-
44-
const session = await app
45-
.get(AuthenticationService)
46-
.sessionForUser(app.get(ConfigService).rootAdmin.id);
47-
const Resources = await app.get(ResourcesHost).getEnhancedMap();
48-
49-
const context = assignToObject(new ReplContext(app).globalScope, {
50-
DateTime,
51-
Duration,
52-
Interval,
53-
CalendarDate,
54-
DateInterval,
55-
mapFromList,
56-
many,
57-
maybeMany,
58-
common,
59-
// eslint-disable-next-line @typescript-eslint/naming-convention
60-
__: lodash, // single underscore is "last execution result"
61-
lodash,
62-
session,
63-
sessionFor: (role: Role): Session => ({
64-
...session,
65-
roles: [`global:${role}`],
66-
}),
67-
Resources,
68-
loadPnp: (filepath: string) => Pnp.fromBuffer(fs.readFileSync(filepath)),
69-
});
70-
71-
if (!process.stdin.isTTY) {
72-
const input = await bufferFromStream(process.stdin);
73-
runInContext(input.toString(), createContext(context));
74-
await app.close();
75-
return;
76-
}
77-
78-
const _repl = await Promise.resolve().then(() => import('repl'));
79-
const replServer = _repl.start({
80-
prompt: clc.green('> '),
81-
ignoreUndefined: true,
82-
});
83-
replServer.on('exit', () => void app.close());
84-
85-
assignToObject(replServer.context, context);
86-
87-
await mkdir('.cache', { recursive: true });
88-
await promisify(replServer.setupHistory.bind(replServer))(
89-
'.cache/repl_history',
90-
);
91-
}
92-
bootstrap().catch((err) => {
93-
// eslint-disable-next-line no-console
94-
console.error(err);
95-
process.exit(1);
18+
runRepl({
19+
module: () => import('./app.module').then((m) => m.AppModule),
20+
options: async () => {
21+
const { bootstrapLogger: logger } = await import('~/core');
22+
return { logger };
23+
},
24+
extraContext: async (app) => {
25+
const { ConfigService, ResourcesHost } = await import('~/core');
26+
const { AuthenticationService } = await import(
27+
'./components/authentication'
28+
);
29+
const { Pnp } = await import('./components/pnp');
30+
31+
const session = await app
32+
.get(AuthenticationService)
33+
.sessionForUser(app.get(ConfigService).rootAdmin.id);
34+
const Resources = await app.get(ResourcesHost).getEnhancedMap();
35+
36+
return {
37+
DateTime,
38+
Duration,
39+
Interval,
40+
CalendarDate,
41+
DateInterval,
42+
mapFromList,
43+
many,
44+
maybeMany,
45+
common,
46+
// eslint-disable-next-line @typescript-eslint/naming-convention
47+
__: lodash, // single underscore is "last execution result"
48+
lodash,
49+
session,
50+
sessionFor: (role: Role): Session => ({
51+
...session,
52+
roles: [`global:${role}`],
53+
}),
54+
Resources,
55+
loadPnp: (filepath: string) => Pnp.fromBuffer(fs.readFileSync(filepath)),
56+
};
57+
},
9658
});

yarn.lock

Lines changed: 37 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)