<commit_before>import Generator = require("yeoman-generator");

import * as glob from "glob-all";
import * as autoComplete from "inquirer-autocomplete-prompt";
import * as path from "path";

import npmExists from "@webpack-cli/utils/npm-exists";
import { getPackageManager } from "@webpack-cli/utils/package-manager";
import PROP_TYPES from "@webpack-cli/utils/prop-types";
import {
	AutoComplete,
	Confirm,
	IInquirerInput,
	IInquirerList,
	Input,
	List,
} from "@webpack-cli/webpack-scaffold";

import { ISchemaProperties, IWebpackOptions } from "./types";
import entryQuestions from "./utils/entry";

// tslint:disable:no-var-requires
const webpackDevServerSchema = require("webpack-dev-server/lib/options.json");
const webpackSchema = require("./utils/optionsSchema.json");
const PROPS: string[] = Array.from(PROP_TYPES.keys());

/**
 *
 * Replaces the string with a substring at the given index
 * https://gist.github.com/efenacigiray/9367920
 *
 * @param	{String} string - string to be modified
 * @param	{Number} index - index to replace from
 * @param	{String} replace - string to replace starting from index
 *
 * @returns	{String} string - The newly mutated string
 *
 */
function replaceAt(str: string, index: number, replace: string): string {
	return str.substring(0, index) + replace + str.substring(index + 1);
}

/**
 *
 * Checks if the given array has a given property
 *
 * @param	{Array} arr - array to check
 * @param	{String} prop - property to check existence of
 *
 * @returns	{Boolean} hasProp - Boolean indicating if the property
 * is present
 */
const traverseAndGetProperties = (arr: object[], prop: string): boolean => {
	let hasProp: boolean = false;
	arr.forEach((p: object): void => {
		if (p[prop]) {
			hasProp = true;
		}
	});
	return hasProp;
};

/**
 *
 * Search config properties
 *
 * @param {Object} answers	Prompt answers object
 * @param {String} input	Input search string
 *
 * @returns {Promise} Returns promise which resolves to filtered props
 *
 */
const searchProps = (answers: object, input: string): Promise<string[]> => {
	input = input || "";
	return Promise.resolve(
		PROPS.filter((prop: string): boolean =>
			prop.toLowerCase().includes(input.toLowerCase()),
		),
	);
};

/**
 *
 * Generator for adding properties
 * @class	AddGenerator
 * @extends	Generator
 * @returns	{Void} After execution, transforms are triggered
 *
 */

export default class AddGenerator extends Generator {
	private dependencies: string[];
	private configuration: {
		config: {
			configName?: string,
			topScope?: string[],
			item?: string;
			webpackOptions?: IWebpackOptions,
		},
	};

	constructor(args, opts) {
		super(args, opts);
		this.dependencies = [];
		this.configuration = {
			config: {
				topScope: ["const webpack = require('webpack')"],
				webpackOptions: {},
			},
		};
		const { registerPrompt } = this.env.adapter.promptModule;
		registerPrompt("autocomplete", autoComplete);
	}

	public prompting() {
		const done: (_?: void) => void | boolean = this.async();
		let action: string;
		const self: this = this;
		const manualOrListInput: (promptAction: string) => IInquirerInput = (promptAction: string) =>
			Input("actionAnswer", `What do you want to add to ${promptAction}?`);
		let inputPrompt: IInquirerInput;

		// first index indicates if it has a deep prop, 2nd indicates what kind of
		const isDeepProp: any[] = [false, false];

		return this.prompt([
			AutoComplete(
				"actionType",
				"What property do you want to add to?",
				{
					pageSize: 7,
					source: searchProps,
					suggestOnly: false,
				},
			),
		])
			.then((actionTypeAnswer: {
				actionType: string,
			}) => {
				// Set initial prop, like devtool
				this.configuration.config.webpackOptions[
					actionTypeAnswer.actionType
				] = null;
				// update the action variable, we're using it later
				action = actionTypeAnswer.actionType;
			})
			.then((_: void) => {
				if (action === "entry") {
					return this.prompt([
						Confirm("entryType", "Will your application have multiple bundles?"),
					])
						.then((entryTypeAnswer: {
							entryType: boolean,
						}) => {
							// Ask different questions for entry points
							return entryQuestions(self, entryTypeAnswer);
						})
						.then((entryOptions: {
							entryType: boolean;
						}) => {
							this.configuration.config.webpackOptions.entry = entryOptions;
							this.configuration.config.item = action;
						});
				}
				const temp: string = action;
				if (action === "resolveLoader") {
					action = "resolve";
				}
				const webpackSchemaProp: ISchemaProperties = webpackSchema.definitions[action];
				/*
				 * https://github.com/webpack/webpack/blob/next/schemas/WebpackOptions.json
				 * Find the properties directly in the properties prop, or the anyOf prop
				 */
				let defOrPropDescription: object = webpackSchemaProp
					? webpackSchemaProp.properties
					: webpackSchema.properties[action].properties
						? webpackSchema.properties[action].properties
						: webpackSchema.properties[action].anyOf
							? webpackSchema.properties[action].anyOf.filter(
								(p: {
									properties?: object,
									enum?: any[],
								}) => p.properties || p.enum,
							  )
							: null;
				if (Array.isArray(defOrPropDescription)) {
					// Todo: Generalize these to go through the array, then merge enum with props if needed
					const hasPropertiesProp: boolean = traverseAndGetProperties(<commit_msg>fix(add): add handling for topScope<commit_after>import Generator = require("yeoman-generator");

import * as glob from "glob-all";
import * as autoComplete from "inquirer-autocomplete-prompt";
import * as path from "path";

import npmExists from "@webpack-cli/utils/npm-exists";
import { getPackageManager } from "@webpack-cli/utils/package-manager";
import PROP_TYPES from "@webpack-cli/utils/prop-types";
import {
	AutoComplete,
	Confirm,
	IInquirerInput,
	IInquirerList,
	Input,
	List,
} from "@webpack-cli/webpack-scaffold";

import { ISchemaProperties, IWebpackOptions } from "./types";
import entryQuestions from "./utils/entry";

// tslint:disable:no-var-requires
const webpackDevServerSchema = require("webpack-dev-server/lib/options.json");
const webpackSchema = require("./utils/optionsSchema.json");
const PROPS: string[] = Array.from(PROP_TYPES.keys());

/**
 *
 * Replaces the string with a substring at the given index
 * https://gist.github.com/efenacigiray/9367920
 *
 * @param	{String} string - string to be modified
 * @param	{Number} index - index to replace from
 * @param	{String} replace - string to replace starting from index
 *
 * @returns	{String} string - The newly mutated string
 *
 */
function replaceAt(str: string, index: number, replace: string): string {
	return str.substring(0, index) + replace + str.substring(index + 1);
}

/**
 *
 * Checks if the given array has a given property
 *
 * @param	{Array} arr - array to check
 * @param	{String} prop - property to check existence of
 *
 * @returns	{Boolean} hasProp - Boolean indicating if the property
 * is present
 */
const traverseAndGetProperties = (arr: object[], prop: string): boolean => {
	let hasProp: boolean = false;
	arr.forEach((p: object): void => {
		if (p[prop]) {
			hasProp = true;
		}
	});
	return hasProp;
};

/**
 *
 * Search config properties
 *
 * @param {Object} answers	Prompt answers object
 * @param {String} input	Input search string
 *
 * @returns {Promise} Returns promise which resolves to filtered props
 *
 */
const searchProps = (answers: object, input: string): Promise<string[]> => {
	input = input || "";
	return Promise.resolve(
		PROPS.filter((prop: string): boolean =>
			prop.toLowerCase().includes(input.toLowerCase()),
		),
	);
};

/**
 *
 * Generator for adding properties
 * @class	AddGenerator
 * @extends	Generator
 * @returns	{Void} After execution, transforms are triggered
 *
 */

export default class AddGenerator extends Generator {
	private dependencies: string[];
	private configuration: {
		config: {
			configName?: string,
			topScope?: string[],
			item?: string;
			webpackOptions?: IWebpackOptions,
		},
	};

	constructor(args, opts) {
		super(args, opts);
		this.dependencies = [];
		this.configuration = {
			config: {
				topScope: ["const webpack = require('webpack')"],
				webpackOptions: {},
			},
		};
		const { registerPrompt } = this.env.adapter.promptModule;
		registerPrompt("autocomplete", autoComplete);
	}

	public prompting() {
		const done: (_?: void) => void | boolean = this.async();
		let action: string;
		const self: this = this;
		const manualOrListInput: (promptAction: string) => IInquirerInput = (promptAction: string) =>
			Input("actionAnswer", `What do you want to add to ${promptAction}?`);
		let inputPrompt: IInquirerInput;

		// first index indicates if it has a deep prop, 2nd indicates what kind of
		const isDeepProp: any[] = [false, false];

		return this.prompt([
			AutoComplete(
				"actionType",
				"What property do you want to add to?",
				{
					pageSize: 7,
					source: searchProps,
					suggestOnly: false,
				},
			),
		])
			.then((actionTypeAnswer: {
				actionType: string,
			}) => {
				// Set initial prop, like devtool
				this.configuration.config.webpackOptions[
					actionTypeAnswer.actionType
				] = null;
				// update the action variable, we're using it later
				action = actionTypeAnswer.actionType;
			})
			.then((_: void) => {
				if (action === "entry") {
					return this.prompt([
						Confirm("entryType", "Will your application have multiple bundles?"),
					])
						.then((entryTypeAnswer: {
							entryType: boolean,
						}) => {
							// Ask different questions for entry points
							return entryQuestions(self, entryTypeAnswer);
						})
						.then((entryOptions: {
							entryType: boolean;
						}) => {
							this.configuration.config.webpackOptions.entry = entryOptions;
							this.configuration.config.item = action;
						});
					} else {
						if(action === 'topScope'){
							return this.prompt([
								Input("topScope", "Enter line youwant to add to topScope"),
							])
							.then((topScopeAnswer) => {
								this.configuration.config.topScope.push(topScopeAnswer.topScope);
								done();
							})
						}
					}
				const temp: string = action;
				if (action === "resolveLoader") {
					action = "resolve";
				}
				const webpackSchemaProp: ISchemaProperties = webpackSchema.definitions[action];
				/*
				 * https://github.com/webpack/webpack/blob/next/schemas/WebpackOptions.json
				 * Find the properties directly in the properties prop, or the anyOf prop
				 */
				let defOrPropDescription: object = webpackSchemaProp
					? webpackSchemaProp.properties
					: webpackSchema.properties[action].properties
						? webpackSchema.properties[action].properties
						: webpackSchema.properties[action].anyOf
							? webpackSchema.properties[action].anyOf.filter(
								(p: {
									properties?: object,
									enum?: any[],
								}) => p.properties || p.enum,
							  )
							: null;
				if (Array.isArray(defOrPropDescription)) {
					// Todo: Generalize these to go through the array, then merge enum with props if needed
					const hasPropertiesProp: boolean = traverseAndGetProperties(
{'fraction_non_alphanumeric': 0.12833318469633462, 'fraction_numerical': 0.0019620083831267277, 'mean_word_length': 3.432411067193676, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 30, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3294667', 'n_tokens_mistral': 3993, 'n_tokens_neox': 3266, 'n_words': 913}