Replace nopt with commander.js for argument parsing (#7673)

- Replace nopt with commander.js for better command-line argument parsing
- Add automatic help generation with detailed descriptions
- Maintain backward compatibility with existing arguments
- Remove unused nopt dependency from package.json

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Matt Godbolt
2025-05-12 12:49:28 -05:00
committed by GitHub
parent 1e07e16758
commit 54c942ba76
9 changed files with 144 additions and 201 deletions

View File

@@ -28,7 +28,7 @@ jobs:
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@v6 uses: cypress-io/github-action@v6
with: with:
start: npm run dev -- --language c++ --noLocal start: npm run dev -- --language c++ --no-local
wait-on: 'http://localhost:10240' wait-on: 'http://localhost:10240'
wait-on-timeout: 120 wait-on-timeout: 120
config: screenshotOnRunFailure=true,video=false config: screenshotOnRunFailure=true,video=false

View File

@@ -84,7 +84,7 @@ prebuild: prereqs scripts
.PHONY: run-only .PHONY: run-only
run-only: node-installed ## Runs the site like it runs in production without building it run-only: node-installed ## Runs the site like it runs in production without building it
env NODE_ENV=production $(NODE) $(NODE_ARGS) ./out/dist/app.js --webpackContent ./out/webpack/static $(EXTRA_ARGS) env NODE_ENV=production $(NODE) $(NODE_ARGS) ./out/dist/app.js --webpack-content ./out/webpack/static $(EXTRA_ARGS)
.PHONY: run .PHONY: run
run: ## Runs the site like it runs in production run: ## Runs the site like it runs in production

225
app.ts
View File

@@ -35,12 +35,12 @@ import url from 'node:url';
import * as fsSync from 'node:fs'; import * as fsSync from 'node:fs';
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import {Command, OptionValues} from 'commander';
import compression from 'compression'; import compression from 'compression';
import express from 'express'; import express from 'express';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
import morgan from 'morgan'; import morgan from 'morgan';
import nopt from 'nopt';
import PromClient from 'prom-client'; import PromClient from 'prom-client';
import responseTime from 'response-time'; import responseTime from 'response-time';
import sanitize from 'sanitize-filename'; import sanitize from 'sanitize-filename';
@@ -92,73 +92,73 @@ import type {Language, LanguageKey} from './types/languages.interfaces.js';
setBaseDirectory(new URL('.', import.meta.url)); setBaseDirectory(new URL('.', import.meta.url));
(nopt as any).invalidHandler = (key: string, val: unknown, types: unknown[]) => { function parseNumberForOptions(value: string): number {
logger.error( const parsedValue = Number.parseInt(value, 10);
`Command line argument type error for "--${key}=${val}", if (Number.isNaN(parsedValue)) {
expected ${types.map((t: unknown) => typeof t).join(' | ')}`, throw new Error(`Invalid number: "${value}"`);
); }
}; return parsedValue;
}
type CompilerExplorerOptions = Partial<{ interface CompilerExplorerOptions extends OptionValues {
env: string[]; env: string[];
rootDir: string; rootDir: string;
host: string; host?: string;
port: number; port: number;
propDebug: boolean; propDebug?: boolean;
debug: boolean; debug?: boolean;
dist: boolean; dist?: boolean;
archivedVersions: string; remoteFetch: boolean;
noRemoteFetch: boolean; tmpDir?: string;
tmpDir: string; wsl?: boolean;
wsl: boolean; language?: string[];
language: string[]; cache: boolean;
noCache: boolean; ensureNoIdClash?: boolean;
ensureNoIdClash: boolean; logHost?: string;
logHost: string; logPort?: number;
logPort: number; hostnameForLogging?: string;
hostnameForLogging: string;
suppressConsoleLog: boolean; suppressConsoleLog: boolean;
metricsPort: number; metricsPort?: number;
loki: string; loki?: string;
discoveryonly: string; discoveryOnly?: string;
prediscovered: string; prediscovered?: string;
webpackContent?: string;
local: boolean;
version: boolean; version: boolean;
webpackContent: string; }
noLocal: boolean;
}>;
// Parse arguments from command line 'node ./app.js args...' const program = new Command();
const opts = nopt({ program
env: [String, Array], .name('compiler-explorer')
rootDir: [String], .description('Interactively investigate compiler output')
host: [String], .option('--env <environments...>', 'Environment(s) to use', ['dev'])
port: [Number], .option('--root-dir <dir>', 'Root directory for config files', './etc')
propDebug: [Boolean], .option('--host <hostname>', 'Hostname to listen on')
debug: [Boolean], .option('--port <port>', 'Port to listen on', parseNumberForOptions, 10240)
dist: [Boolean], .option('--prop-debug', 'Debug properties')
archivedVersions: [String], .option('--debug', 'Enable debug output')
// Ignore fetch marks and assume every compiler is found locally .option('--dist', 'Running in dist mode')
noRemoteFetch: [Boolean], .option('--no-remote-fetch', 'Ignore fetch marks and assume every compiler is found locally')
tmpDir: [String], .option('--tmpDir, --tmp-dir <dir>', 'Directory to use for temporary files')
wsl: [Boolean], .option('--wsl', 'Running under Windows Subsystem for Linux')
// If specified, only loads the specified languages, resulting in faster loadup/iteration times .option('--language <languages...>', 'Only load specified languages for faster startup')
language: [String, Array], .option('--no-cache', 'Do not use caching for compilation results')
// Do not use caching for compilation results (Requests might still be cached by the client's browser) .option('--ensure-no-id-clash', "Don't run if compilers have clashing ids")
noCache: [Boolean], .option('--logHost, --log-host <hostname>', 'Hostname for remote logging')
// Don't cleanly run if two or more compilers have clashing ids .option('--logPort, --log-port <port>', 'Port for remote logging', parseNumberForOptions)
ensureNoIdClash: [Boolean], .option('--hostname-for-logging <hostname>', 'Hostname to use in logs')
logHost: [String], .option('--suppressConsoleLog, --suppress-console-log', 'Disable console logging')
logPort: [Number], .option('--metricsPort, --metrics-port <port>', 'Port to serve metrics on', parseNumberForOptions)
hostnameForLogging: [String], .option('--loki <url>', 'URL for Loki logging')
suppressConsoleLog: [Boolean], .option('--discoveryonly, --discovery-only <file>', 'Output discovery info to file and exit')
metricsPort: [Number], .option('--prediscovered <file>', 'Input discovery info from file')
loki: [String], .option('--webpack-content <dir>', 'Path to webpack content')
discoveryonly: [String], .option('--no-local', 'Disable local config')
prediscovered: [String], .option('--version', 'Show version information');
version: [Boolean],
webpackContent: [String], program.parse();
noLocal: [Boolean],
}) as CompilerExplorerOptions; const opts = program.opts<CompilerExplorerOptions>();
if (opts.debug) logger.level = 'debug'; if (opts.debug) logger.level = 'debug';
@@ -222,39 +222,29 @@ const releaseBuildNumber = (() => {
return ''; return '';
})(); })();
function patchUpLanguageArg(languages: string[] | undefined): string[] | null { const appArgs: AppArguments = {
if (!languages) return null; rootDir: opts.rootDir,
if (languages.length === 1) { env: opts.env,
// Support old style comma-separated language args.
return languages[0].split(',');
}
return languages;
}
// Set default values for omitted arguments
const defArgs: AppArguments = {
rootDir: opts.rootDir || './etc',
env: opts.env || ['dev'],
hostname: opts.host, hostname: opts.host,
port: opts.port || 10240, port: opts.port,
gitReleaseName: gitReleaseName, gitReleaseName: gitReleaseName,
releaseBuildNumber: releaseBuildNumber, releaseBuildNumber: releaseBuildNumber,
wantedLanguages: patchUpLanguageArg(opts.language), wantedLanguages: opts.language,
doCache: !opts.noCache, doCache: opts.cache,
fetchCompilersFromRemote: !opts.noRemoteFetch, fetchCompilersFromRemote: opts.remoteFetch,
ensureNoCompilerClash: opts.ensureNoIdClash, ensureNoCompilerClash: opts.ensureNoIdClash,
suppressConsoleLog: opts.suppressConsoleLog || false, suppressConsoleLog: opts.suppressConsoleLog,
}; };
if (opts.logHost && opts.logPort) { if (opts.logHost && opts.logPort) {
logToPapertrail(opts.logHost, opts.logPort, defArgs.env.join('.'), opts.hostnameForLogging); logToPapertrail(opts.logHost, opts.logPort, appArgs.env.join('.'), opts.hostnameForLogging);
} }
if (opts.loki) { if (opts.loki) {
logToLoki(opts.loki); logToLoki(opts.loki);
} }
if (defArgs.suppressConsoleLog) { if (appArgs.suppressConsoleLog) {
logger.info('Disabling further console logging'); logger.info('Disabling further console logging');
suppressConsoleLog(); suppressConsoleLog();
} }
@@ -276,12 +266,12 @@ function getFaviconFilename() {
const propHierarchy = [ const propHierarchy = [
'defaults', 'defaults',
defArgs.env, appArgs.env,
defArgs.env.map(e => `${e}.${process.platform}`), appArgs.env.map(e => `${e}.${process.platform}`),
process.platform, process.platform,
os.hostname(), os.hostname(),
].flat(); ].flat();
if (!opts.noLocal) { if (opts.local) {
propHierarchy.push('local'); propHierarchy.push('local');
} }
logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`); logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`);
@@ -290,20 +280,20 @@ logger.info(`properties hierarchy: ${propHierarchy.join(', ')}`);
if (opts.propDebug) props.setDebug(true); if (opts.propDebug) props.setDebug(true);
// *All* files in config dir are parsed // *All* files in config dir are parsed
const configDir = path.join(defArgs.rootDir, 'config'); const configDir = path.join(appArgs.rootDir, 'config');
props.initialize(configDir, propHierarchy); props.initialize(configDir, propHierarchy);
// Instantiate a function to access records concerning "compiler-explorer" // Instantiate a function to access records concerning "compiler-explorer"
// in hidden object props.properties // in hidden object props.properties
const ceProps = props.propsFor('compiler-explorer'); const ceProps = props.propsFor('compiler-explorer');
const restrictToLanguages = ceProps<string>('restrictToLanguages'); const restrictToLanguages = ceProps<string>('restrictToLanguages');
if (restrictToLanguages) { if (restrictToLanguages) {
defArgs.wantedLanguages = restrictToLanguages.split(','); appArgs.wantedLanguages = restrictToLanguages.split(',');
} }
const languages = (() => { const languages = (() => {
if (defArgs.wantedLanguages) { if (appArgs.wantedLanguages) {
const filteredLangs: Partial<Record<LanguageKey, Language>> = {}; const filteredLangs: Partial<Record<LanguageKey, Language>> = {};
for (const wantedLang of defArgs.wantedLanguages) { for (const wantedLang of appArgs.wantedLanguages) {
for (const lang of Object.values(allLanguages)) { for (const lang of Object.values(allLanguages)) {
if (lang.id === wantedLang || lang.name === wantedLang || lang.alias.includes(wantedLang)) { if (lang.id === wantedLang || lang.name === wantedLang || lang.alias.includes(wantedLang)) {
filteredLangs[lang.id] = lang; filteredLangs[lang.id] = lang;
@@ -459,8 +449,7 @@ function oldGoogleUrlHandler(req: express.Request, res: express.Response, next:
} }
function startListening(server: express.Express) { function startListening(server: express.Express) {
const ss = systemdSocket(); const ss: {fd: number} | null = systemdSocket(); // TODO: I'm not sure this works any more
let _port;
if (ss) { if (ss) {
// ms (5 min default) // ms (5 min default)
const idleTimeout = process.env.IDLE_TIMEOUT; const idleTimeout = process.env.IDLE_TIMEOUT;
@@ -478,9 +467,15 @@ function startListening(server: express.Express) {
server.all('*', reset); server.all('*', reset);
logger.info(` IDLE_TIMEOUT: ${idleTimeout}`); logger.info(` IDLE_TIMEOUT: ${idleTimeout}`);
} }
_port = ss; logger.info(` Listening on systemd socket: ${JSON.stringify(ss)}`);
server.listen(ss);
} else { } else {
_port = defArgs.port; logger.info(` Listening on http://${appArgs.hostname || 'localhost'}:${appArgs.port}/`);
if (appArgs.hostname) {
server.listen(appArgs.port, appArgs.hostname);
} else {
server.listen(appArgs.port);
}
} }
const startupGauge = new PromClient.Gauge({ const startupGauge = new PromClient.Gauge({
@@ -489,24 +484,8 @@ function startListening(server: express.Express) {
}); });
startupGauge.set(process.uptime()); startupGauge.set(process.uptime());
const startupDurationMs = Math.floor(process.uptime() * 1000); const startupDurationMs = Math.floor(process.uptime() * 1000);
if (Number.isNaN(Number.parseInt(_port))) { logger.info(` Startup duration: ${startupDurationMs}ms`);
// unix socket, not a port number... logger.info('=======================================');
logger.info(` Listening on socket: //${_port}/`);
logger.info(` Startup duration: ${startupDurationMs}ms`);
logger.info('=======================================');
server.listen(_port);
} else {
// normal port number
logger.info(` Listening on http://${defArgs.hostname || 'localhost'}:${_port}/`);
logger.info(` Startup duration: ${startupDurationMs}ms`);
logger.info('=======================================');
// silly express typing, passing undefined is fine but
if (defArgs.hostname) {
server.listen(_port, defArgs.hostname);
} else {
server.listen(_port);
}
}
} }
const awsProps = props.propsFor('aws'); const awsProps = props.propsFor('aws');
@@ -514,31 +493,31 @@ const awsProps = props.propsFor('aws');
// eslint-disable-next-line max-statements // eslint-disable-next-line max-statements
async function main() { async function main() {
await aws.initConfig(awsProps); await aws.initConfig(awsProps);
SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, defArgs); SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, appArgs);
const webServer = express(); const webServer = express();
const router = express.Router(); const router = express.Router();
startWineInit(); startWineInit();
RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, defArgs.env); RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, appArgs.env);
const formattingService = new FormattingService(); const formattingService = new FormattingService();
await formattingService.initialize(ceProps); await formattingService.initialize(ceProps);
const clientOptionsHandler = new ClientOptionsHandler(sources, compilerProps, defArgs); const clientOptionsHandler = new ClientOptionsHandler(sources, compilerProps, appArgs);
const compilationQueue = CompilationQueue.fromProps(compilerProps.ceProps); const compilationQueue = CompilationQueue.fromProps(compilerProps.ceProps);
const compilationEnvironment = new CompilationEnvironment( const compilationEnvironment = new CompilationEnvironment(
compilerProps, compilerProps,
awsProps, awsProps,
compilationQueue, compilationQueue,
formattingService, formattingService,
defArgs.doCache, appArgs.doCache,
); );
const compileHandler = new CompileHandler(compilationEnvironment, awsProps); const compileHandler = new CompileHandler(compilationEnvironment, awsProps);
compilationEnvironment.setCompilerFinder(compileHandler.findCompiler.bind(compileHandler)); compilationEnvironment.setCompilerFinder(compileHandler.findCompiler.bind(compileHandler));
const storageType = getStorageTypeByKey(storageSolution); const storageType = getStorageTypeByKey(storageSolution);
const storageHandler = new storageType(httpRoot, compilerProps, awsProps); const storageHandler = new storageType(httpRoot, compilerProps, awsProps);
const compilerFinder = new CompilerFinder(compileHandler, compilerProps, defArgs, clientOptionsHandler); const compilerFinder = new CompilerFinder(compileHandler, compilerProps, appArgs, clientOptionsHandler);
const isExecutionWorker = ceProps<boolean>('execqueue.is_worker', false); const isExecutionWorker = ceProps<boolean>('execqueue.is_worker', false);
const healthCheckFilePath = ceProps('healthCheckFilePath', null) as string | null; const healthCheckFilePath = ceProps('healthCheckFilePath', null) as string | null;
@@ -576,7 +555,7 @@ async function main() {
if (!isExecutionWorker && initialCompilers.length === 0) { if (!isExecutionWorker && initialCompilers.length === 0) {
throw new Error('Unexpected failure, no compilers found!'); throw new Error('Unexpected failure, no compilers found!');
} }
if (defArgs.ensureNoCompilerClash) { if (appArgs.ensureNoCompilerClash) {
logger.warn('Ensuring no compiler ids clash'); logger.warn('Ensuring no compiler ids clash');
if (initialFindResults.foundClash) { if (initialFindResults.foundClash) {
// If we are forced to have no clashes, throw an error with some explanation // If we are forced to have no clashes, throw an error with some explanation
@@ -586,7 +565,7 @@ async function main() {
} }
} }
if (opts.discoveryonly) { if (opts.discoveryOnly) {
for (const compiler of initialCompilers) { for (const compiler of initialCompilers) {
if (compiler.buildenvsetup && compiler.buildenvsetup.id === '') delete compiler.buildenvsetup; if (compiler.buildenvsetup && compiler.buildenvsetup.id === '') delete compiler.buildenvsetup;
@@ -597,8 +576,8 @@ async function main() {
compiler.cachedPossibleArguments = compilerInstance.possibleArguments.possibleArguments; compiler.cachedPossibleArguments = compilerInstance.possibleArguments.possibleArguments;
} }
} }
await fs.writeFile(opts.discoveryonly, JSON.stringify(initialCompilers)); await fs.writeFile(opts.discoveryOnly, JSON.stringify(initialCompilers));
logger.info(`Discovered compilers saved to ${opts.discoveryonly}`); logger.info(`Discovered compilers saved to ${opts.discoveryOnly}`);
process.exit(0); process.exit(0);
} }
@@ -607,7 +586,7 @@ async function main() {
clientOptionsHandler, clientOptionsHandler,
renderConfig, renderConfig,
storageHandler, storageHandler,
defArgs.wantedLanguages?.[0], appArgs.wantedLanguages?.[0],
); );
const routeApi = new RouteAPI(router, { const routeApi = new RouteAPI(router, {
compileHandler, compileHandler,
@@ -615,7 +594,7 @@ async function main() {
storageHandler, storageHandler,
compilationEnvironment, compilationEnvironment,
ceProps, ceProps,
defArgs, defArgs: appArgs,
renderConfig, renderConfig,
renderGoldenLayout, renderGoldenLayout,
}); });
@@ -649,7 +628,7 @@ async function main() {
if (opts.metricsPort) { if (opts.metricsPort) {
logger.info(`Running metrics server on port ${opts.metricsPort}`); logger.info(`Running metrics server on port ${opts.metricsPort}`);
setupMetricsServer(opts.metricsPort, defArgs.hostname); setupMetricsServer(opts.metricsPort, appArgs.hostname);
} }
webServer webServer
@@ -851,7 +830,7 @@ async function main() {
noscriptHandler.initializeRoutes(); noscriptHandler.initializeRoutes();
routeApi.initializeRoutes(); routeApi.initializeRoutes();
if (!defArgs.doCache) { if (!appArgs.doCache) {
logger.info(' with disabled caching'); logger.info(' with disabled caching');
} }
setupEventLoopLagLogging(); setupEventLoopLagLogging();

View File

@@ -22,7 +22,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. // POSSIBILITY OF SUCH DAMAGE.
import nopt from 'nopt'; import {Command} from 'commander';
import _ from 'underscore'; import _ from 'underscore';
import {CompilerArguments} from './lib/compiler-arguments.js'; import {CompilerArguments} from './lib/compiler-arguments.js';
@@ -30,12 +30,20 @@ import * as Parsers from './lib/compilers/argument-parsers.js';
import {executeDirect} from './lib/exec.js'; import {executeDirect} from './lib/exec.js';
import {logger} from './lib/logger.js'; import {logger} from './lib/logger.js';
const opts = nopt({ const program = new Command();
parser: [String], program
exe: [String], .name('compiler-args-app.ts')
padding: [Number], .usage('--parser=<compilertype> --exe=<path> [--padding=<number>]')
debug: [Boolean], .description(
}); 'Extracts compiler arguments\nFor example: node --no-warnings=ExperimentalWarning --import=tsx compiler-args-app.ts --parser=clang --exe=/opt/compiler-explorer/clang-15.0.0/bin/clang++ --padding=50',
)
.requiredOption('--parser <type>', 'Compiler parser type')
.requiredOption('--exe <path>', 'Path to compiler executable')
.option('--padding <number>', 'Padding for output formatting', '40')
.option('--debug', 'Enable debug output');
program.parse();
const opts = program.opts();
if (opts.debug) logger.level = 'debug'; if (opts.debug) logger.level = 'debug';
@@ -73,7 +81,7 @@ class CompilerArgsApp {
constructor() { constructor() {
this.parserName = opts.parser; this.parserName = opts.parser;
this.executable = opts.exe; this.executable = opts.exe;
this.pad = opts.padding || 40; this.pad = Number.parseInt(opts.padding, 10);
this.compiler = { this.compiler = {
compiler: { compiler: {
exe: this.executable, exe: this.executable,
@@ -145,17 +153,7 @@ class CompilerArgsApp {
} }
} }
if (!opts.parser || !opts.exe) { const app = new CompilerArgsApp();
console.error( app.doTheParsing()
'Usage: ' + .then(() => app.print())
'node --no-warnings=ExperimentalWarning --import=tsx compiler-args-app.ts ' + .catch(e => console.error(e));
'--parser=<compilertype> --exe=<path> [--padding=<number>]\n' +
'for example: --parser=clang --exe=/opt/compiler-explorer/clang-15.0.0/bin/clang++ --padding=50',
);
process.exit(1);
} else {
const app = new CompilerArgsApp();
app.doTheParsing()
.then(() => app.print())
.catch(e => console.error(e));
}

View File

@@ -223,7 +223,7 @@ Note that path-style properties often support variable substitution as shown abo
### Property Debugging ### Property Debugging
You can enable detailed debugging of property resolution by using the `--propDebug` flag when starting Compiler You can enable detailed debugging of property resolution by using the `--prop-debug` flag when starting Compiler
Explorer. This shows every property lookup, including where properties are being overridden and which configuration Explorer. This shows every property lookup, including where properties are being overridden and which configuration
source they come from. source they come from.
@@ -257,7 +257,7 @@ The configuration system is implemented primarily in the following files:
If you need to troubleshoot configuration issues, you can run Compiler Explorer with debug output: If you need to troubleshoot configuration issues, you can run Compiler Explorer with debug output:
``` ```
make EXTRA_ARGS='--propDebug' dev make EXTRA_ARGS='--prop-debug' dev
``` ```
This will show detailed logs about property resolution, including which properties are being overridden and from which This will show detailed logs about property resolution, including which properties are being overridden and from which

View File

@@ -4,7 +4,7 @@ Our frontend testing is done with cypress.
To run the tests locally: To run the tests locally:
- start a server with `npm run dev -- --language c++ --noLocal` - this configuration ensures your setup is clean of any - start a server with `npm run dev -- --language c++ --no-local` - this configuration ensures your setup is clean of any
local properties. local properties.
- in another terminal run `npx cypress open`, then choose "end to end" and then you should be able to run tests - in another terminal run `npx cypress open`, then choose "end to end" and then you should be able to run tests
interactively. interactively.

View File

@@ -29,7 +29,7 @@ export type AppArguments = {
port: number; port: number;
gitReleaseName: string; gitReleaseName: string;
releaseBuildNumber: string; releaseBuildNumber: string;
wantedLanguages: string[] | null; wantedLanguages: string[] | undefined;
doCache: boolean; doCache: boolean;
fetchCompilersFromRemote: boolean; fetchCompilersFromRemote: boolean;
ensureNoCompilerClash: boolean | undefined; ensureNoCompilerClash: boolean | undefined;

63
package-lock.json generated
View File

@@ -27,6 +27,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chart.js": "^4.4.9", "chart.js": "^4.4.9",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"commander": "^13.1.0",
"compression": "^1.8.0", "compression": "^1.8.0",
"copy-webpack-plugin": "^13.0.0", "copy-webpack-plugin": "^13.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
@@ -46,7 +47,6 @@
"monaco-vim": "^0.4.2", "monaco-vim": "^0.4.2",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"node-targz": "^0.2.0", "node-targz": "^0.2.0",
"nopt": "^8.1.0",
"p-queue": "^8.1.0", "p-queue": "^8.1.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"profanities": "^3.0.1", "profanities": "^3.0.1",
@@ -87,7 +87,6 @@
"@types/jquery": "^3.5.32", "@types/jquery": "^3.5.32",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/node-targz": "^0.2.4", "@types/node-targz": "^0.2.4",
"@types/nopt": "^3.0.32",
"@types/request": "^2.48.12", "@types/request": "^2.48.12",
"@types/response-time": "^2.3.8", "@types/response-time": "^2.3.8",
"@types/serve-favicon": "^2.5.7", "@types/serve-favicon": "^2.5.7",
@@ -5233,13 +5232,6 @@
"@types/tar-fs": "*" "@types/tar-fs": "*"
} }
}, },
"node_modules/@types/nopt": {
"version": "3.0.32",
"resolved": "https://registry.npmjs.org/@types/nopt/-/nopt-3.0.32.tgz",
"integrity": "sha512-UP8QR0GaR8AE3l4wDmyCx4lEkX5o/1YVeDBqb1UqmfHefZqFNedQLTsobfzw56CvlXVVbt6kAwJJbN1yDTp16Q==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/pg": { "node_modules/@types/pg": {
"version": "8.6.1", "version": "8.6.1",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz",
@@ -5843,15 +5835,6 @@
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/abbrev": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
"integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==",
"license": "ISC",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/accepts": { "node_modules/accepts": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@@ -6943,13 +6926,12 @@
} }
}, },
"node_modules/commander": { "node_modules/commander": {
"version": "6.2.1", "version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 6" "node": ">=18"
} }
}, },
"node_modules/common-tags": { "node_modules/common-tags": {
@@ -7534,6 +7516,16 @@
"ieee754": "^1.1.13" "ieee754": "^1.1.13"
} }
}, },
"node_modules/cypress/node_modules/commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/dashdash": { "node_modules/dashdash": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -9864,16 +9856,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/lint-staged/node_modules/commander": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/lint-staged/node_modules/emoji-regex": { "node_modules/lint-staged/node_modules/emoji-regex": {
"version": "10.4.0", "version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
@@ -10899,21 +10881,6 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/nopt": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
"integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
"license": "ISC",
"dependencies": {
"abbrev": "^3.0.0"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",

View File

@@ -36,6 +36,7 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chart.js": "^4.4.9", "chart.js": "^4.4.9",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"commander": "^13.1.0",
"compression": "^1.8.0", "compression": "^1.8.0",
"copy-webpack-plugin": "^13.0.0", "copy-webpack-plugin": "^13.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
@@ -55,7 +56,6 @@
"monaco-vim": "^0.4.2", "monaco-vim": "^0.4.2",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"node-targz": "^0.2.0", "node-targz": "^0.2.0",
"nopt": "^8.1.0",
"p-queue": "^8.1.0", "p-queue": "^8.1.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"profanities": "^3.0.1", "profanities": "^3.0.1",
@@ -96,7 +96,6 @@
"@types/jquery": "^3.5.32", "@types/jquery": "^3.5.32",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/node-targz": "^0.2.4", "@types/node-targz": "^0.2.4",
"@types/nopt": "^3.0.32",
"@types/request": "^2.48.12", "@types/request": "^2.48.12",
"@types/response-time": "^2.3.8", "@types/response-time": "^2.3.8",
"@types/serve-favicon": "^2.5.7", "@types/serve-favicon": "^2.5.7",