yeoman-environment 5.0.0-beta.0 → 5.0.0-beta.1

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/bin/bin.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  (async function () {
3
+ // eslint-disable-next-line import-x/extensions
3
4
  await import('../dist/cli/index.js');
4
5
  })();
package/dist/cli/index.js CHANGED
@@ -2,9 +2,9 @@ import { readFileSync } from 'node:fs';
2
2
  import process from 'node:process';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import YeomanCommand, { addEnvironmentOptions } from '../util/command.js';
6
- import { createEnv as createEnvironment } from '../index.js';
7
- import { environmentAction, printGroupedGenerator } from './utils.js';
5
+ import YeomanCommand, { addEnvironmentOptions } from "../util/command.js";
6
+ import { createEnv as createEnvironment } from "../index.js";
7
+ import { environmentAction, printGroupedGenerator } from "./utils.js";
8
8
  const program = new YeomanCommand();
9
9
  const packageJson = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json')).toString());
10
10
  program.version(packageJson.version).allowExcessArguments(false).enablePositionalOptions();
@@ -1,5 +1,5 @@
1
1
  import type { BaseGeneratorMeta } from '@yeoman/types';
2
- import type YeomanCommand from '../util/command.js';
2
+ import type YeomanCommand from '../util/command.ts';
3
3
  export declare const printGroupedGenerator: (generators: BaseGeneratorMeta[]) => void;
4
4
  /**
5
5
  * @param {string} generatorNamespace
package/dist/cli/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { requireNamespace } from '@yeoman/namespace';
2
2
  import { groupBy } from 'lodash-es';
3
3
  import createLogger from 'debug';
4
- import { createEnv as createEnvironment } from '../index.js';
4
+ import { createEnv as createEnvironment } from "../index.js";
5
5
  const debug = createLogger('yeoman:yoe');
6
6
  export const printGroupedGenerator = (generators) => {
7
7
  const grouped = groupBy(generators, 'packagePath');
@@ -1,5 +1,5 @@
1
- import { type BaseGeneratorConstructor } from '@yeoman/types';
2
- import YeomanCommand from './util/command.js';
1
+ import type { BaseGeneratorConstructor } from '@yeoman/types';
2
+ import YeomanCommand from './util/command.ts';
3
3
  export type CommandPreparation = {
4
4
  resolved?: string;
5
5
  command?: YeomanCommand;
package/dist/commands.js CHANGED
@@ -1,5 +1,5 @@
1
- import YeomanCommand, { addEnvironmentOptions } from './util/command.js';
2
- import { createEnv as createEnvironment } from './index.js';
1
+ import YeomanCommand, { addEnvironmentOptions } from "./util/command.js";
2
+ import { createEnv as createEnvironment } from "./index.js";
3
3
  /**
4
4
  * Prepare a commander instance for cli support.
5
5
  *
package/dist/commit.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createConflicterTransform, createYoResolveTransform, forceYoFiles } from '@yeoman/conflicter';
2
2
  import createdLogger from 'debug';
3
+ import {} from 'mem-fs-editor';
3
4
  import { createCommitTransform } from 'mem-fs-editor/transform';
4
5
  import { isFilePending } from 'mem-fs-editor/state';
5
6
  const debug = createdLogger('yeoman:environment:commit');
@@ -1,4 +1,5 @@
1
1
  import type { BaseGenerator, Logger } from '@yeoman/types';
2
+ import type { InstallTask } from './package-manager.ts';
2
3
  export declare class ComposedStore {
3
4
  private readonly log?;
4
5
  private readonly generators;
@@ -7,8 +8,8 @@ export declare class ComposedStore {
7
8
  constructor({ log }?: {
8
9
  log?: Logger;
9
10
  });
10
- get customCommitTask(): any;
11
- get customInstallTask(): any;
11
+ get customCommitTask(): (() => Promise<void> | void) | undefined;
12
+ get customInstallTask(): InstallTask | undefined;
12
13
  getGenerators(): Record<string, BaseGenerator>;
13
14
  addGenerator(generator: BaseGenerator): {
14
15
  uniqueBy: any;
@@ -22,9 +23,9 @@ export declare class ComposedStore {
22
23
  uniqueBy?: undefined;
23
24
  };
24
25
  getUniqueByPathMap(root: string): Map<string, BaseGenerator>;
25
- findFeature(featureName: string): Array<{
26
+ findFeature<T = unknown>(featureName: string): Array<{
26
27
  generatorId: string;
27
- feature: any;
28
+ feature: T;
28
29
  }>;
29
30
  private findUniqueFeature;
30
31
  }
@@ -58,7 +58,7 @@ export class ComposedStore {
58
58
  .map(([generatorId, generator]) => {
59
59
  const { features = generator.getFeatures?.() } = generator;
60
60
  const feature = features?.[featureName];
61
- return feature ? { generatorId, feature } : undefined;
61
+ return feature ? { generatorId, feature: feature } : undefined;
62
62
  })
63
63
  .filter(Boolean);
64
64
  }
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from 'node:events';
2
2
  import { QueuedAdapter, type TerminalAdapterOptions } from '@yeoman/adapter';
3
- import type { ApplyTransformsOptions, BaseEnvironment, BaseEnvironmentOptions, BaseGenerator, BaseGeneratorConstructor, BaseGeneratorMeta, ComposeOptions, GeneratorMeta, GetGeneratorConstructor, InputOutputAdapter, InstantiateOptions, LookupGeneratorMeta } from '@yeoman/types';
3
+ import type { ApplyTransformsOptions, BaseEnvironment, BaseEnvironmentOptions, BaseGenerator, BaseGeneratorConstructorMeta, BaseGeneratorMeta, ComposeOptions, GeneratorMeta, GetGeneratorConstructor, InputOutputAdapter, InstantiateOptions, LookupGeneratorMeta } from '@yeoman/types';
4
4
  import { type Store as MemFs } from 'mem-fs';
5
5
  import { type MemFsEditorFile } from 'mem-fs-editor';
6
6
  import { FlyRepository } from 'fly-import';
@@ -8,10 +8,11 @@ import GroupedQueue from 'grouped-queue';
8
8
  import { type FilePipelineTransform } from '@yeoman/transform';
9
9
  import { type YeomanNamespace } from '@yeoman/namespace';
10
10
  import { type ConflicterOptions } from '@yeoman/conflicter';
11
- import { ComposedStore } from './composed-store.js';
12
- import Store from './store.js';
13
- import type YeomanCommand from './util/command.js';
14
- import { type LookupOptions } from './generator-lookup.js';
11
+ import { ComposedStore } from './composed-store.ts';
12
+ import Store from './store.ts';
13
+ import type YeomanCommand from './util/command.ts';
14
+ import { type LookupOptions } from './generator-lookup.ts';
15
+ import { type InstallTask } from './package-manager.ts';
15
16
  export type EnvironmentLookupOptions = LookupOptions & {
16
17
  /** Add a scope to the namespace if there is no scope */
17
18
  registerToScope?: string;
@@ -64,7 +65,7 @@ export default class EnvironmentBase extends EventEmitter implements BaseEnviron
64
65
  * @param namespaceOrPath
65
66
  * @return the generator meta registered under the namespace
66
67
  */
67
- findMeta(namespaceOrPath: string | YeomanNamespace): Promise<GeneratorMeta | undefined>;
68
+ findMeta(namespaceOrPath: string | YeomanNamespace): GeneratorMeta | undefined;
68
69
  /**
69
70
  * Get a single generator from the registered list of generators. The lookup is
70
71
  * based on generator's namespace, "walking up" the namespaces until a matching
@@ -75,7 +76,7 @@ export default class EnvironmentBase extends EventEmitter implements BaseEnviron
75
76
  * @param namespaceOrPath
76
77
  * @return the generator registered under the namespace
77
78
  */
78
- get<C extends BaseGeneratorConstructor = BaseGeneratorConstructor>(namespaceOrPath: string | YeomanNamespace): Promise<C | undefined>;
79
+ get<G extends BaseGenerator = BaseGenerator>(namespaceOrPath: string | YeomanNamespace): Promise<(GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta) | undefined> | ((GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta) | undefined);
79
80
  /**
80
81
  * Create is the Generator factory. It takes a namespace to lookup and optional
81
82
  * hash of options, that lets you define `arguments` and `options` to
@@ -87,7 +88,7 @@ export default class EnvironmentBase extends EventEmitter implements BaseEnviron
87
88
  * @param instantiateOptions
88
89
  * @return The instantiated generator
89
90
  */
90
- create<G extends BaseGenerator = BaseGenerator>(namespaceOrPath: string | GetGeneratorConstructor<G>, instantiateOptions?: InstantiateOptions<G>): Promise<G>;
91
+ create<G extends BaseGenerator = BaseGenerator>(namespaceOrPath: string | (GetGeneratorConstructor<G> & Partial<BaseGeneratorConstructorMeta>), instantiateOptions?: InstantiateOptions<G>): Promise<G>;
91
92
  /**
92
93
  * Instantiate a Generator with metadatas
93
94
  *
@@ -245,7 +246,7 @@ export default class EnvironmentBase extends EventEmitter implements BaseEnviron
245
246
  watchForPackageManagerInstall({ cwd, queueTask, installTask, }?: {
246
247
  cwd?: string;
247
248
  queueTask?: boolean;
248
- installTask?: (nodePackageManager: string | undefined, defaultTask: () => Promise<boolean>) => void | Promise<void>;
249
+ installTask?: InstallTask;
249
250
  }): void;
250
251
  /**
251
252
  * Start Environment queue
@@ -5,41 +5,44 @@ import process from 'node:process';
5
5
  import { realpathSync } from 'node:fs';
6
6
  import { QueuedAdapter } from '@yeoman/adapter';
7
7
  import { create as createMemFs } from 'mem-fs';
8
+ import {} from 'mem-fs-editor';
8
9
  import { FlyRepository } from 'fly-import';
9
10
  import createdLogger from 'debug';
10
- // @ts-expect-error grouped-queue don't have types
11
11
  import GroupedQueue from 'grouped-queue';
12
12
  import { isFilePending } from 'mem-fs-editor/state';
13
13
  import { filePipeline, transform } from '@yeoman/transform';
14
14
  import { toNamespace } from '@yeoman/namespace';
15
15
  import chalk from 'chalk';
16
+ import {} from '@yeoman/conflicter';
16
17
  import { defaults, pick } from 'lodash-es';
17
- import { ComposedStore } from './composed-store.js';
18
- import Store from './store.js';
19
- import { asNamespace, defaultLookups } from './util/namespace.js';
20
- import { lookupGenerators } from './generator-lookup.js';
21
- import { UNKNOWN_NAMESPACE, UNKNOWN_RESOLVED, defaultQueues } from './constants.js';
22
- import { resolveModulePath } from './util/resolve.js';
23
- import { commitSharedFsTask } from './commit.js';
24
- import { packageManagerInstallTask } from './package-manager.js';
25
- import { splitArgsFromString as splitArgumentsFromString } from './util/util.js';
18
+ import { ComposedStore } from "./composed-store.js";
19
+ import Store from "./store.js";
20
+ import { asNamespace, defaultLookups } from "./util/namespace.js";
21
+ import { lookupGenerators } from "./generator-lookup.js";
22
+ import { UNKNOWN_NAMESPACE, UNKNOWN_RESOLVED, defaultQueues } from "./constants.js";
23
+ import { resolveModulePath } from "./util/resolve.js";
24
+ import { commitSharedFsTask } from "./commit.js";
25
+ import { packageManagerInstallTask } from "./package-manager.js";
26
+ import { splitArgsFromString as splitArgumentsFromString } from "./util/util.js";
26
27
  const require = createRequire(import.meta.url);
27
28
  const ENVIRONMENT_VERSION = require('../package.json').version;
28
29
  const debug = createdLogger('yeoman:environment');
29
- const getInstantiateOptions = (arguments_, options) => {
30
- if (Array.isArray(arguments_) || typeof arguments_ === 'string') {
31
- return { generatorArgs: splitArgumentsFromString(arguments_), generatorOptions: options };
30
+ const getInstantiateOptions = (firstArg, generatorOptions) => {
31
+ // First argument can be an array of string, a string, a ComposeOptions, a GeneratorOptions, old variant of ComposeOptions.
32
+ if (Array.isArray(firstArg) || typeof firstArg === 'string') {
33
+ return { generatorArgs: splitArgumentsFromString(firstArg), generatorOptions };
32
34
  }
33
- if (arguments_ !== undefined) {
34
- if ('generatorOptions' in arguments_ || 'generatorArgs' in arguments_) {
35
- return arguments_;
35
+ if (firstArg !== undefined) {
36
+ if ('generatorOptions' in firstArg || 'generatorArgs' in firstArg) {
37
+ return firstArg;
36
38
  }
37
- if ('options' in arguments_ || 'arguments' in arguments_ || 'args' in arguments_) {
38
- const { args: insideArguments, arguments: generatorArguments = insideArguments, options: generatorOptions, ...remainingOptions } = arguments_;
39
+ if ('options' in firstArg || 'arguments' in firstArg || 'args' in firstArg) {
40
+ // Backward compatibility
41
+ const { args: insideArguments, arguments: generatorArguments = insideArguments, options: generatorOptions, ...remainingOptions } = firstArg;
39
42
  return { generatorArgs: splitArgumentsFromString(generatorArguments), generatorOptions: generatorOptions ?? remainingOptions };
40
43
  }
41
44
  }
42
- return { generatorOptions: options };
45
+ return { generatorOptions };
43
46
  };
44
47
  const getComposeOptions = (...varargs) => {
45
48
  if (varargs.filter(Boolean).length === 0)
@@ -156,7 +159,7 @@ export default class EnvironmentBase extends EventEmitter {
156
159
  * @param namespaceOrPath
157
160
  * @return the generator meta registered under the namespace
158
161
  */
159
- async findMeta(namespaceOrPath) {
162
+ findMeta(namespaceOrPath) {
160
163
  // Stop the recursive search if nothing is left
161
164
  if (!namespaceOrPath) {
162
165
  return;
@@ -171,7 +174,7 @@ export default class EnvironmentBase extends EventEmitter {
171
174
  return maybeMeta;
172
175
  }
173
176
  try {
174
- const resolved = await resolveModulePath(namespaceOrPath);
177
+ const resolved = resolveModulePath(namespaceOrPath);
175
178
  if (resolved) {
176
179
  return this.store.add({ resolved, namespace: this.namespace(resolved) });
177
180
  }
@@ -191,19 +194,17 @@ export default class EnvironmentBase extends EventEmitter {
191
194
  * @param namespaceOrPath
192
195
  * @return the generator registered under the namespace
193
196
  */
194
- async get(namespaceOrPath) {
195
- const meta = await this.findMeta(namespaceOrPath);
196
- return meta?.importGenerator();
197
+ get(namespaceOrPath) {
198
+ return this.findMeta(namespaceOrPath)?.importGenerator();
197
199
  }
198
- async create(namespaceOrPath, ...arguments_) {
199
- let constructor;
200
+ create(namespaceOrPath, ...arguments_) {
200
201
  const namespace = typeof namespaceOrPath === 'string' ? toNamespace(namespaceOrPath) : undefined;
201
202
  const checkGenerator = (Generator) => {
202
203
  const generatorNamespace = Generator?.namespace;
203
- if (namespace && generatorNamespace !== namespace.namespace && generatorNamespace !== UNKNOWN_NAMESPACE) {
204
+ if (namespace && generatorNamespace && generatorNamespace !== namespace.namespace && generatorNamespace !== UNKNOWN_NAMESPACE) {
204
205
  // Update namespace object in case of aliased namespace.
205
206
  try {
206
- namespace.namespace = Generator.namespace;
207
+ namespace.namespace = generatorNamespace;
207
208
  }
208
209
  catch {
209
210
  // Invalid namespace can be aliased to a valid one.
@@ -220,26 +221,25 @@ export default class EnvironmentBase extends EventEmitter {
220
221
  }
221
222
  return Generator;
222
223
  };
223
- if (typeof namespaceOrPath !== 'string') {
224
- return this.instantiate(checkGenerator(namespaceOrPath), ...arguments_);
225
- }
226
224
  if (typeof namespaceOrPath === 'string') {
227
- const meta = await this.findMeta(namespaceOrPath);
228
- constructor = await meta?.importGenerator();
225
+ const meta = this.findMeta(namespaceOrPath);
226
+ const constructor = meta?.importGenerator();
229
227
  if (namespace && !constructor) {
230
228
  // Await this.lookupLocalNamespaces(namespace);
231
229
  // constructor = await this.get(namespace);
232
230
  }
233
- if (constructor) {
234
- constructor._meta = meta;
231
+ if (constructor && 'then' in constructor) {
232
+ return constructor.then(g => {
233
+ return this.instantiate(checkGenerator(g), ...arguments_);
234
+ });
235
235
  }
236
+ return this.instantiate(checkGenerator(constructor), ...arguments_);
236
237
  }
237
238
  else {
238
- constructor = namespaceOrPath;
239
+ return this.instantiate(checkGenerator(namespaceOrPath), ...arguments_);
239
240
  }
240
- return this.instantiate(checkGenerator(constructor), ...arguments_);
241
241
  }
242
- async instantiate(constructor, ...arguments_) {
242
+ instantiate(constructor, ...arguments_) {
243
243
  const composeOptions = arguments_.length > 0 ? getInstantiateOptions(...arguments_) : {};
244
244
  const { namespace = UNKNOWN_NAMESPACE, resolved = UNKNOWN_RESOLVED, _meta } = constructor;
245
245
  const environmentOptions = { env: this, resolved, namespace };
@@ -255,7 +255,7 @@ export default class EnvironmentBase extends EventEmitter {
255
255
  ...environmentOptions,
256
256
  };
257
257
  if (!composeOptions.generatorOptions?.help && generator._postConstruct) {
258
- await generator._postConstruct();
258
+ return Promise.resolve(generator._postConstruct()).then(() => generator);
259
259
  }
260
260
  return generator;
261
261
  }
@@ -325,10 +325,12 @@ export default class EnvironmentBase extends EventEmitter {
325
325
  await generator.queueTasks();
326
326
  return;
327
327
  }
328
- if (!generator.options.forwardErrorToEnvironment) {
329
- generator.on('error', (error) => this.emit('error', error));
328
+ // Backward compatibility
329
+ const oldGenerator = generator;
330
+ if (!oldGenerator.options.forwardErrorToEnvironment) {
331
+ oldGenerator.on('error', (error) => this.emit('error', error));
330
332
  }
331
- generator.promise = generator.run();
333
+ oldGenerator.promise = oldGenerator.run();
332
334
  };
333
335
  if (schedule) {
334
336
  this.queueTask('environment:run', async () => runGenerator());
@@ -498,7 +500,7 @@ export default class EnvironmentBase extends EventEmitter {
498
500
  if (typeof match !== 'string') {
499
501
  throw new TypeError('string is required');
500
502
  }
501
- const aliases = [...this.aliases].reverse();
503
+ const aliases = [...this.aliases].toReversed();
502
504
  return aliases.reduce((resolved, alias) => {
503
505
  if (!alias.match.test(resolved)) {
504
506
  return resolved;
@@ -549,7 +551,8 @@ export default class EnvironmentBase extends EventEmitter {
549
551
  return new Promise((resolve, reject) => {
550
552
  Object.assign(this.options, removePropertiesWithNullishValues(pick(options, ['skipInstall', 'nodePackageManager'])));
551
553
  this.logCwd = options.logCwd ?? this.logCwd;
552
- this.conflicterOptions = pick(defaults({}, this.options, options), ['force', 'bail', 'ignoreWhitespace', 'dryRun', 'skipYoResolve']);
554
+ const conflicterOptionsProperties = ['force', 'bail', 'ignoreWhitespace', 'dryRun', 'skipYoResolve'];
555
+ this.conflicterOptions = defaults({}, pick(this.options, conflicterOptionsProperties), pick(options, conflicterOptionsProperties));
553
556
  this.conflicterOptions.cwd = this.logCwd;
554
557
  this.queueCommit();
555
558
  this.queueTask('install', () => {
@@ -1,6 +1,6 @@
1
- import type { BaseGeneratorConstructor } from '@yeoman/types';
2
- import { type LookupOptions } from './generator-lookup.js';
3
- import EnvironmentBase, { type EnvironmentOptions } from './environment-base.js';
1
+ import type { BaseGeneratorConstructor, BaseGeneratorOptions, GeneratorEnvironmentOptions } from '@yeoman/types';
2
+ import { type LookupOptions } from './generator-lookup.ts';
3
+ import EnvironmentBase, { type EnvironmentOptions } from './environment-base.ts';
4
4
  declare class FullEnvironment extends EnvironmentBase {
5
5
  constructor(options?: EnvironmentOptions);
6
6
  /**
@@ -14,7 +14,7 @@ declare class FullEnvironment extends EnvironmentBase {
14
14
  *
15
15
  * @param {Object} options
16
16
  */
17
- loadSharedOptions(options: EnvironmentOptions): Pick<EnvironmentOptions, "skipInstall" | "forceInstall" | "skipCache" | "skipLocalCache" | "skipParseOptions" | "localConfigOnly" | "askAnswered">;
17
+ loadSharedOptions(options: EnvironmentOptions): Pick<EnvironmentOptions, "askAnswered" | "skipInstall" | "forceInstall" | "skipCache" | "skipLocalCache" | "skipParseOptions" | "localConfigOnly">;
18
18
  /**
19
19
  * @protected
20
20
  * Outputs the general help and usage. Optionally, if generators have been
@@ -107,10 +107,7 @@ declare class FullEnvironment extends EnvironmentBase {
107
107
  * on the provided arguments, options and the list of registered generators.
108
108
  *
109
109
  * When the environment was unable to resolve a generator, an error is raised.
110
- *
111
- * @param {String|Array} args
112
- * @param {Object} [options]
113
110
  */
114
- run(arguments_?: string[], options?: any): Promise<void>;
111
+ run(arguments_?: string | string[], options?: EnvironmentOptions & BaseGeneratorOptions & Partial<GeneratorEnvironmentOptions>): Promise<void>;
115
112
  }
116
113
  export default FullEnvironment;
@@ -4,9 +4,10 @@ import { requireNamespace, toNamespace } from '@yeoman/namespace';
4
4
  import { flyImport } from 'fly-import';
5
5
  import { defaults, pick, uniq } from 'lodash-es';
6
6
  import { valid } from 'semver';
7
- import YeomanCommand from './util/command.js';
8
- import EnvironmentBase from './environment-base.js';
9
- import { splitArgsFromString as splitArgumentsFromString } from './util/util.js';
7
+ import {} from "./generator-lookup.js";
8
+ import YeomanCommand from "./util/command.js";
9
+ import EnvironmentBase, {} from "./environment-base.js";
10
+ import { splitArgsFromString as splitArgumentsFromString } from "./util/util.js";
10
11
  class FullEnvironment extends EnvironmentBase {
11
12
  constructor(options = {}, adapterCompat) {
12
13
  if (adapterCompat) {
@@ -156,7 +157,7 @@ class FullEnvironment extends EnvironmentBase {
156
157
  // Instantiate the generator for options
157
158
  const generator = await this.create(namespace.namespace, { generatorArgs: [], generatorOptions: { help: true } });
158
159
  namespaceCommand.registerGenerator(generator);
159
- namespaceCommand._parseCommand([], arguments_);
160
+ namespaceCommand.parse(arguments_, { from: 'user' });
160
161
  return this.run([namespace.namespace, ...namespaceCommand.args], {
161
162
  ...namespaceCommand.opts(),
162
163
  });
@@ -287,13 +288,9 @@ class FullEnvironment extends EnvironmentBase {
287
288
  * on the provided arguments, options and the list of registered generators.
288
289
  *
289
290
  * When the environment was unable to resolve a generator, an error is raised.
290
- *
291
- * @param {String|Array} args
292
- * @param {Object} [options]
293
291
  */
294
- async run(arguments_, options) {
292
+ async run(arguments_, options = {}) {
295
293
  arguments_ = Array.isArray(arguments_) ? arguments_ : splitArgumentsFromString(arguments_);
296
- options = { ...options };
297
294
  let name = arguments_.shift();
298
295
  if (!name) {
299
296
  throw new Error('Must provide at least one argument, the generator namespace to invoke.');
@@ -312,10 +309,7 @@ class FullEnvironment extends EnvironmentBase {
312
309
  }
313
310
  const generator = await this.create(name, {
314
311
  generatorArgs: arguments_,
315
- generatorOptions: {
316
- ...options,
317
- initialGenerator: true,
318
- },
312
+ generatorOptions: options,
319
313
  });
320
314
  if (options.help) {
321
315
  console.log(generator.help());
@@ -1,5 +1,5 @@
1
- import { type LookupOptions as LookupOptionsApi } from '@yeoman/types';
2
- import { type ModuleLookupOptions } from './module-lookup.js';
1
+ import type { LookupOptions as LookupOptionsApi } from '@yeoman/types';
2
+ import { type ModuleLookupOptions } from './module-lookup.ts';
3
3
  export type LookupOptions = LookupOptionsApi & ModuleLookupOptions & {
4
4
  lookups?: string[];
5
5
  };
@@ -1,8 +1,8 @@
1
1
  import { extname, isAbsolute, join, posix } from 'node:path';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import { requireNamespace, toNamespace } from '@yeoman/namespace';
4
- import { findPackagesIn, getNpmPaths, moduleLookupSync } from './module-lookup.js';
5
- import { asNamespace, defaultLookups } from './util/namespace.js';
4
+ import { findPackagesIn, getNpmPaths, moduleLookupSync } from "./module-lookup.js";
5
+ import { asNamespace, defaultLookups } from "./util/namespace.js";
6
6
  export const defaultExtensions = ['.ts', '.cts', '.mts', '.js', '.cjs', '.mjs'];
7
7
  /**
8
8
  * Search for generators and their sub generators.
@@ -69,7 +69,7 @@ export function lookupGenerator(namespace, options) {
69
69
  options.filePatterns = options.filePatterns ?? defaultLookups.map(prefix => join(prefix, '*/index.{js,ts}'));
70
70
  const ns = requireNamespace(namespace);
71
71
  options.packagePatterns = options.packagePatterns ?? [ns.generatorHint];
72
- options.npmPaths = options.npmPaths ?? getNpmPaths({ localOnly: options.localOnly }).reverse();
72
+ options.npmPaths = options.npmPaths ?? getNpmPaths({ localOnly: options.localOnly }).toReversed();
73
73
  options.packagePatterns = options.packagePatterns ?? ['generator-*'];
74
74
  options.packagePaths = options.packagePaths ?? findPackagesIn(options.npmPaths, options.packagePatterns);
75
75
  let paths = options.singleResult ? undefined : [];
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { type EnvironmentOptions } from './environment-base.js';
2
- import Environment from './environment-full.js';
3
- export { default } from './environment-full.js';
4
- export { default as EnvironmentBase } from './environment-base.js';
1
+ import { type EnvironmentOptions } from './environment-base.ts';
2
+ import Environment from './environment-full.ts';
3
+ export { default } from './environment-full.ts';
4
+ export { default as EnvironmentBase } from './environment-base.ts';
5
5
  export declare const createEnv: (options?: EnvironmentOptions) => Environment;
6
- export * from './commands.js';
7
- export * from './util/command.js';
8
- export * from './package-manager.js';
9
- export * from './commit.js';
10
- export { lookupGenerator } from './generator-lookup.js';
6
+ export declare const enforceUpdate: () => void;
7
+ export * from './commands.ts';
8
+ export * from './util/command.ts';
9
+ export * from './package-manager.ts';
10
+ export * from './commit.ts';
11
+ export { lookupGenerator } from './generator-lookup.ts';
package/dist/index.js CHANGED
@@ -1,9 +1,12 @@
1
- import Environment from './environment-full.js';
2
- export { default } from './environment-full.js';
3
- export { default as EnvironmentBase } from './environment-base.js';
1
+ import {} from "./environment-base.js";
2
+ import Environment from "./environment-full.js";
3
+ export { default } from "./environment-full.js";
4
+ export { default as EnvironmentBase } from "./environment-base.js";
4
5
  export const createEnv = (options) => new Environment(options);
5
- export * from './commands.js';
6
- export * from './util/command.js';
7
- export * from './package-manager.js';
8
- export * from './commit.js';
9
- export { lookupGenerator } from './generator-lookup.js';
6
+ // Backward compatibility
7
+ export const enforceUpdate = () => { };
8
+ export * from "./commands.js";
9
+ export * from "./util/command.js";
10
+ export * from "./package-manager.js";
11
+ export * from "./commit.js";
12
+ export { lookupGenerator } from "./generator-lookup.js";
@@ -7,7 +7,7 @@ import { compact, uniq } from 'lodash-es';
7
7
  import { globbySync } from 'globby';
8
8
  import slash from 'slash';
9
9
  import createdLogger from 'debug';
10
- import { execaOutput } from './util/util.js';
10
+ import { execaOutput } from "./util/util.js";
11
11
  const __filename = fileURLToPath(import.meta.url);
12
12
  const __dirname = dirname(__filename);
13
13
  const PROJECT_ROOT = join(__dirname, '..');
@@ -25,13 +25,13 @@ export function moduleLookupSync(options, find) {
25
25
  if (options.packagePaths) {
26
26
  options.packagePaths = arrify(options.packagePaths);
27
27
  if (options.reverse) {
28
- options.packagePaths = options.packagePaths.reverse();
28
+ options.packagePaths = options.packagePaths.toReversed();
29
29
  }
30
30
  }
31
31
  else {
32
32
  options.npmPaths = options.npmPaths ?? getNpmPaths(options);
33
33
  if (options.reverse && Array.isArray(options.npmPaths)) {
34
- options.npmPaths = options.npmPaths.reverse();
34
+ options.npmPaths = options.npmPaths.toReversed();
35
35
  }
36
36
  options.packagePatterns = arrify(options.packagePatterns ?? PACKAGE_NAME_PATTERN).map(packagePattern => slash(packagePattern));
37
37
  options.packagePaths = findPackagesIn(options.npmPaths, options.packagePatterns);
@@ -161,7 +161,7 @@ function getLocalNpmPaths() {
161
161
  }
162
162
  paths.push(lookup);
163
163
  });
164
- return uniq(paths.reverse());
164
+ return uniq(paths.toReversed());
165
165
  }
166
166
  /**
167
167
  * Get the global npm lookup directories
@@ -203,12 +203,12 @@ function getGlobalNpmPaths(filterPaths = true) {
203
203
  // Ex: /usr/another_global/node_modules/yeoman-denerator/node_modules/yeoman-environment/lib (1 level dependency)
204
204
  paths.push(...filterValidNpmPath(join(PROJECT_ROOT, '../../..'), !filterPaths));
205
205
  // Ex: /usr/another_global/node_modules/yeoman-environment/lib (installed directly)
206
+ // eslint-disable-next-line unicorn/prefer-single-call
206
207
  paths.push(join(PROJECT_ROOT, '..'));
207
208
  // Get yarn global directory and infer the module paths from there
208
209
  const yarnBase = execaOutput('yarn', ['global', 'dir']);
209
210
  if (yarnBase) {
210
- paths.push(resolve(yarnBase, 'node_modules'));
211
- paths.push(resolve(yarnBase, '../link/'));
211
+ paths.push(resolve(yarnBase, 'node_modules'), resolve(yarnBase, '../link/'));
212
212
  }
213
213
  // Get npm global prefix and infer the module paths from there
214
214
  const globalInstall = execaOutput('npm', ['root', '-g']);
@@ -219,5 +219,5 @@ function getGlobalNpmPaths(filterPaths = true) {
219
219
  if (process.argv[1]) {
220
220
  paths.push(...filterValidNpmPath(join(dirname(process.argv[1]), '../..'), !filterPaths));
221
221
  }
222
- return uniq(paths.filter(Boolean).reverse());
222
+ return uniq(paths.filter(Boolean).toReversed());
223
223
  }
@@ -1,12 +1,13 @@
1
1
  import type { MemFsEditorFile } from 'mem-fs-editor';
2
- import { type InputOutputAdapter } from '@yeoman/types';
3
- import { type Store } from 'mem-fs';
2
+ import type { InputOutputAdapter } from '@yeoman/types';
3
+ import type { Store } from 'mem-fs';
4
+ export type InstallTask = (nodePackageManager: string | undefined, defaultTask: () => Promise<boolean>) => void | Promise<void>;
4
5
  export type PackageManagerInstallTaskOptions = {
5
6
  memFs: Store<MemFsEditorFile>;
6
7
  packageJsonLocation: string;
7
8
  adapter: InputOutputAdapter;
8
9
  nodePackageManager?: string;
9
- customInstallTask?: boolean | ((nodePackageManager: string | undefined, defaultTask: () => Promise<boolean>) => void | Promise<void>);
10
+ customInstallTask?: boolean | InstallTask;
10
11
  skipInstall?: boolean;
11
12
  };
12
13
  /**
package/dist/store.d.ts CHANGED
@@ -7,10 +7,10 @@ import type { BaseEnvironment, BaseGeneratorMeta, GeneratorMeta, GetGeneratorCon
7
7
  * @private
8
8
  */
9
9
  export default class Store {
10
- private readonly environment;
11
10
  private readonly _meta;
12
11
  private readonly _packagesPaths;
13
12
  private readonly _packagesNS;
13
+ private readonly environment;
14
14
  constructor(environment: BaseEnvironment);
15
15
  /**
16
16
  * Store a module under the namespace key
package/dist/store.js CHANGED
@@ -1,3 +1,11 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
1
9
  import { pathToFileURL } from 'node:url';
2
10
  import { extname, join } from 'node:path';
3
11
  import { createRequire } from 'node:module';
@@ -13,12 +21,12 @@ const require = createRequire(import.meta.url);
13
21
  * @private
14
22
  */
15
23
  export default class Store {
16
- environment;
17
24
  _meta = {};
18
25
  // Store packages paths by ns
19
26
  _packagesPaths = {};
20
27
  // Store packages ns
21
28
  _packagesNS = [];
29
+ environment;
22
30
  constructor(environment) {
23
31
  this.environment = environment;
24
32
  }
@@ -51,28 +59,60 @@ export default class Store {
51
59
  if (!meta.resolved) {
52
60
  throw new Error(`Generator Stub or resolved path is required for ${meta.namespace}`);
53
61
  }
54
- importModule = async () => import(pathToFileURL(meta.resolved).href);
62
+ importModule = () => {
63
+ try {
64
+ return require(meta.resolved);
65
+ }
66
+ catch {
67
+ return import(__rewriteRelativeImportExtension(pathToFileURL(meta.resolved).href));
68
+ }
69
+ };
55
70
  }
56
71
  let importPromise;
57
- const importGenerator = async () => {
72
+ // eslint-disable-next-line prefer-const
73
+ let generatorMeta;
74
+ const importGenerator = () => {
75
+ const handleImport = () => {
76
+ if (importModule && !Generator) {
77
+ const maybeModule = importModule();
78
+ if (maybeModule.then) {
79
+ importPromise = maybeModule;
80
+ return maybeModule.then((mod) => {
81
+ Generator = mod;
82
+ importPromise = undefined;
83
+ });
84
+ }
85
+ else {
86
+ Generator = maybeModule;
87
+ }
88
+ }
89
+ };
90
+ const handleModule = () => {
91
+ const factory = this.getFactory(Generator);
92
+ if (typeof factory === 'function') {
93
+ importPromise = factory(this.environment);
94
+ return Promise.resolve(importPromise).then((mod) => {
95
+ const generator = this._getGenerator(mod, meta, generatorMeta);
96
+ Generator = generator;
97
+ importPromise = undefined;
98
+ return generator;
99
+ });
100
+ }
101
+ return this._getGenerator(Generator, meta, generatorMeta);
102
+ };
58
103
  if (importPromise) {
59
- Generator = await importPromise;
60
- }
61
- if (importModule && !Generator) {
62
- importPromise = importModule();
63
- Generator = await importPromise;
104
+ return importPromise.then(() => Promise.resolve(handleImport()).then(() => handleModule()));
64
105
  }
65
- const factory = this.getFactory(Generator);
66
- if (typeof factory === 'function') {
67
- importPromise = factory(this.environment);
68
- Generator = await importPromise;
106
+ const maybeImportPromise = handleImport();
107
+ if (maybeImportPromise?.then) {
108
+ return maybeImportPromise.then(() => handleModule());
69
109
  }
70
- return this._getGenerator(Generator, meta);
110
+ return handleModule();
71
111
  };
72
112
  const instantiate = async (arguments_ = [], options = {}) => this.environment.instantiate(await importGenerator(), { generatorArgs: arguments_, generatorOptions: options });
73
113
  const instantiateHelp = async () => instantiate([], { help: true });
74
114
  const { packageNamespace } = toNamespace(meta.namespace) ?? {};
75
- const generatorMeta = {
115
+ generatorMeta = {
76
116
  ...meta,
77
117
  importGenerator,
78
118
  importModule,
@@ -132,7 +172,7 @@ export default class Store {
132
172
  debug('Overriding a package with namespace %s and path %s, with path %s', packageNS, this._packagesPaths[packageNS][0], packagePath);
133
173
  // Remove old packagePath
134
174
  const index = packagePaths.indexOf(packagePath);
135
- if (index > -1) {
175
+ if (index !== -1) {
136
176
  packagePaths.splice(index, 1);
137
177
  }
138
178
  packagePaths.splice(0, 0, packagePath);
@@ -169,12 +209,13 @@ export default class Store {
169
209
  // CJS is imported in default, for backward compatibility we support a Generator exported as `module.exports = { default }`
170
210
  return module.createGenerator ?? module.default?.createGenerator ?? module.default?.default?.createGenerator;
171
211
  }
172
- _getGenerator(module, meta) {
212
+ _getGenerator(module, meta, generatorMeta) {
173
213
  const Generator = module.default?.default ?? module.default ?? module;
174
214
  if (typeof Generator !== 'function') {
175
215
  throw new TypeError("The generator doesn't provide a constructor.");
176
216
  }
177
217
  Object.assign(Generator, meta);
218
+ Generator._meta = generatorMeta;
178
219
  return Generator;
179
220
  }
180
221
  }
@@ -1,6 +1,7 @@
1
1
  import { Command, Option } from 'commander';
2
- import type BaseEnvironment from '../environment-base.js';
2
+ import type BaseEnvironment from '../environment-base.ts';
3
3
  export default class YeomanCommand extends Command {
4
+ #private;
4
5
  env?: BaseEnvironment;
5
6
  createCommand(name?: string): YeomanCommand;
6
7
  /**
@@ -29,6 +30,6 @@ export default class YeomanCommand extends Command {
29
30
  * @return {YeomanCommand} this;
30
31
  */
31
32
  addGeneratorOptions(options: Record<string, any>): this;
32
- _addGeneratorOption(optionName: string, optionDefinition: any, additionalDescription?: string): any;
33
+ _addGeneratorOption(optionName: string, optionDefinition: any, additionalDescription?: string): Option | this | undefined;
33
34
  }
34
35
  export declare const addEnvironmentOptions: (command?: YeomanCommand) => YeomanCommand;
@@ -65,13 +65,16 @@ export default class YeomanCommand extends Command {
65
65
  }
66
66
  return this;
67
67
  }
68
+ #findOption(arg) {
69
+ return this.options.find(option => option.short === arg || option.long === arg);
70
+ }
68
71
  _addGeneratorOption(optionName, optionDefinition, additionalDescription = '') {
69
72
  if (optionName === 'help') {
70
73
  return;
71
74
  }
72
75
  const longOption = `--${optionName}`;
73
- const existingOption = this._findOption(longOption);
74
- if (this._findOption(longOption)) {
76
+ const existingOption = this.#findOption(longOption);
77
+ if (this.#findOption(longOption)) {
75
78
  return existingOption;
76
79
  }
77
80
  let cmdString = '';
@@ -40,7 +40,7 @@ export const asNamespace = (filepath, { lookups = defaultLookups }) => {
40
40
  const nsLookups = [...lookups, '..']
41
41
  .map(found => slash(found))
42
42
  .sort((a, b) => a.split('/').length - b.split('/').length)
43
- .reverse();
43
+ .toReversed();
44
44
  // If `ns` contains a lookup dir in its path, remove it.
45
45
  for (const lookup of nsLookups) {
46
46
  // Only match full directory (begin with leading slash or start of input, end with trailing slash)
@@ -3,4 +3,4 @@
3
3
  * @param specifier - Filepath or module name
4
4
  * @return - The resolved path leading to the module
5
5
  */
6
- export declare function resolveModulePath(specifier: string, resolvedOrigin?: string): Promise<string | undefined>;
6
+ export declare function resolveModulePath(specifier: string, resolvedOrigin?: string): string | undefined;
@@ -1,14 +1,14 @@
1
1
  import { dirname, extname, join, normalize, resolve, sep } from 'node:path';
2
- import { realpath, stat } from 'node:fs/promises';
2
+ import { realpathSync, statSync } from 'node:fs';
3
3
  import untildify from 'untildify';
4
- import { locatePath } from 'locate-path';
5
- import { defaultExtensions } from '../generator-lookup.js';
4
+ import { locatePathSync } from 'locate-path';
5
+ import { defaultExtensions } from "../generator-lookup.js";
6
6
  /**
7
7
  * Resolve a module path
8
8
  * @param specifier - Filepath or module name
9
9
  * @return - The resolved path leading to the module
10
10
  */
11
- export async function resolveModulePath(specifier, resolvedOrigin) {
11
+ export function resolveModulePath(specifier, resolvedOrigin) {
12
12
  let maybeResolved = specifier;
13
13
  if (maybeResolved.startsWith('.')) {
14
14
  if (resolvedOrigin) {
@@ -24,15 +24,15 @@ export async function resolveModulePath(specifier, resolvedOrigin) {
24
24
  maybeResolved += sep;
25
25
  }
26
26
  try {
27
- let specStat = await stat(maybeResolved);
27
+ let specStat = statSync(maybeResolved);
28
28
  if (specStat.isSymbolicLink()) {
29
- specStat = await stat(await realpath(maybeResolved));
29
+ specStat = statSync(realpathSync(maybeResolved));
30
30
  }
31
31
  if (specStat.isFile()) {
32
32
  return maybeResolved;
33
33
  }
34
34
  if (specStat.isDirectory()) {
35
- return await locatePath(defaultExtensions.map(extension => `index${extension}`).map(file => join(maybeResolved, file)));
35
+ return locatePathSync(defaultExtensions.map(extension => `index${extension}`).map(file => join(maybeResolved, file)));
36
36
  }
37
37
  }
38
38
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yeoman-environment",
3
- "version": "5.0.0-beta.0",
3
+ "version": "5.0.0-beta.1",
4
4
  "description": "Handles the lifecyle and bootstrapping of generators in a specific environment",
5
5
  "keywords": [
6
6
  "development",
@@ -58,18 +58,18 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@yeoman/adapter": "^2.1.1",
61
- "@yeoman/conflicter": "^2.4.0",
61
+ "@yeoman/conflicter": "^3.0.0",
62
62
  "@yeoman/namespace": "^1.0.1",
63
63
  "@yeoman/transform": "^2.1.0",
64
- "@yeoman/types": "^1.6.0",
64
+ "@yeoman/types": "^1.7.1",
65
65
  "arrify": "^3.0.0",
66
- "chalk": "^5.4.1",
67
- "commander": "^13.1.0",
68
- "debug": "^4.4.0",
69
- "execa": "^9.5.3",
70
- "fly-import": "^0.4.1",
66
+ "chalk": "^5.5.0",
67
+ "commander": "^14.0.0",
68
+ "debug": "^4.4.1",
69
+ "execa": "^9.6.0",
70
+ "fly-import": "^1.0.0",
71
71
  "globby": "^14.1.0",
72
- "grouped-queue": "^2.0.0",
72
+ "grouped-queue": "^2.1.0",
73
73
  "locate-path": "^7.2.0",
74
74
  "lodash-es": "^4.17.21",
75
75
  "mem-fs": "^4.1.2",
@@ -82,22 +82,22 @@
82
82
  "devDependencies": {
83
83
  "@types/debug": "^4.1.12",
84
84
  "@types/lodash-es": "^4.17.12",
85
- "@types/node": "^18.19.100",
85
+ "@types/node": "^20.19.11",
86
86
  "@types/semver": "^7.7.0",
87
- "@yeoman/eslint": "0.2.0",
87
+ "@yeoman/eslint": "1.0.0",
88
88
  "c8": "^10.1.3",
89
- "cpy-cli": "^5.0.0",
90
- "eslint": "9.12.0",
91
- "esmocha": "^3.0.0",
92
- "fs-extra": "^11.3.0",
89
+ "cpy-cli": "^6.0.0",
90
+ "eslint": "9.33.0",
91
+ "esmocha": "^4.0.0",
92
+ "fs-extra": "^11.3.1",
93
93
  "jsdoc": "^4.0.4",
94
- "prettier": "3.5.3",
95
- "prettier-plugin-packagejson": "^2.5.12",
94
+ "prettier": "3.6.2",
95
+ "prettier-plugin-packagejson": "^2.5.19",
96
96
  "rimraf": "^6.0.1",
97
- "sinon": "^20.0.0",
97
+ "sinon": "^21.0.0",
98
98
  "sinon-test": "^3.1.6",
99
99
  "strip-ansi": "^7.1.0",
100
- "typescript": "5.8.3",
100
+ "typescript": "5.9.2",
101
101
  "yeoman-assert": "^3.1.1",
102
102
  "yeoman-environment": "file:./",
103
103
  "yeoman-generator-2": "npm:yeoman-generator@^2.0.5",
@@ -105,11 +105,12 @@
105
105
  "yeoman-generator-5": "npm:yeoman-generator@^5.10.0",
106
106
  "yeoman-generator-6": "npm:yeoman-generator@^6.0.1",
107
107
  "yeoman-generator-7": "npm:yeoman-generator@^7.0.0",
108
- "yeoman-test": "^10.1.0"
108
+ "yeoman-generator-8": "npm:yeoman-generator@^8.0.0-beta.0",
109
+ "yeoman-test": "^10.1.1"
109
110
  },
110
111
  "peerDependencies": {
111
- "@yeoman/types": "^1.1.1",
112
- "mem-fs": "^4.0.0"
112
+ "@yeoman/types": "^1.7.1",
113
+ "mem-fs": "^4.1.2"
113
114
  },
114
115
  "engines": {
115
116
  "node": "^20.17.0 || >=22.9.0"
@@ -131,7 +132,7 @@
131
132
  "shelljs": "^0.8.5",
132
133
  "sort-keys": "^4.2.0",
133
134
  "text-table": "^0.2.0",
134
- "yeoman-environment": "^3.19.3"
135
+ "yeoman-environment": "file:./"
135
136
  },
136
137
  "yeoman-generator-4": {
137
138
  "chalk": "^4.1.0",
@@ -149,7 +150,7 @@
149
150
  "shelljs": "^0.8.5",
150
151
  "sort-keys": "^4.2.0",
151
152
  "text-table": "^0.2.0",
152
- "yeoman-environment": "^3.19.3"
153
+ "yeoman-environment": "file:./"
153
154
  },
154
155
  "yeoman-generator-5": {
155
156
  "chalk": "^4.1.0",
@@ -167,10 +168,16 @@
167
168
  "shelljs": "^0.8.5",
168
169
  "sort-keys": "^4.2.0",
169
170
  "text-table": "^0.2.0",
170
- "yeoman-environment": "*"
171
+ "yeoman-environment": "file:./"
171
172
  },
172
173
  "yeoman-generator-6": {
173
- "yeoman-environment": "*"
174
+ "yeoman-environment": "file:./"
175
+ },
176
+ "yeoman-generator-7": {
177
+ "yeoman-environment": "file:./"
178
+ },
179
+ "yeoman-generator-8": {
180
+ "yeoman-environment": "file:./"
174
181
  }
175
182
  }
176
183
  }