Skip to content

Commit

Permalink
implement onTargetDirectory and onReady
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima committed Nov 29, 2022
1 parent 104810e commit 77fa4b3
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 37 deletions.
111 changes: 76 additions & 35 deletions src/run-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,24 @@ export class RunContextBase<
protected environmentPromise?: PromiseRunResult<GeneratorType>;
protected editor?: MemFsEditor.Editor;

private readonly memFs: Record<string, string | Record<string, unknown>> = {};
private args: string[] = [];
private options: any = {};
private answers: any = {};

private readonly onReadyCallbacks: Array<(this: this, generator: GeneratorType) => any> = [];
private readonly onTargetDirectoryCallbacks: Array<(this: this, targetDirectory: string) => any> = [];
private readonly inDirCallbacks: any[] = [];
private readonly Generator: string | GeneratorConstructor | typeof Generator;
private readonly helpers: YeomanTest;
private readonly temporaryDir = path.join(
tempDirectory,
crypto.randomBytes(20).toString('hex'),
);

private localConfig: any = null;
private dependencies: any[] = [];
private readonly inDirCallbacks: any[] = [];
private lookups: LookupOptions[] = [];
private readonly Generator: string | GeneratorConstructor | typeof Generator;
private oldCwd?: string;
private readonly helpers: YeomanTest;
private eventListenersSet = false;
private targetDirectory?: string;
private envCB: any;
Expand All @@ -87,10 +93,6 @@ export class RunContextBase<
private errored = false;

private generatorPromise?: Promise<GeneratorType>;
private readonly temporaryDir = path.join(
tempDirectory,
crypto.randomBytes(20).toString('hex'),
);

/**
* This class provide a run context object to façade the complexity involved in setting
Expand Down Expand Up @@ -139,16 +141,21 @@ export class RunContextBase<
await this.build();
}

this.environmentPromise = this.generatorPromise!.then(async (generator) =>
this.env
.runGenerator(generator as any)
.then(() => new RunResult(this._createRunResultOptions()))
.finally(() => {
this.helpers.restorePrompt(this.env);
this.completed = true;
}),
);
return this.environmentPromise;
const generator = await this.generatorPromise!;

for (const onReadyCallback of this.onReadyCallbacks) {
// eslint-disable-next-line no-await-in-loop
await onReadyCallback.call(this, generator);
}

try {
await this.env.runGenerator(generator as any);
} finally {
this.helpers.restorePrompt(this.env);
this.completed = true;
}

return new RunResult(this._createRunResultOptions());
}

// If any event listeners is added, setup event listeners emitters
Expand Down Expand Up @@ -414,21 +421,57 @@ export class RunContextBase<
/**
* Add files to mem-fs.
* Files will be resolved relative to targetDir.
* @param fs
* @param files
*/
withFiles(fs: Record<string, string | Record<string, unknown>>): this {
Object.assign(this.memFs, fs);
withFiles(files: Record<string, string | Record<string, unknown>>): this {
return this.onTargetDirectory(function () {
for (const [file, content] of Object.entries(files)) {
const resolvedFile = isAbsolute(file)
? file
: resolve(this.targetDirectory!, file);
if (typeof content === 'string') {
this.editor!.write(resolvedFile, content);
} else {
this.editor!.writeJSON(resolvedFile, content);
}
}
});
}

/**
* Execute callback after targetDirectory is set
* @param callback
* @returns
*/
onTargetDirectory(callback: (this: this, targetDirectory: string) => any): this {
this.assertNotBuild();
this.onTargetDirectoryCallbacks.push(callback);
return this;
}

/**
* Build the generator and the environment.
* @return {RunContext|false} this
* Execute callback after environment is ready
* @param callback
* @returns
*/
protected async build(callback?: (context: any) => any): Promise<void> {
onReady(callback: (this: this, generator: GeneratorType) => any): this {
this.assertNotBuild();
this.onReadyCallbacks.push(callback);
return this;
}

protected assertNotBuild() {
if (this.ran || this.completed) {
throw new Error('The context is already built');
}
}

/**
* Build the generator and the environment.
* @return {RunContext|false} this
*/
protected async build(callback?: (context: any) => any): Promise<void> {
this.assertNotBuild();

this.ran = true;

Expand All @@ -446,7 +489,9 @@ export class RunContextBase<
}
}

this.targetDirectory = this.targetDirectory ?? process.cwd();
if (!this.targetDirectory) {
throw new Error('targetDirectory is required');
}

const testEnv = this.helpers.createTestEnv(this.envOptions.createEnv, {
cwd: this.settings.forwardCwd ? this.targetDirectory : undefined,
Expand All @@ -456,15 +501,10 @@ export class RunContextBase<
this.env = this.envCB ? (await this.envCB(testEnv)) ?? testEnv : testEnv;

this.editor = MemFsEditor.create(this.env.sharedFs);
for (const [file, content] of Object.entries(this.memFs)) {
const resolvedFile = isAbsolute(file)
? file
: resolve(this.targetDirectory, file);
if (typeof content === 'string') {
this.editor.write(resolvedFile, content);
} else {
this.editor.writeJSON(resolvedFile, content);
}

for (const onTargetDirectory of this.onTargetDirectoryCallbacks) {
// eslint-disable-next-line no-await-in-loop
await onTargetDirectory.call(this, this.targetDirectory);
}

for (const lookup of this.lookups) {
Expand Down Expand Up @@ -533,9 +573,10 @@ export class RunContextBase<

this.eventListenersSet = true;

this.onReady(generator => this.emit('ready', generator));

return this.build().then(async () =>
this.generatorPromise!.then((generator) => {
this.emit('ready', generator);
this.run()
.catch((error) => {
if (
Expand Down
36 changes: 34 additions & 2 deletions test/helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ describe('yeoman-test', function () {
});
});

describe('with a files', function () {
it('return a RunContext object', async function () {
describe('with files', function () {
it('write files to mem-fs', async function () {
const runResult = await helpers
.run(helpers.createDummyGenerator())
.withFiles({'foo.txt': 'foo', 'foo.json': {foo: 'bar'}});
Expand All @@ -310,6 +310,38 @@ describe('yeoman-test', function () {
`);
});
});

describe('callbacks', function () {
it('calls in order', async function () {
const order: string[] = [];

const runContext = helpers.run(helpers.createDummyGenerator());
await runContext
.onReady(function () {
assert.strictEqual(this, runContext);
order.push('onReady 0');
})
.onReady(function () {
assert.strictEqual(this, runContext);
order.push('onReady 1');
})
.onTargetDirectory(function () {
assert.strictEqual(this, runContext);
order.push('onTargetDir 0');
})
.onTargetDirectory(function () {
assert.strictEqual(this, runContext);
order.push('onTargetDir 1');
});

assert.deepStrictEqual(order, [
'onTargetDir 0',
'onTargetDir 1',
'onReady 0',
'onReady 1',
]);
});
});
});

describe('.createTestEnv', () => {
Expand Down

0 comments on commit 77fa4b3

Please sign in to comment.