Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import minimist from 'minimist';
import createDebug from 'debug';
import { type MemFsEditor, create as createMemFsEditor } from 'mem-fs-editor';
import { type YeomanNamespace, requireNamespace, toNamespace } from '@yeoman/namespace';
import type { BaseEnvironment, BaseGenerator as GeneratorApi, Logger, QueuedAdapter } from '@yeoman/types';
import type {
BaseEnvironment,
BaseGenerator as GeneratorApi,
GeneratorMeta,
Logger,
QueuedAdapter,
} from '@yeoman/types';
import type { ArgumentSpec, BaseFeatures, BaseOptions, CliOptionSpec } from './types.js';
import type { PromptAnswers, PromptQuestion, PromptQuestions, QuestionRegistrationOptions } from './questions.js';
import Storage, { type StorageOptions } from './util/storage.js';
Expand Down Expand Up @@ -69,6 +75,8 @@ export class BaseGenerator<
readonly _ = _;
appname!: string;
args!: string[];
/** Generator metadata, provided by the environment. */
_meta!: GeneratorMeta;
/** @deprecated */
arguments!: string[];
_destinationRoot!: string;
Expand Down Expand Up @@ -157,6 +165,7 @@ export class BaseGenerator<
const { env, ...generatorOptions } = actualOptions;

// Load parameters
this._meta = ((actualOptions as any)._meta ?? {}) as GeneratorMeta;
this._args = actualArgs;
this.options = generatorOptions as any;

Expand Down Expand Up @@ -727,15 +736,32 @@ export class BaseGenerator<
* @return The name of the root generator
*/
rootGeneratorName() {
return readPackageUpSync({ cwd: this.resolved })?.packageJson?.name ?? '*';
return this.#rootGeneratorPackageJson()?.name ?? '*';
}

/**
* Determine the root generator version (the one who's extending Generator).
* @return The version of the root generator
*/
rootGeneratorVersion() {
return readPackageUpSync({ cwd: this.resolved })?.packageJson?.version ?? '0.0.0';
return this.#rootGeneratorPackageJson()?.version ?? '0.0.0';
}

/**
* The root generator's package.json.
*
* Uses `meta.getPackageJson` when provided by the environment (parsed once per package and cached by the environment).
* Otherwise, when the generator package's path is provided through meta, read its package.json directly.
* Otherwise (legacy environments, stubs, direct instantiation) look the package.json up from the resolved path,
* skipping normalization since only `name` and `version` are used.
*/
#rootGeneratorPackageJson(): PackageJson | undefined {
const packageJson = (this as any)._meta?.getPackageJson?.();
if (packageJson) {
return packageJson as PackageJson;
}

return readPackageUpSync({ cwd: this.resolved, normalize: false })?.packageJson;
}

/**
Expand Down
10 changes: 10 additions & 0 deletions test/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,16 @@ describe('Base', () => {
fs.writeFileSync(path.join(resolveddir, 'package.json'), '{ "name": "generator-name" }');
expect(dummy.rootGeneratorName()).toBe('generator-name');
});

it('returns generator name from meta getPackageJson', () => {
const getPackageJson = vi.fn().mockReturnValue({ name: 'generator-meta-name', version: '2.0.0' });
// The environment sets the meta after instantiation.
dummy._meta = { namespace: 'dummy', getPackageJson };

expect(dummy.rootGeneratorName()).toBe('generator-meta-name');
expect(dummy.rootGeneratorVersion()).toBe('2.0.0');
expect(getPackageJson).toHaveBeenCalledTimes(2);
});
});

describe('#rootGeneratorVersion', () => {
Expand Down
Loading