diff --git a/.gitignore b/.gitignore
index 2ab8b0a6666..1f1ea578ac1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,4 @@ moodle-plugin-ci.phar
.hugo_build.lock
phpcs.xml
jsconfig.json
+UPGRADING-CURRENT.md
diff --git a/.grunt/notes/src/components.mjs b/.grunt/notes/src/components.mjs
new file mode 100644
index 00000000000..f328766dfed
--- /dev/null
+++ b/.grunt/notes/src/components.mjs
@@ -0,0 +1,110 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import * as Components from '../../components.js';
+
+const componentData = Components.fetchComponentData();
+
+/**
+ * The standard components shipped with core Moodle.
+ *
+ * @type {Object}
+ */
+export const standardComponents = componentData.standardComponents;
+
+/**
+ * All components of the current Moodle instance.
+ *
+ * @type {Object}
+ */
+export const allComponents = componentData.components;
+
+/**
+ * Get all components of the current Moodle instance.
+ *
+ * @returns {Array}
+ */
+export const getAllComponents = () => {
+ let components = new Map(Object.entries(componentData.pluginTypes).map(([value, path]) => ([path,{
+ path,
+ value,
+ name: `${value} (plugin type)`,
+ }])));
+
+ Object
+ .entries(componentData.components)
+ .filter(([path, value]) => Object.values(componentData.standardComponents).includes(value))
+ .forEach(([path, value]) => {
+ const entry = {
+ path,
+ value,
+ name: value,
+ };
+ if (Object.values(componentData.subsystems).includes(value)) {
+ if (components.has(path)) {
+ entry.name = `${value} (subsystem / plugintype)`;
+ } else {
+ entry.name = `${value} (subsystem)`;
+ }
+ }
+
+ components.set(path, entry);
+ });
+
+ return Array.from(components.values());
+};
+
+/**
+ * Whether the specified component is a standard component shipped with core Moodle.
+ *
+ * @param {string} componentName
+ * @returns {boolean}
+ */
+export const isStandardComponent = (componentName) => {
+ if (Object.values(componentData.standardComponents).includes(componentName)) {
+ return true;
+ }
+
+ if (Object.keys(componentData.pluginTypes).includes(componentName)) {
+ return true;
+ }
+
+ return false;
+};
+
+export const rewritePlugintypeAsSubsystem = (componentName) => {
+ if (Object.keys(componentData.pluginTypes).includes(componentName)) {
+ const pluginTypePath = componentData.pluginTypes[componentName];
+ if (Object.keys(componentData.subsystems).includes(pluginTypePath)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Whether the specified component is a community component.
+ *
+ * @param {string} componentName
+ * @returns {boolean}
+ */
+export const isCommunityComponent = (componentName) => {
+ if (isStandardComponent(componentName)) {
+ return false;
+ }
+
+ return Object.values(componentData.components).indexOf(componentName) !== -1;
+}
diff --git a/.grunt/notes/src/create.mjs b/.grunt/notes/src/create.mjs
new file mode 100644
index 00000000000..70c41532db8
--- /dev/null
+++ b/.grunt/notes/src/create.mjs
@@ -0,0 +1,85 @@
+#!/usr/bin/env node
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+
+import { createNote } from './note.mjs';
+import { getInitialValues } from './helpers.mjs';
+import * as Prompts from './prompts.mjs';
+import logger from './logger.mjs';
+
+export default async (options) => {
+ // Processs the initial values.
+ const initialValues = getInitialValues(options);
+
+ // Fetch information.
+ const messages = [];
+ const { issueNumber } = await inquirer.prompt([
+ Prompts.getIssuePrompt(),
+ ], initialValues);
+
+ let selection = {};
+ let notePath;
+ do {
+ selection = {};
+ selection = await inquirer.prompt([
+ Prompts.getComponentsPrompt(),
+ Prompts.getTypePrompt(),
+ Prompts.getMessagePromptInput(),
+ ], initialValues);
+ if (selection.message === '') {
+ selection = Object.assign(
+ selection,
+ await inquirer.prompt([
+ Prompts.getMessagePromptEditor(),
+ ]),
+ );
+ }
+
+ logger.info(`
+ Creating upgrade note with the following options:
+
+ - Issue: ${chalk.bold(issueNumber)}
+ - Component: ${chalk.bold(selection.components)}
+ - Type: ${chalk.bold(selection.type)}
+ - Message:
+ ${chalk.bold(selection.message)}
+`);
+
+ messages.push({
+ components: [selection.components],
+ type: selection.type,
+ message: selection.message,
+ });
+
+ // Save the note so far.
+ if (notePath) {
+ await createNote(issueNumber, messages, notePath);
+ logger.info(`Updated note at: ${chalk.underline(chalk.bold(notePath))}`);
+ } else {
+ notePath = await createNote(issueNumber, messages);
+ logger.info(`Note created at: ${chalk.underline(chalk.bold(notePath))}`);
+ }
+
+ selection = Object.assign(
+ selection,
+ await inquirer.prompt([
+ Prompts.getAddAnotherPrompt(),
+ ], initialValues),
+ );
+ } while (selection.addAnother);
+};
diff --git a/.grunt/notes/src/generate.mjs b/.grunt/notes/src/generate.mjs
new file mode 100644
index 00000000000..8a09419e121
--- /dev/null
+++ b/.grunt/notes/src/generate.mjs
@@ -0,0 +1,318 @@
+#!/usr/bin/env node
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import chalk from 'chalk';
+import { getAllComponents } from './components.mjs';
+import { getCombinedNotesByComponent, deleteAllNotes } from './note.mjs';
+import { getNoteName } from './noteTypes.mjs';
+import { writeFile, readFile, unlink } from 'fs/promises';
+import { join as joinPath } from 'path';
+import logger from './logger.mjs';
+import { getCurrentVersion } from './helpers.mjs';
+
+/**
+ * Helper to fetch the current notes from a file.
+ *
+ * @param {string} file
+ * @returns {Promise}
+ */
+const getCurrentNotes = async (file) => {
+ try {
+ return await readFile(file, 'utf8');
+ } catch (error) {
+ return null;
+ }
+}
+
+/**
+ * Update the UPGRADING.md file.
+ *
+ * @param {string} upgradeNotes
+ * @param {Object} options
+ * @param {boolean} options.deleteNotes
+ * @returns {Promise}
+ */
+const updateUpgradeNotes = async (upgradeNotes, options) => {
+ const fileName = 'UPGRADING.md';
+ // Write the notes to a file.
+ logger.info(`Writing notes to ${chalk.underline(chalk.bold(fileName))}`);
+ // Prepend to the existing file.
+ const existingContent = await getCurrentNotes(fileName);
+ if (existingContent) {
+ await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
+ } else {
+ // This should not normally happen.
+ await writeFile(fileName, upgradeNotes);
+ }
+
+ if (options.deleteNotes) {
+ logger.warn(`>>> Deleting all notes <<<`)
+ // Delete the notes.
+ deleteAllNotes();
+ }
+};
+
+/**
+ * Create the current summary notes.
+ *
+ * @param {string} upgradeNotes
+ * @returns {Promise}
+ */
+const createCurrentSummary = async (upgradeNotes) => {
+ const fileName = 'UPGRADING-CURRENT.md';
+ const notes = `# Moodle upgrade notes\n\n${upgradeNotes}`;
+ await writeFile(fileName, notes);
+
+ logger.info(`Running upgrade notes written to ${chalk.underline(chalk.bold(fileName))}`);
+};
+
+/**
+ * Get the indexes of the lines that contain the version headings.
+ *
+ * @param {array} lines
+ * @returns {array}
+ */
+const getVersionLineIndexes = (lines) => {
+ const h2Indexes = [];
+ lines.forEach((line, index) => {
+ const matches = line.match(/^##\s(?.*)$/);
+ if (matches) {
+ h2Indexes.push({
+ index,
+ line,
+ version: matches.groups.version,
+ });
+ }
+ });
+
+ return h2Indexes;
+};
+
+/**
+ * Find the index of the Unreleased heading.
+ *
+ * @param {array} versionHeadings
+ * @returns {number}
+ */
+const findUnreleasedHeadingIndex = (versionHeadings) => versionHeadings.findIndex((heading) => {
+ if (heading.version === 'Unreleased') {
+ // Used if version cannot be guessed.
+ return true;
+ }
+
+ if (heading.version.endsWith('+')) {
+ // Weekly release for a stable branch.
+ return true;
+ }
+
+ if (heading.version.match(/beta|rc\d/)) {
+ // Beta and RC rolls are treated as weeklies.
+ return true;
+ }
+
+
+
+ if (heading.version.endsWith('dev')) {
+ // Development version.
+ return true;
+ }
+
+ return false;
+});
+
+/**
+ * Get the before and after content, to facilitate replacing any existing Unreleased notes.
+ *
+ * @param {array} lines
+ * @returns {Object} {beforeContent: string, afterContent: string}
+ */
+const getBeforeAndAfterContent = (lines) => {
+ const existingLines = lines.split('\n');
+ const versionHeadings = getVersionLineIndexes(existingLines);
+
+ if (versionHeadings.length > 0) {
+ const unreleasedHeadingIndex = findUnreleasedHeadingIndex(versionHeadings);
+ if (unreleasedHeadingIndex !== -1) {
+ const beforeContent = existingLines.slice(0, versionHeadings[unreleasedHeadingIndex].index).join('\n');
+ if (versionHeadings.length > unreleasedHeadingIndex + 1) {
+ const afterContent = existingLines.slice(versionHeadings[unreleasedHeadingIndex + 1].index).join('\n');
+ return {
+ beforeContent,
+ afterContent,
+ };
+ }
+ return {
+ beforeContent,
+ afterContent: '',
+ };
+ }
+
+ return {
+ beforeContent: existingLines.slice(0, versionHeadings[0].index).join('\n'),
+ afterContent: existingLines.slice(versionHeadings[0].index).join('\n'),
+ };
+ }
+
+ return {
+ beforeContent: existingLines.join('\n'),
+ afterContent: '',
+ }
+};
+
+/**
+ * Get the notes for the component.
+ *
+ * @param {string} type
+ * @param {Number} headingLevel
+ * @returns {string}
+ */
+const getNotesForComponent = (types, headingLevel) => {
+ let upgradeNotes = '';
+ Object.entries(types).forEach(([type, notes]) => {
+ upgradeNotes += '#'.repeat(headingLevel);
+ upgradeNotes += ` ${getNoteName(type)}\n\n`;
+ notes.forEach(({ message, issueNumber }) => {
+ // Split the message into lines, removing empty lines.
+ const messageLines = message
+ .split('\n')
+ .filter((line) => line.trim().length > 0);
+
+ const firstLine = messageLines.shift().trim();
+ upgradeNotes += `- ${firstLine}\n`;
+
+ messageLines
+ .forEach((line) => {
+ upgradeNotes += ` ${line.trimEnd()}\n`;
+ });
+ upgradeNotes += `\n For more information see [${issueNumber}](https://tracker.moodle.org/browse/${issueNumber})\n`;
+ });
+ upgradeNotes += '\n';
+ });
+
+ return upgradeNotes;
+};
+
+/**
+ * Get the updated notes mixed with existing content.
+ *
+ * @param {string} existingContent
+ * @param {string} upgradeNotes
+ */
+const getUpdatedNotes = (existingContent, upgradeNotes) => {
+ const { beforeContent, afterContent } = getBeforeAndAfterContent(existingContent);
+ const newContent = `${beforeContent}\n${upgradeNotes}\n${afterContent}`
+ .split('\n')
+ .filter((line, index, lines) => {
+ if (line === '' && lines[index - 1] === '') {
+ // Remove multiple consecutive empty lines.
+ return false;
+ }
+ return true;
+ })
+ .join('\n');
+
+ return newContent;
+};
+
+/**
+ * Update the notes for each component.
+ */
+const updateComponentNotes = (
+ notes,
+ version,
+ notesFileName = 'UPGRADING.md',
+ removeEmpty = false,
+) => {
+ return getAllComponents().map(async (component) => {
+ logger.verbose(`Updating notes for ${component.name} into ${component.path}`);
+ const fileName = joinPath(component.path, notesFileName);
+
+ const existingContent = await getCurrentNotes(fileName);
+
+ if (!existingContent) {
+ if (!notes[component.value]) {
+ // No existing notes, and no new notes to add.
+ return;
+ }
+ } else {
+ if (!notes[component.value]) {
+ // There is existing content, but nothing to add.
+ if (removeEmpty) {
+ logger.verbose(`Removing empty notes file ${fileName}`);
+ await unlink(fileName);
+ }
+ return;
+ }
+ }
+
+ const componentNotes = notes[component.value];
+ let upgradeNotes = `## ${version}\n\n`;
+ upgradeNotes += getNotesForComponent(componentNotes, 3);
+
+ if (existingContent) {
+ await writeFile(fileName, getUpdatedNotes(existingContent, upgradeNotes));
+ } else {
+ await writeFile(
+ fileName,
+ `# ${component.name} Upgrade notes\n\n${upgradeNotes}`,
+ );
+ }
+ });
+}
+
+/**
+ * Generate the upgrade notes for a new release.
+ *
+ * @param {string|undefined} version
+ * @param {Object} options
+ * @param {boolean} options.generateUpgradeNotes
+ * @param {boolean} options.deleteNotes
+ * @returns {Promise}
+ */
+export default async (version, options = {}) => {
+ const notes = await getCombinedNotesByComponent();
+
+ if (Object.keys(notes).length === 0) {
+ logger.warn('No notes to generate');
+ return;
+ }
+
+ if (!version) {
+ version = await getCurrentVersion();
+ }
+
+ // Generate the upgrade notes for this release.
+ // We have
+ // - a title with the release name
+ // - the change types
+ // - which contain the components
+ // - which document each changev
+ let upgradeNotes = `## ${version}\n\n`;
+
+ Object.entries(notes).forEach(([component, types]) => {
+ upgradeNotes += `### ${component}\n\n`;
+ upgradeNotes += getNotesForComponent(types, 4);
+ });
+
+ await Promise.all([
+ createCurrentSummary(upgradeNotes),
+ ...updateComponentNotes(notes, version, 'UPGRADING-CURRENT.md', true),
+ ]);
+ if (options.generateUpgradeNotes) {
+ await Promise.all(updateComponentNotes(notes, version));
+ await updateUpgradeNotes(upgradeNotes, options);
+ }
+};
diff --git a/.grunt/notes/src/helpers.mjs b/.grunt/notes/src/helpers.mjs
new file mode 100644
index 00000000000..87d741e732a
--- /dev/null
+++ b/.grunt/notes/src/helpers.mjs
@@ -0,0 +1,230 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import chalk from 'chalk';
+import { isStandardComponent, isCommunityComponent, rewritePlugintypeAsSubsystem } from './components.mjs';
+import { isValidNoteName } from './noteTypes.mjs';
+import logger from './logger.mjs';
+import { readFile } from 'fs/promises';
+
+/**
+ * Validate an issue number input
+ *
+ * @param {string} input
+ * @returns {string|boolean}
+ */
+export const validateIssueNumber = (input) => {
+ if (!input) {
+ return 'You must provide a tracker issue number';
+ }
+
+ if (input.match(/^[a-zA-Z]*-\d+$/)) {
+ return true;
+ }
+
+ if (input.match(/^\d+$/)) {
+ return true;
+ }
+
+ return 'The issue number was not recognised as a valid issue number';
+};
+
+/**
+ * Format an issue number input.
+ *
+ * @param {string} input
+ * @returns {string}
+ */
+export const formatIssueNumber = (input) => {
+ if (input.match(/^[a-zA-Z]*-\d+$/)) {
+ return input;
+ }
+
+ if (input.match(/^\d+$/)) {
+ return `MDL-${input}`;
+ }
+
+ return input;
+};
+
+/**
+ * Validate a component.
+ *
+ * @param {string} input
+ * @returns {string|boolean}
+ */
+export const validateComponent = (input) => {
+ if (isStandardComponent(input)) {
+ return true;
+ }
+
+ if (isCommunityComponent(input)) {
+ return 'Currently only core plugins are supported.';
+ }
+
+ return 'The component was not recognised as a standard component';
+};
+
+export const formatComponent = (input) => {
+ if (rewritePlugintypeAsSubsystem(input)) {
+ return `core_${input}`;
+ }
+ return input;
+}
+
+/**
+ * Get the initial values from the options.
+ *
+ * @param {object} options
+ * @returns {object}
+ */
+export const getInitialValues = (options) => {
+ const initialValues = {};
+
+ const type = getInitialTypeValue(options);
+ if (type) {
+ initialValues.type = type;
+ }
+
+ const issueNumber = getInitialIssueValue(options);
+ if (issueNumber) {
+ initialValues.issueNumber = issueNumber;
+ }
+
+ const component = getInitialComponentValue(options);
+ if (component) {
+ initialValues.components = component;
+ }
+
+ const message = getInitialMessageValue(options);
+ if (message) {
+ initialValues.message = message
+ initialValues.addAnother = false;
+ }
+
+ return initialValues;
+};
+
+/**
+ * Get the initial type value.
+ *
+ * @param {Object} options
+ * @returns {string|undefined}
+ */
+const getInitialTypeValue = (options) => {
+ if (!options.type) {
+ return;
+ }
+
+ options.type = options.type.trim().toLowerCase();
+
+ if (isValidNoteName(options.type)) {
+ return options.type;
+ }
+
+ logger.warn(`Note type "${chalk.underline(chalk.red(options.type))}" is not valid.`);
+};
+
+/**
+ * Get the initial issue number value.
+ *
+ * @param {Object} options
+ * @returns {string|undefined}
+ */
+
+const getInitialIssueValue = (options) => {
+ if (!options.issue) {
+ return;
+ }
+ options.issue = options.issue.trim().toUpperCase();
+
+ const issueNumberValidated = validateIssueNumber(options.issue);
+ if (issueNumberValidated === true) {
+ const issueNumber = formatIssueNumber(options.issue);
+ if (issueNumber !== options.issue) {
+ logger.warn(
+ `Issue number "${chalk.underline(chalk.red(options.issue))}" was updated to ` +
+ `"${chalk.underline(chalk.green(issueNumber))}"`
+ );
+ }
+
+ return issueNumber;
+ } else {
+ logger.warn(`Issue number "${chalk.underline(chalk.red(options.issue))}" is not valid: ${issueNumberValidated}`);
+ }
+};
+
+/**
+ * Get the initial component value.
+ *
+ * @param {Object} options
+ * @returns {string|undefined}
+ */
+const getInitialComponentValue = (options) => {
+ if (!options.component) {
+ return;
+ }
+
+ options.component = options.component.trim().toLowerCase();
+ const componentValidated = validateComponent(options.component);
+ if (componentValidated === true) {
+ const component = formatComponent(options.component);
+ if (component !== options.component) {
+ logger.warn(
+ `Component "${chalk.underline(chalk.red(options.component))}" was updated to ` +
+ `"${chalk.underline(chalk.green(component))}"`
+ );
+ }
+
+ return component;
+ } else {
+ logger.warn(`Component "${chalk.underline(chalk.red(options.component))}" is not valid: ${componentValidated}`);
+ }
+};
+
+/**
+ * Get the initial message value.
+ *
+ * @param {Object} options
+ * @returns {string|undefined}
+ */
+
+const getInitialMessageValue = (options) => {
+ if (!options.message) {
+ return;
+ }
+
+ return options.message.trim();
+};
+
+/**
+ * Get the current version from the project /version.php file.
+ *
+ * @returns {Promise}
+ */
+export const getCurrentVersion = async () => {
+ const versionRegex = new RegExp(/^ *\$release *= *['\"](?[^ \+]+\+?) *\(Build:.*/m);
+ try {
+ const versionFile = await readFile('version.php', 'utf8');
+ const match = versionFile.match(versionRegex);
+ if (match) {
+ return match.groups.release;
+ }
+ } catch(error) {
+ logger.error('Unable to read the version file');
+ }
+
+ return "Unreleased";
+}
diff --git a/.grunt/notes/src/logger.mjs b/.grunt/notes/src/logger.mjs
new file mode 100644
index 00000000000..571cc992b33
--- /dev/null
+++ b/.grunt/notes/src/logger.mjs
@@ -0,0 +1,30 @@
+#!/usr/bin/env node
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import winston from 'winston';
+
+const logger = winston.createLogger({
+ level: 'info',
+ format: winston.format.combine(
+ winston.format.colorize(),
+ winston.format.simple()
+ ),
+ transports: [
+ new winston.transports.Console(),
+ ],
+});
+
+export default logger;
diff --git a/.grunt/notes/src/note.mjs b/.grunt/notes/src/note.mjs
new file mode 100644
index 00000000000..3aafcd1f35e
--- /dev/null
+++ b/.grunt/notes/src/note.mjs
@@ -0,0 +1,183 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import yaml from 'js-yaml';
+import path from 'path';
+import { writeFile, mkdir, readdir, readFile, unlink } from 'fs/promises';
+import { isValidNoteName } from './noteTypes.mjs';
+
+const unreleasedPath = path.resolve('.upgradenotes');
+
+/**
+ * Get the filename for the note.
+ *
+ * @param {string} issueNumnber The issue number
+ * @returns {string}
+ */
+const getFilename = (issueNumber) => {
+ const dateTimeFormat = new Intl.DateTimeFormat(undefined, {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ fractionalSecondDigits: 2,
+ timeZone: 'UTC',
+ });
+
+ const date = Object.fromEntries(
+ dateTimeFormat.formatToParts(new Date())
+ .filter((p) => p.type !== 'literal')
+ .map((p) => ([p.type, p.value]))
+ );
+
+ const dateString = [
+ date.year,
+ date.month,
+ date.day,
+ date.hour,
+ date.minute,
+ date.second,
+ date.fractionalSecond,
+ ].join('');
+
+ return `${issueNumber}-${dateString}.yml`;
+};
+
+/**
+ * Create a new note.
+ *
+ * @param {string} issueNumber
+ * @param {[type: string]: {message: string}} messages
+ * @returns {string} The path to the note on disk
+ */
+export const createNote = async (
+ issueNumber,
+ messages,
+ notePath,
+) => {
+ const note = {
+ issueNumber,
+ notes: {},
+ };
+
+ messages.forEach(({components, type, message}) => {
+ note.notes[components] = note.notes[components] || [];
+ note.notes[components].push({message, type});
+ });
+
+ if (!notePath) {
+ notePath = path.resolve(unreleasedPath, getFilename(issueNumber));
+ }
+ const noteContent = yaml.dump(note);
+
+ await mkdir(unreleasedPath, {recursive: true});
+ await writeFile(notePath, noteContent);
+
+ return notePath;
+};
+
+/**
+ * Get all unreleased notes.
+ *
+ * @returns {Promise<{issueNumber: string, components: string[], types: {[type: string]: {message: string}[]}}[]>
+ */
+export const getAllNotes = async () => {
+ const files = await readdir(unreleasedPath);
+ const notes = files
+ .filter((file) => file.endsWith('.yml'))
+ .map(async (file) => {
+ const filePath = path.resolve(unreleasedPath, file);
+ const fileContent = await readFile(filePath, 'utf8');
+
+ return {
+ ...yaml.load(fileContent),
+ filePath,
+ };
+ });
+
+ return Promise.all(notes);
+};
+
+/**
+ * Get the list of notes, grouped by note type, then component.
+ *
+ * @returns {Promise<{[type: string]: {[components: string]: {message: string, issueNumber: string}[]}}>}
+ */
+export const getCombinedNotes = async () => {
+ const notes = await getAllNotes();
+ const combinedNotes = {};
+
+ notes.forEach((note) => {
+ Object.entries(note.notes).forEach(([components, data]) => {
+ data.forEach((entry) => {
+ if (!isValidNoteName(entry.type)) {
+ throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
+ }
+ combinedNotes[entry.type] = combinedNotes[entry.type] || {};
+ combinedNotes[entry.type][components] = combinedNotes[entry.type][components] || [];
+ combinedNotes[entry.type][components].push({message: entry.message, issueNumber: note.issueNumber});
+ });
+ });
+ });
+
+ return combinedNotes;
+};
+
+/**
+ * Get the list of notes, grouped by component, then by note type.
+ *
+ * @returns {Promise<{[component: string]: {[type: string]: {message: string, issueNumber: string}[]}}>}
+ */
+export const getCombinedNotesByComponent = async () => {
+ const notes = await getAllNotes();
+ const combinedNotes = {};
+
+ notes.forEach((note) => {
+ Object.entries(note.notes).forEach(([component, data]) => {
+ combinedNotes[component] = combinedNotes[component] || {};
+ data.forEach((entry) => {
+ if (!isValidNoteName(entry.type)) {
+ throw new Error(`Invalid note type: "${entry.type}" in file ${note.filePath}`);
+ }
+ combinedNotes[component][entry.type] = combinedNotes[component][entry.type] || [];
+ combinedNotes[component][entry.type].push({
+ component,
+ message: entry.message,
+ issueNumber: note.issueNumber,
+ type: entry.type,
+ });
+ });
+ });
+ });
+
+ return combinedNotes;
+};
+
+/**
+ * Delete all unreleased notes.
+ *
+ * @returns {Promise}
+ */
+export const deleteAllNotes = async () => {
+ const files = await readdir(unreleasedPath);
+ return Promise.all(
+ files
+ .filter((item, index) => files.indexOf(item) === index)
+ .filter((file) => file.endsWith('.yml'))
+ .map((file) => unlink(`${unreleasedPath}/${file}`))
+ );
+};
diff --git a/.grunt/notes/src/noteTypes.mjs b/.grunt/notes/src/noteTypes.mjs
new file mode 100644
index 00000000000..eaa1834271c
--- /dev/null
+++ b/.grunt/notes/src/noteTypes.mjs
@@ -0,0 +1,45 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+const noteTypes = {
+ 'improved': 'Added',
+ 'removed': 'Removed',
+ 'changed': 'Changed',
+ 'deprecated': 'Deprecated',
+ 'fixed': 'Fixed',
+};
+
+/**
+ * Get the note names.
+ *
+ * @returns {string[]}
+ */
+export const getNoteNames = () => Object.keys(noteTypes);
+
+/**
+ * Get the human-readable note name.
+ *
+ * @param {string} type
+ * @returns {string}
+ */
+export const getNoteName = (type) => noteTypes[type];
+
+/**
+ * Whether the note name is valid.
+ *
+ * @param {string} type
+ * @returns {boolean}
+ */
+export const isValidNoteName = (type) => noteTypes[type] !== undefined;
diff --git a/.grunt/notes/src/prompts.mjs b/.grunt/notes/src/prompts.mjs
new file mode 100644
index 00000000000..8b95ed1724d
--- /dev/null
+++ b/.grunt/notes/src/prompts.mjs
@@ -0,0 +1,153 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import inquirer from 'inquirer';
+import SearchList from 'inquirer-search-list';
+
+import { getNoteNames } from './noteTypes.mjs';
+import { getAllComponents } from './components.mjs';
+import {
+ formatComponent,
+ formatIssueNumber,
+ validateComponent,
+ validateIssueNumber,
+ } from './helpers.mjs';
+
+/**
+ * A Search List which accepts an initial value.
+ */
+class SearchListWithInitialValue extends SearchList {
+ constructor(options, ...args) {
+ super(options, ...args);
+
+ if (options.default) {
+ const pointer = this.filterList.findIndex((item) => {
+ return item.value === options.default;
+ });
+ if (pointer > -1) {
+ this.pointer = pointer;
+ }
+ }
+ }
+}
+
+inquirer.registerPrompt('search-list', SearchListWithInitialValue);
+
+/**
+ * Get the issue type prompt.
+ *
+ * @param {string} defaultData The initially selected value
+ * @returns {Object}
+ */
+export const getTypePrompt = (defaultData) => ({
+ default: defaultData,
+ type: 'search-list',
+ message: 'Type of change',
+ name: 'type',
+ choices: getNoteNames(),
+ validate: (selection) => {
+ if (selection.length < 1) {
+ return 'You must select at least one type of change';
+ }
+
+ return true;
+ },
+});
+
+/**
+ * Get the component prompt.
+ *
+ * @param {string} [defaultValue='core'] The initally selected value.
+ * @returns
+ */
+export const getComponentsPrompt = (defaultValue) => {
+ if (!defaultValue ) {
+ defaultValue = 'core';
+ }
+
+ return {
+ choices: getAllComponents(),
+ default: defaultValue,
+ type: 'search-list',
+ message: 'Component',
+ name: 'components',
+ validate: validateComponent,
+ filter: formatComponent,
+ };
+};
+
+/**
+ * Get the issue number prompt as an inline input.
+ *
+ * @param {string} defaultData
+ * @returns {object}
+ */
+export const getIssuePrompt = (defaultData) => ({
+ default: defaultData,
+ type: 'input',
+ message: 'Tracker issue number',
+ name: 'issueNumber',
+ validate: validateIssueNumber,
+ filter: formatIssueNumber,
+});
+
+/**
+ * Get a message prompt.
+ *
+ * @param {string} defaultData
+ * @returns
+ */
+export const getMessagePromptEditor = (defaultData) => ({
+ default: defaultData,
+ type: process.stdin.isTTY ? 'editor' : 'input',
+ postfix: '.md',
+ message: 'Message',
+ name: 'message',
+ waitUserInput: false,
+ validate: (input) => {
+ if (!input) {
+ return 'You must provide a message';
+ }
+ return true;
+ },
+ // Remove any trailing whitespace.
+ filter: (input) => input.split('\n').map((line) => line.trimEnd()).join('\n'),
+});
+
+/**
+ * Get a message prompt.
+ *
+ * @param {string} defaultData
+ * @returns
+ */
+export const getMessagePromptInput = (defaultData) => ({
+ default: defaultData,
+ type: 'input',
+ message: 'Message (leave empty to use editor)',
+ name: 'message',
+ filter: (input) => input.trim(),
+});
+
+/**
+ * Get a prompt to ask the user if they wish to add another entry.
+ *
+ * @returns {Object}
+ */
+export const getAddAnotherPrompt = () => ({
+ type: 'confirm',
+ message: 'Do you want to add another note?',
+ default: false,
+ name: 'addAnother',
+});
diff --git a/.grunt/upgradenotes.mjs b/.grunt/upgradenotes.mjs
new file mode 100755
index 00000000000..c274049bfaf
--- /dev/null
+++ b/.grunt/upgradenotes.mjs
@@ -0,0 +1,103 @@
+#!/usr/bin/env node
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see .
+
+import { Argument, Option, program } from 'commander';
+import chalk from 'chalk';
+
+import { getNoteNames } from './notes/src/noteTypes.mjs';
+import createAction from './notes/src/create.mjs';
+import generateAction from './notes/src/generate.mjs';
+import logger from './notes/src/logger.mjs';
+
+console.log(`
+${chalk.bold(chalk.underline(chalk.green('Moodle Upgrade Notes Generator')))}
+
+This tool is used to generate the upgrade notes for changes you make in Moodle.
+
+Please remember that the intended audience of these changes is
+${chalk.italic('plugin developers')} who need to know how to update their plugins
+for a new Moodle version.
+
+Upgrade notes should not be used to document changes for site administrators, or
+for internal API changes which are not expected to be used outside of the
+relevant component.
+`)
+
+program.configureHelp({
+ helpWidth: 100,
+});
+
+program.on('option:verbose', () => {
+ logger.level = 'verbose';
+});
+
+program.addOption(
+ new Option(
+ '-v, --verbose',
+ 'Output more information during the generation process',
+ )
+ .default(false)
+);
+
+// Define the command line options.
+program
+ .command('create')
+ .summary('Generate a new upgrade note')
+ .addOption(
+ new Option('-t, --type ', `The type of change to document. Valid types are: ${getNoteNames().join(', ')}`)
+ )
+ .addOption(new Option('-i, --issue ', 'The tracker issue number'))
+ .addOption(new Option('-c, --component ', 'The component to write a note for'))
+ .addOption(new Option(
+ '-m, --message ',
+ 'The message to use for the upgrade note',
+ ))
+ .action((options) => createAction(options));
+
+program
+ .command('summary')
+ .summary('Generate a local copy of the upgrade notes summary')
+ .addArgument(
+ new Argument('[version]', 'The Moodle version to create the summary notes for')
+ )
+ .action((version) => generateAction(version));
+
+program
+ .command('release')
+ .summary('Generate the markdown copies of the upgrade notes for a Moodle release')
+ .addArgument(
+ new Argument('[version]', 'The Moodle version to create the release notes for')
+ )
+ .addOption(
+ new Option(
+ '--generate-upgrade-notes',
+ 'Generate the UPGRADING.md notes for the release. ' +
+ 'Note: This option is intended for use by the release manager when generating the upgrade notes.',
+ )
+ .default(true)
+ )
+ .addOption(
+ new Option(
+ '-d, --delete-notes',
+ 'Delete the notes after generating the UPGRADING.md notes for the release. ' +
+ 'Note: This option is intended for use by the release manager when generating the upgrade notes.' +
+ 'This option has no effect unless --generate-upgrade-notes is also set.'
+ )
+ .default(false)
+ )
+ .action((version, options) => generateAction(version, options));
+
+program.parse();
diff --git a/.upgradenotes/.gitkeep b/.upgradenotes/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/UPGRADING.md b/UPGRADING.md
new file mode 100644
index 00000000000..dbad8e733de
--- /dev/null
+++ b/UPGRADING.md
@@ -0,0 +1,7 @@
+# Moodle Upgrade notes
+
+This file contains important information for developers on changes to the Moodle codebase.
+
+More detailed information on key changes can be found in the [Developer update notes](https://moodledev.io/docs/devupdate) for your version of Moodle.
+
+The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index b3d9fc361d8..50c070eea3e 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -16,6 +16,8 @@
"babel-plugin-system-import-transformer": "^4.0.0",
"babel-plugin-transform-es2015-modules-amd-lazy": "2.0.1",
"babel-preset-minify": "0.5.1",
+ "chalk": "^5.3.0",
+ "commander": "^12.0.0",
"cross-env": "^7.0.3",
"docdash": "^2.0.2",
"eslint": "^8.56.0",
@@ -33,6 +35,8 @@
"grunt-stylelint": "^0.19.0",
"hugo-bin": "^0.80.2",
"hugo-lunr-indexer": "^1.1.3",
+ "inquirer": "^9.2.15",
+ "inquirer-search-list": "^1.2.6",
"jsdoc": "^4.0.2",
"jsdoc-to-markdown": "^8.0.0",
"jshint": "^2.13.4",
@@ -45,6 +49,7 @@
"shifter": "https://github.com/andrewnicols/shifter/archive/v1.2.0_moodle-0.tar.gz",
"stylelint": "^15.11.0",
"stylelint-csstree-validator": "^3.0.0",
+ "winston": "^3.13.0",
"xpath": "0.0.32"
},
"engines": {
@@ -568,6 +573,44 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/highlight/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@babel/parser": {
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
@@ -1713,6 +1756,15 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@colors/colors": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
"node_modules/@csstools/css-parser-algorithms": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz",
@@ -1799,6 +1851,17 @@
"postcss-selector-parser": "^6.0.13"
}
},
+ "node_modules/@dabh/diagnostics": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
+ "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
+ "dev": true,
+ "dependencies": {
+ "colorspace": "1.1.x",
+ "enabled": "2.0.x",
+ "kuler": "^2.0.0"
+ }
+ },
"node_modules/@es-joy/jsdoccomment": {
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz",
@@ -2068,6 +2131,18 @@
"node": ">=v12.0.0"
}
},
+ "node_modules/@ljharb/through": {
+ "version": "2.3.13",
+ "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz",
+ "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -2241,6 +2316,12 @@
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"dev": true
},
+ "node_modules/@types/triple-beam": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+ "dev": true
+ },
"node_modules/@types/uuid": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz",
@@ -2350,6 +2431,33 @@
"node": ">=6"
}
},
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-escapes/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -3194,13 +3302,19 @@
}
},
"node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"dev": true,
"dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3283,42 +3397,22 @@
}
},
"node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
"engines": {
- "node": ">=4"
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/chalk/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/chalk/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
},
"node_modules/chokidar": {
"version": "3.5.3",
@@ -3386,6 +3480,39 @@
"node": ">=0.2.5"
}
},
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/cli/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -3418,6 +3545,15 @@
"node": "*"
}
},
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/clone-response": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
@@ -3440,6 +3576,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3455,6 +3601,16 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/colord": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
@@ -3470,6 +3626,16 @@
"node": ">=0.1.90"
}
},
+ "node_modules/colorspace": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+ "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+ "dev": true,
+ "dependencies": {
+ "color": "^3.1.3",
+ "text-hex": "1.0.x"
+ }
+ },
"node_modules/command-line-args": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz",
@@ -3559,12 +3725,12 @@
}
},
"node_modules/commander": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz",
- "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
+ "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==",
"dev": true,
"engines": {
- "node": ">= 6"
+ "node": ">=18"
}
},
"node_modules/comment-parser": {
@@ -4197,6 +4363,35 @@
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -4371,6 +4566,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
+ "node_modules/enabled": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+ "dev": true
+ },
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -4434,16 +4635,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/es-abstract/node_modules/has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"engines": {
"node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/es-to-primitive": {
@@ -5211,6 +5421,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/external-editor/node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5293,6 +5529,27 @@
"pend": "~1.2.0"
}
},
+ "node_modules/fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "dev": true
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz",
@@ -5584,6 +5841,12 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
+ "node_modules/fn.name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+ "dev": true
+ },
"node_modules/for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -5724,10 +5987,22 @@
"dev": true
},
"node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fuzzy": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz",
+ "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
},
"node_modules/gaze": {
"version": "1.1.3",
@@ -6018,14 +6293,19 @@
}
},
"node_modules/get-intrinsic": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
- "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"dev": true,
"dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1"
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -6096,6 +6376,15 @@
"node": ">=10.0.0"
}
},
+ "node_modules/gherkin-lint/node_modules/commander": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz",
+ "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/gherkin-lint/node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -6296,6 +6585,18 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/got": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz",
@@ -6826,12 +7127,36 @@
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-symbol-support-x": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
@@ -6842,9 +7167,9 @@
}
},
"node_modules/has-symbols": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
- "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
"engines": {
"node": ">= 0.4"
@@ -6865,6 +7190,18 @@
"node": "*"
}
},
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/hawk": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz",
@@ -7153,9 +7490,9 @@
}
},
"node_modules/inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/ini": {
@@ -7164,6 +7501,328 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true
},
+ "node_modules/inquirer": {
+ "version": "9.2.15",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz",
+ "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==",
+ "dev": true,
+ "dependencies": {
+ "@ljharb/through": "^2.3.12",
+ "ansi-escapes": "^4.3.2",
+ "chalk": "^5.3.0",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^4.1.0",
+ "external-editor": "^3.1.0",
+ "figures": "^3.2.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "1.0.0",
+ "ora": "^5.4.1",
+ "run-async": "^3.0.0",
+ "rxjs": "^7.8.1",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/inquirer-search-list": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/inquirer-search-list/-/inquirer-search-list-1.2.6.tgz",
+ "integrity": "sha512-C4pKSW7FOYnkAloH8rB4FiM91H1v08QFZZJh6KRt//bMfdDBIhgdX8wjHvrVH2bu5oIo6wYqGpzSBxkeClPxew==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.3.0",
+ "figures": "^2.0.0",
+ "fuzzy": "^0.1.3",
+ "inquirer": "^3.3.0"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/ansi-regex": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
+ "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/chardet": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+ "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==",
+ "dev": true
+ },
+ "node_modules/inquirer-search-list/node_modules/cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==",
+ "dev": true,
+ "dependencies": {
+ "restore-cursor": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/cli-width": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
+ "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
+ "dev": true
+ },
+ "node_modules/inquirer-search-list/node_modules/external-editor": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+ "dev": true,
+ "dependencies": {
+ "chardet": "^0.4.0",
+ "iconv-lite": "^0.4.17",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/inquirer": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.0",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^2.0.4",
+ "figures": "^2.0.0",
+ "lodash": "^4.3.0",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rx-lite": "^4.0.8",
+ "rx-lite-aggregates": "^4.0.8",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^4.0.0",
+ "through": "^2.3.6"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==",
+ "dev": true
+ },
+ "node_modules/inquirer-search-list/node_modules/onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "dependencies": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer-search-list/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/inquirer/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/inquirer/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/inquirer/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/inquirer/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/inquirer/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
@@ -7328,6 +7987,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-natural-number": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
@@ -7422,18 +8090,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-regex/node_modules/has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-relative": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
@@ -7491,18 +8147,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-symbol/node_modules/has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-unc-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
@@ -7515,6 +8159,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -8061,6 +8717,12 @@
"node": "*"
}
},
+ "node_modules/kuler": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+ "dev": true
+ },
"node_modules/less": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/less/-/less-1.7.5.tgz",
@@ -8426,6 +9088,88 @@
"integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
"dev": true
},
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/logform": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz",
+ "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==",
+ "dev": true,
+ "dependencies": {
+ "@colors/colors": "1.6.0",
+ "@types/triple-beam": "^1.3.2",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^2.3.1",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
"node_modules/long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
@@ -8715,6 +9459,15 @@
"node": ">= 0.6"
}
},
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/mimic-response": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
@@ -8798,6 +9551,15 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "node_modules/mute-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz",
+ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@@ -8981,6 +9743,20 @@
"node": ">=4"
}
},
+ "node_modules/npm-run-all/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/npm-run-all/node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
@@ -9053,6 +9829,18 @@
"node": ">=4"
}
},
+ "node_modules/npm-run-all/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -9174,6 +9962,30 @@
"wrappy": "1"
}
},
+ "node_modules/one-time": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+ "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+ "dev": true,
+ "dependencies": {
+ "fn.name": "1.x.x"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optimist": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz",
@@ -9209,6 +10021,103 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/ora/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/ora/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/ora/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/ora/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/os-filter-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz",
@@ -10259,6 +11168,19 @@
"lowercase-keys": "^1.0.0"
}
},
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -10346,6 +11268,15 @@
"rollup": "^2.0.0"
}
},
+ "node_modules/run-async": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
+ "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -10369,6 +11300,30 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rx-lite": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+ "integrity": "sha512-Cun9QucwK6MIrp3mry/Y7hqD1oFqTYLQ4pGxaHTjIdaFDWRGGLikqp6u8LcWJnzpoALg9hap+JGk8sFIUuEGNA==",
+ "dev": true
+ },
+ "node_modules/rx-lite-aggregates": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+ "integrity": "sha512-3xPNZGW93oCjiO7PtKxRK6iOVYBWBvtf9QHDfU23Oc+dLIQmAV//UnyXV/yihv81VS/UqoQPk4NegS8EFi55Hg==",
+ "dev": true,
+ "dependencies": {
+ "rx-lite": "*"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -10381,6 +11336,15 @@
"integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=",
"dev": true
},
+ "node_modules/safe-stable-stringify": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
+ "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -10501,6 +11465,23 @@
"randombytes": "^2.1.0"
}
},
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@@ -10591,6 +11572,21 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "dev": true
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -10794,6 +11790,15 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
+ "node_modules/stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/stream-connect": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz",
@@ -11418,6 +12423,12 @@
"node": ">=4"
}
},
+ "node_modules/text-hex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+ "dev": true
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -11469,6 +12480,18 @@
"ms": "^2.1.1"
}
},
+ "node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "dependencies": {
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
"node_modules/to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
@@ -11540,6 +12563,21 @@
"node": ">=0.10.0"
}
},
+ "node_modules/triple-beam": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14.0.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
+ "dev": true
+ },
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -11621,18 +12659,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/unbox-primitive/node_modules/has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/unbzip2-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
@@ -11806,6 +12832,15 @@
"node >=0.1.95"
]
},
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
"node_modules/websocket-driver": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
@@ -11866,6 +12901,82 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/winston": {
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz",
+ "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==",
+ "dev": true,
+ "dependencies": {
+ "@colors/colors": "^1.6.0",
+ "@dabh/diagnostics": "^2.0.2",
+ "async": "^3.2.3",
+ "is-stream": "^2.0.0",
+ "logform": "^2.4.0",
+ "one-time": "^1.0.0",
+ "readable-stream": "^3.4.0",
+ "safe-stable-stringify": "^2.3.1",
+ "stack-trace": "0.0.x",
+ "triple-beam": "^1.3.0",
+ "winston-transport": "^4.7.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/winston-transport": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
+ "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==",
+ "dev": true,
+ "dependencies": {
+ "logform": "^2.3.2",
+ "readable-stream": "^3.6.0",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/winston-transport/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/winston/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/winston/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
diff --git a/package.json b/package.json
index 35410165952..5521e481e54 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,9 @@
"name": "Moodle",
"private": true,
"description": "Moodle",
+ "scripts": {
+ "upgradenote": "node .grunt/upgradenotes.mjs create"
+ },
"devDependencies": {
"@babel/core": "7.17.5",
"@babel/eslint-parser": "^7.21.3",
@@ -13,6 +16,8 @@
"babel-plugin-system-import-transformer": "^4.0.0",
"babel-plugin-transform-es2015-modules-amd-lazy": "2.0.1",
"babel-preset-minify": "0.5.1",
+ "chalk": "^5.3.0",
+ "commander": "^12.0.0",
"cross-env": "^7.0.3",
"docdash": "^2.0.2",
"eslint": "^8.56.0",
@@ -30,6 +35,8 @@
"grunt-stylelint": "^0.19.0",
"hugo-bin": "^0.80.2",
"hugo-lunr-indexer": "^1.1.3",
+ "inquirer": "^9.2.15",
+ "inquirer-search-list": "^1.2.6",
"jsdoc": "^4.0.2",
"jsdoc-to-markdown": "^8.0.0",
"jshint": "^2.13.4",
@@ -42,6 +49,7 @@
"shifter": "https://github.com/andrewnicols/shifter/archive/v1.2.0_moodle-0.tar.gz",
"stylelint": "^15.11.0",
"stylelint-csstree-validator": "^3.0.0",
+ "winston": "^3.13.0",
"xpath": "0.0.32"
},
"engines": {