yeoman-generator 7.3.2 → 7.3.3

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.
@@ -29,7 +29,6 @@ export class FsMixin {
29
29
  copyTemplate(...args) {
30
30
  const [from, to, options = {}, ...remaining] = args;
31
31
  options.fromBasePath = options.fromBasePath ?? this.templatePath();
32
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
33
32
  return this.fs.copy(from, this.destinationPath(to), options, ...remaining);
34
33
  }
35
34
  /**
@@ -55,7 +54,6 @@ export class FsMixin {
55
54
  * mem-fs-editor method's shortcut, for more information see [mem-fs-editor]{@link https://github.com/SBoudrias/mem-fs-editor}.
56
55
  * Shortcut for this.fs!.readJSON(this.destinationPath(filepath)).
57
56
  */
58
- // eslint-disable-next-line @typescript-eslint/naming-convention
59
57
  readDestinationJSON(...args) {
60
58
  return this.fs.readJSON(...applyToFirstStringArg(this.destinationPath.bind(this), args));
61
59
  }
@@ -72,7 +70,6 @@ export class FsMixin {
72
70
  * mem-fs-editor method's shortcut, for more information see [mem-fs-editor]{@link https://github.com/SBoudrias/mem-fs-editor}.
73
71
  * Shortcut for this.fs!.writeJSON(this.destinationPath(filepath)).
74
72
  */
75
- // eslint-disable-next-line @typescript-eslint/naming-convention
76
73
  writeDestinationJSON(...args) {
77
74
  return this.fs.writeJSON(...applyToFirstStringArg(this.destinationPath.bind(this), args));
78
75
  }
@@ -82,7 +79,6 @@ export class FsMixin {
82
79
  * Shortcut for this.fs!.delete(this.destinationPath(filepath)).
83
80
  */
84
81
  deleteDestination(...args) {
85
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
86
82
  return this.fs.delete(...applyToFirstStringArg(this.destinationPath.bind(this), args));
87
83
  }
88
84
  /**
@@ -93,7 +89,6 @@ export class FsMixin {
93
89
  copyDestination(...args) {
94
90
  const [from, to, options = {}, ...remaining] = args;
95
91
  options.fromBasePath = options.fromBasePath ?? this.destinationPath();
96
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
97
92
  return this.fs.copy(from, this.destinationPath(to), options, ...remaining);
98
93
  }
99
94
  /**
@@ -104,7 +99,6 @@ export class FsMixin {
104
99
  moveDestination(...args) {
105
100
  const [from, to, options = {}, ...remaining] = args;
106
101
  options.fromBasePath = options.fromBasePath ?? this.destinationPath();
107
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
108
102
  return this.fs.move(from, this.destinationPath(to), options, ...remaining);
109
103
  }
110
104
  /**
@@ -186,7 +180,7 @@ export class FsMixin {
186
180
  if (!template.when || template.when(eachData, this)) {
187
181
  return this.renderTemplateAsync(source, destination, eachData, template.templateOptions, template.copyOptions);
188
182
  }
189
- return undefined;
183
+ return;
190
184
  }));
191
185
  }
192
186
  /**
@@ -18,7 +18,7 @@ export class HelpMixin {
18
18
  help() {
19
19
  const filepath = path.resolve(this.sourceRoot(), '../USAGE');
20
20
  const exists = fs.existsSync(filepath);
21
- let out = ['Usage:', ' ' + this.usage(), ''];
21
+ let out = ['Usage:', ` ${this.usage()}`, ''];
22
22
  // Build options
23
23
  if (Object.keys(this._options).length > 0) {
24
24
  out = [...out, 'Options:', this.optionsHelp(), ''];
@@ -44,12 +44,12 @@ export class HelpMixin {
44
44
  let name = this._namespace;
45
45
  let args = '';
46
46
  if (this._arguments.length > 0) {
47
- args = this._arguments.map(arg => formatArg(arg)).join(' ') + ' ';
47
+ args = `${this._arguments.map(arg => formatArg(arg)).join(' ')} `;
48
48
  }
49
49
  name = name.replace(/^yeoman:/, '');
50
50
  let out = `yo ${name} ${args}${options}`;
51
51
  if (this.description) {
52
- out += '\n\n' + this.description;
52
+ out += `\n\n${this.description}`;
53
53
  }
54
54
  return out;
55
55
  }
@@ -1,7 +1,7 @@
1
1
  import type { BaseGenerator, GetGeneratorOptions } from '@yeoman/types';
2
2
  import { type FileTransform } from 'mem-fs';
3
3
  import { type MemFsEditorFile } from 'mem-fs-editor';
4
- import type { Task, TaskOptions, BaseOptions, Priority, ComposeOptions, GeneratorPipelineOptions } from '../types.js';
4
+ import type { BaseOptions, ComposeOptions, GeneratorPipelineOptions, Priority, Task, TaskOptions } from '../types.js';
5
5
  import type Generator from '../index.js';
6
6
  import type BaseGeneratorImpl from '../generator.js';
7
7
  type TaskStatus = {
@@ -83,7 +83,7 @@ export declare abstract class TasksMixin {
83
83
  * @param args: Task arguments.
84
84
  * @param taskStatus.
85
85
  */
86
- executeTask(this: BaseGeneratorImpl, task: Task, args?: any[] | ((generator: Generator<BaseOptions, import("../types.js").BaseFeatures>) => any[]), taskStatus?: TaskStatus | undefined): Promise<void>;
86
+ executeTask(this: BaseGeneratorImpl, task: Task, args?: any[] | ((generator: Generator) => any[]), taskStatus?: TaskStatus | undefined): Promise<void>;
87
87
  /**
88
88
  * Ignore cancellable tasks.
89
89
  */
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/member-ordering */
2
1
  import { dirname, isAbsolute, resolve as pathResolve, relative } from 'node:path';
3
2
  import { pathToFileURL } from 'node:url';
4
3
  import { createRequire } from 'node:module';
@@ -7,7 +6,6 @@ import { stat } from 'node:fs/promises';
7
6
  import createDebug from 'debug';
8
7
  import { toNamespace } from '@yeoman/namespace';
9
8
  import { isFileTransform } from 'mem-fs';
10
- // eslint-disable-next-line n/file-extension-in-import
11
9
  import { isFilePending } from 'mem-fs-editor/state';
12
10
  const debug = createDebug('yeoman:generator');
13
11
  // Ensure a prototype method is a candidate run by default
@@ -180,14 +178,9 @@ export class TasksMixin {
180
178
  const methods = Object.keys(this.getTaskSourcesPropertyDescriptors());
181
179
  let validMethods = methods.filter(method => methodIsValid(method));
182
180
  const { taskPrefix } = this.features;
183
- if (taskPrefix) {
184
- validMethods = validMethods
185
- .filter(method => method.startsWith(taskPrefix))
186
- .map(method => method.slice(taskPrefix.length));
187
- }
188
- else {
189
- validMethods = validMethods.filter(method => !method.startsWith('#'));
190
- }
181
+ validMethods = taskPrefix
182
+ ? validMethods.filter(method => method.startsWith(taskPrefix)).map(method => method.slice(taskPrefix.length))
183
+ : validMethods.filter(method => !method.startsWith('#'));
191
184
  if (this.features.tasksMatchingPriority) {
192
185
  const queueNames = Object.keys(this._queues);
193
186
  validMethods = validMethods.filter(method => queueNames.includes(method));
@@ -344,7 +337,6 @@ export class TasksMixin {
344
337
  }
345
338
  this.queueOwnTasks({ auto: true });
346
339
  }
347
- // eslint-disable-next-line max-params
348
340
  async composeWith(generator, args, options, immediately = false) {
349
341
  if (Array.isArray(generator)) {
350
342
  const generators = [];
@@ -412,9 +404,10 @@ export class TasksMixin {
412
404
  try {
413
405
  generatorFile = await this.resolveGeneratorPath(generator.path ?? generator.Generator.resolved);
414
406
  }
415
- catch { }
407
+ catch {
408
+ // Ignore error
409
+ }
416
410
  const resolved = generatorFile ?? generator.path ?? generator.Generator.resolved;
417
- // eslint-disable-next-line @typescript-eslint/naming-convention
418
411
  return this.composeLocallyWithOptions({ Generator: generator.Generator, resolved }, composeOptions);
419
412
  }
420
413
  if (skipEnvRegister || isAbsolute(generator) || generator.startsWith('.')) {
@@ -426,11 +419,16 @@ export class TasksMixin {
426
419
  try {
427
420
  generator = await this.resolveGeneratorPath(generator);
428
421
  }
429
- catch { }
422
+ catch {
423
+ // Ignore error
424
+ }
430
425
  }
431
426
  return this.env.composeWith(generator, composeOptions);
432
427
  }
433
428
  async composeLocallyWithOptions({ Generator, resolved = Generator.resolved }, options = {}) {
429
+ if (!resolved) {
430
+ throw new Error('Generator path property is not a string');
431
+ }
434
432
  const generatorNamespace = this.env.namespace(resolved);
435
433
  const findGenerator = async () => {
436
434
  const generatorImport = await import(resolved);
@@ -441,7 +439,12 @@ export class TasksMixin {
441
439
  }
442
440
  return typeof generatorImport.default === 'function' ? generatorImport.default : generatorImport;
443
441
  };
444
- Generator = Generator ?? (await findGenerator());
442
+ try {
443
+ Generator = Generator ?? (await findGenerator());
444
+ }
445
+ catch {
446
+ throw new Error('Missing Generator property');
447
+ }
445
448
  Generator.namespace = generatorNamespace;
446
449
  Generator.resolved = resolved;
447
450
  return this.env.composeWith(Generator, options);
@@ -457,7 +460,9 @@ export class TasksMixin {
457
460
  generatorResolvedFile = generatorFile;
458
461
  }
459
462
  }
460
- catch { }
463
+ catch {
464
+ // Ignore error
465
+ }
461
466
  if (!generatorResolvedFile) {
462
467
  // Resolve the generator file.
463
468
  // Use import.resolve when stable.
@@ -23,7 +23,6 @@ export class PackageJsonMixin {
23
23
  : dependencies;
24
24
  return Object.fromEntries(await Promise.all(
25
25
  // Make sure to convert empty string too
26
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
27
26
  Object.entries(depMap).map(async ([pkg, version]) => [pkg, version || (await latestVersion(pkg))])));
28
27
  }
29
28
  /**
@@ -1,5 +1,4 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { type Options as ExecaOptions, type ExecaChildProcess, type SyncOptions, type ExecaSyncReturnValue } from 'execa';
1
+ import { type ExecaChildProcess, type Options as ExecaOptions, type ExecaSyncReturnValue, type SyncOptions } from 'execa';
3
2
  export declare class SpawnCommandMixin {
4
3
  /**
5
4
  * Normalize a command across OS and spawn it (asynchronously).
@@ -1,4 +1,4 @@
1
- import { execa, execaSync, execaCommand, execaCommandSync, } from 'execa';
1
+ import { execa, execaCommand, execaCommandSync, execaSync, } from 'execa';
2
2
  export class SpawnCommandMixin {
3
3
  spawnCommand(command, args, opt) {
4
4
  if (Array.isArray(args) || (opt && args === undefined)) {
package/dist/constants.js CHANGED
@@ -1,3 +1,2 @@
1
- // eslint-disable-next-line @typescript-eslint/naming-convention
2
1
  export const DESTINATION_ROOT_CHANGE_EVENT = 'destinationRootChange';
3
2
  export const requiredEnvironmentVersion = '4.0.0-rc.0';
@@ -1,11 +1,10 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { EventEmitter } from 'node:events';
3
2
  import * as _ from 'lodash-es';
4
3
  import createDebug from 'debug';
5
4
  import { type MemFsEditor } from 'mem-fs-editor';
6
5
  import { type YeomanNamespace } from '@yeoman/namespace';
7
6
  import type { BaseEnvironment, BaseGenerator as GeneratorApi, Logger, QueuedAdapter } from '@yeoman/types';
8
- import type { ArgumentSpec, BaseOptions, BaseFeatures, CliOptionSpec, Priority } from './types.js';
7
+ import type { ArgumentSpec, BaseFeatures, BaseOptions, CliOptionSpec, Priority } from './types.js';
9
8
  import type { PromptAnswers, PromptQuestions, QuestionRegistrationOptions } from './questions.js';
10
9
  import Storage, { type StorageOptions } from './util/storage.js';
11
10
  import { FsMixin } from './actions/fs.js';
package/dist/generator.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fs, { readFileSync } from 'node:fs';
2
- import path, { dirname, resolve as pathResolve, join as pathJoin } from 'node:path';
2
+ import path, { dirname, join as pathJoin, resolve as pathResolve } from 'node:path';
3
3
  import os from 'node:os';
4
4
  import { EventEmitter } from 'node:events';
5
5
  import { fileURLToPath } from 'node:url';
@@ -22,15 +22,11 @@ import { GitMixin } from './actions/user.js';
22
22
  import { TasksMixin } from './actions/lifecycle.js';
23
23
  const _filename = fileURLToPath(import.meta.url);
24
24
  const _dirname = dirname(_filename);
25
- // eslint-disable-next-line @typescript-eslint/naming-convention
26
25
  const EMPTY = '@@_YEOMAN_EMPTY_MARKER_@@';
27
- // eslint-disable-next-line @typescript-eslint/naming-convention
28
26
  const ENV_VER_WITH_VER_API = '2.9.0';
29
27
  const packageJson = JSON.parse(readFileSync(pathJoin(_dirname, '../package.json'), 'utf8'));
30
28
  // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
31
- export class BaseGenerator
32
- // eslint-disable-next-line unicorn/prefer-event-target
33
- extends EventEmitter {
29
+ export class BaseGenerator extends EventEmitter {
34
30
  options;
35
31
  _initOptions;
36
32
  _args;
@@ -76,7 +72,6 @@ export class BaseGenerator
76
72
  _running = false;
77
73
  features;
78
74
  yoGeneratorVersion = packageJson.version;
79
- // eslint-disable-next-line complexity
80
75
  constructor(args, options, features) {
81
76
  super();
82
77
  const actualArgs = Array.isArray(args) ? args : [];
@@ -86,7 +81,6 @@ export class BaseGenerator
86
81
  // Load parameters
87
82
  this._args = actualArgs;
88
83
  this.options = generatorOptions;
89
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
90
84
  this.features = actualFeatures ?? {};
91
85
  // Initialize properties
92
86
  this._options = {};
@@ -231,7 +225,6 @@ export class BaseGenerator
231
225
  if (runningVersion === undefined) {
232
226
  return true;
233
227
  }
234
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
235
228
  if (this.options.ignoreVersionCheck || warning) {
236
229
  console.warn(`Current ${packageDependency} is not compatible with current generator, min required: ${versionToCheck} current version: ${runningVersion}. Some features may be missing, try updating reinstalling 'yo'.`);
237
230
  return false;
@@ -357,7 +350,7 @@ export class BaseGenerator
357
350
  }
358
351
  const spec = typeof name === 'object'
359
352
  ? name
360
- : { hide: false, type: Boolean, description: 'Description for ' + name, ...config, name };
353
+ : { hide: false, type: Boolean, description: `Description for ${name}`, ...config, name };
361
354
  const specName = spec.name;
362
355
  // Check whether boolean option is invalid (starts with no-)
363
356
  const boolOptionRegex = /^no-/;
@@ -366,7 +359,7 @@ export class BaseGenerator
366
359
  throw new Error([
367
360
  `Option name ${chalk.yellow(specName)} cannot start with ${chalk.red('no-')}\n`,
368
361
  `Option name prefixed by ${chalk.yellow('--no')} are parsed as implicit`,
369
- ` boolean. To use ${chalk.yellow('--' + specName)} as an option, use\n`,
362
+ ` boolean. To use ${chalk.yellow(`--${specName}`)} as an option, use\n`,
370
363
  chalk.cyan(` this.option('${simpleName}', {type: Boolean})`),
371
364
  ].join(''));
372
365
  }
@@ -449,7 +442,6 @@ export class BaseGenerator
449
442
  for (const [name, option] of Object.entries(parsedOptions)) {
450
443
  // Manually set value as undefined if it should be.
451
444
  if (option === EMPTY) {
452
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
453
445
  delete parsedOptions[name];
454
446
  }
455
447
  else if (this._options[name] && option !== undefined) {
@@ -471,7 +463,7 @@ export class BaseGenerator
471
463
  }
472
464
  }
473
465
  else if (config.type === Array) {
474
- value = parsedOptions._.slice(index, parsedOptions._.length);
466
+ value = parsedOptions._.slice(index);
475
467
  }
476
468
  else {
477
469
  value = config.type(parsedOptions._[index]);
@@ -637,7 +629,7 @@ export class BaseGenerator
637
629
  * @return joined path
638
630
  */
639
631
  templatePath(...dest) {
640
- let filepath = path.join.apply(path, dest);
632
+ let filepath = path.join(...dest);
641
633
  if (!path.isAbsolute(filepath)) {
642
634
  filepath = path.join(this.sourceRoot(), filepath);
643
635
  }
@@ -649,7 +641,7 @@ export class BaseGenerator
649
641
  * @return joined path
650
642
  */
651
643
  destinationPath(...dest) {
652
- let filepath = path.join.apply(path, dest);
644
+ let filepath = path.join(...dest);
653
645
  if (!path.isAbsolute(filepath)) {
654
646
  filepath = path.join(this.destinationRoot(), filepath);
655
647
  }
@@ -665,7 +657,7 @@ export class BaseGenerator
665
657
  */
666
658
  determineAppname() {
667
659
  const appName = this.packageJson.get('name') ?? path.basename(this.destinationRoot());
668
- return appName.replaceAll(/[^\w\s]+?/g, ' ');
660
+ return appName.replaceAll(/[^\s\w]+?/g, ' ');
669
661
  }
670
662
  }
671
663
  applyMixins(BaseGenerator, [FsMixin, HelpMixin, PackageJsonMixin, SpawnCommandMixin, GitMixin, TasksMixin]);
package/dist/index.js CHANGED
@@ -25,7 +25,6 @@ export default class Generator extends BaseGenerator {
25
25
  if (!this._simpleGit) {
26
26
  this._simpleGit = simpleGit({ baseDir: this.destinationPath() }).env({
27
27
  ...process.env,
28
- // eslint-disable-next-line @typescript-eslint/naming-convention
29
28
  LANG: 'en',
30
29
  });
31
30
  this.on(DESTINATION_ROOT_CHANGE_EVENT, () => {
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/naming-convention */
2
1
  /**
3
2
  * https://github.com/microsoft/TypeScript/issues/14107#issuecomment-1146738780
4
3
  */
@@ -7,7 +7,7 @@ import type Storage from './storage.js';
7
7
  * @param questions Original prompt questions
8
8
  * @return Prompt questions array with prefilled values.
9
9
  */
10
- export declare const prefillQuestions: <A extends import("inquirer").Answers = import("inquirer").Answers>(store: Storage, questions: PromptQuestion<A>[]) => PromptQuestion<A>[];
10
+ export declare const prefillQuestions: <A extends PromptAnswers = PromptAnswers>(store: Storage, questions: Array<PromptQuestion<A>>) => PromptQuestion<A>[];
11
11
  /**
12
12
  * Store the answers in the global store
13
13
  *
@@ -1,5 +1,4 @@
1
1
  import assert from 'node:assert';
2
- // eslint-disable-next-line @typescript-eslint/promise-function-async
3
2
  const getChoices = (question) => {
4
3
  if (question.type === 'list') {
5
4
  return question.choices;
@@ -13,7 +12,7 @@ const getChoices = (question) => {
13
12
  if (question.type === 'rawlist') {
14
13
  return question.choices;
15
14
  }
16
- return undefined;
15
+ return;
17
16
  };
18
17
  /**
19
18
  * Returns the default value for a checkbox
@@ -1,5 +1,5 @@
1
1
  import assert from 'node:assert';
2
- import { cloneDeep, defaults as setDefaults, merge, get, set } from 'lodash-es';
2
+ import { cloneDeep, get, merge, set, defaults as setDefaults } from 'lodash-es';
3
3
  import sortKeys from 'sort-keys';
4
4
  /**
5
5
  * Proxy handler for Storage
@@ -220,7 +220,6 @@ class Storage {
220
220
  */
221
221
  delete(key) {
222
222
  const store = this._store;
223
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
224
223
  delete store[key];
225
224
  this._persist(store);
226
225
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yeoman-generator",
3
- "version": "7.3.2",
3
+ "version": "7.3.3",
4
4
  "description": "Rails-inspired generator system that provides scaffolding for your apps",
5
5
  "keywords": [
6
6
  "development",
@@ -44,15 +44,15 @@
44
44
  "doc:generate": "jsdoc -c jsdoc.json -d $npm_package_config_doc_path$DOC_FOLDER",
45
45
  "doc:prettier": "prettier $npm_package_config_doc_path$DOC_FOLDER --write --ignore-path .prettierignore-doc",
46
46
  "prepare": "npm run build",
47
- "pretest": "xo",
48
- "test": "c8 esmocha --forbid-only"
47
+ "pretest": "eslint . && npm run build",
48
+ "test": "vitest run --coverage"
49
49
  },
50
50
  "config": {
51
51
  "doc_path": "../yeoman-generator-doc/"
52
52
  },
53
53
  "dependencies": {
54
54
  "@types/lodash-es": "^4.17.9",
55
- "@types/node": "^18.18.5",
55
+ "@types/node": ">=18.18.5",
56
56
  "@yeoman/namespace": "^1.0.0",
57
57
  "chalk": "^5.3.0",
58
58
  "debug": "^4.1.1",
@@ -72,39 +72,33 @@
72
72
  "devDependencies": {
73
73
  "@types/debug": "^4.1.9",
74
74
  "@types/ejs": "^3.1.4",
75
- "@types/inquirer": "^9.0.4",
75
+ "@types/json-schema": "^7.0.15",
76
76
  "@types/minimist": "^1.2.3",
77
77
  "@types/semver": "^7.5.3",
78
78
  "@types/sinon": "^17.0.1",
79
79
  "@types/text-table": "^0.2.3",
80
+ "@vitest/coverage-v8": "^2.0.5",
80
81
  "@yeoman/adapter": "^1.4.0",
81
- "@yeoman/transform": "^1.2.0",
82
- "c8": "^8.0.1",
82
+ "@yeoman/eslint": "^0.2.0",
83
+ "@yeoman/transform": "^2.0.0",
83
84
  "cpy-cli": "^5.0.0",
84
85
  "ejs": "^3.1.9",
85
- "esmocha": "^1.0.1",
86
- "inquirer": "^9.2.11",
86
+ "inquirer": "^11.1.0",
87
87
  "jsdoc": "^4.0.2",
88
88
  "nock": "^13.3.4",
89
89
  "prettier": "^3.0.3",
90
90
  "prettier-plugin-packagejson": "^2.4.6",
91
- "sinon": "^18.0.0",
91
+ "sinon": "^19.0.0",
92
92
  "tui-jsdoc-template": "^1.2.2",
93
93
  "typescript": "^5.2.2",
94
- "xo": "^0.56.0",
94
+ "vitest": "^2.0.5",
95
95
  "yeoman-assert": "^3.1.1",
96
- "yeoman-environment": "^4.0.0",
97
- "yeoman-test": "^8.1.0"
96
+ "yeoman-environment": "^4.4.1",
97
+ "yeoman-test": "^9.0.0"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "@yeoman/types": "^1.1.1",
101
- "mem-fs": "^4.0.0",
102
- "yeoman-environment": "^4.0.0"
103
- },
104
- "peerDependenciesMeta": {
105
- "yeoman-environment": {
106
- "optional": true
107
- }
101
+ "mem-fs": "^4.0.0"
108
102
  },
109
103
  "engines": {
110
104
  "node": "^18.17.0 || >=20.5.0"