StyleForces

This commit is contained in:
Vladimir (unknowableshade) Eremin committed 2023-07-10 12:59:58 +03:00
1 parent fb1367284a
commit 33b9bc19a9
15 files changed
+5650 -100

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"warnOnUnsupportedTypeScriptVersion": false,
"sourceType": "module"
},
"env": {
"browser": false,
"node": true,
"es6": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"plugins": ["@typescript-eslint", "import", "simple-import-sort"],
"ignorePatterns": ["**/node_modules/**", "/dist/**", "/tests/**"],
"rules": {
"curly": ["error", "all"],
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}
+70 -9
View File
@@ -1,9 +1,70 @@
/cf-log-parser-linux
/cf-log-parser-macos
/cf-log-parser-win.exe
/dist
/log.txt
/name.txt
/node_modules
/output.json
/package-lock.json
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Binaries
bin/
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
dist/
# Python Virtual Environment
.venv
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# VSCode
.vscode-test
.vscode
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# Artifacts
data
+5
View File
@@ -0,0 +1,5 @@
# Node.js Tools
node_modules
# Typescript compiller artifacts
dist/
+23
View File
@@ -0,0 +1,23 @@
{
"semi": true,
"trailingComma": "none",
"singleQuote": false,
"printWidth": 100,
"arrowParens": "always",
"bracketSpacing": true,
"endOfLine": "crlf",
"overrides": [
{
"files": ["**/*.json, **/*.yml"],
"options": {
"tabWidth": 2
}
},
{
"files": ["**/*.ts"],
"options": {
"tabWidth": 4
}
}
]
}
+4783
View File
File diff suppressed because it is too large. Load diff
+44 -9
View File
@@ -1,17 +1,52 @@
{
"name": "cf-log-parser",
"name": "styleforces",
"version": "1.0.0",
"description": "",
"description": "Various tooling for codeforces interaction.",
"type": "module",
"main": "./dist/index.js",
"bin": "./dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start": "node ./dist/index.js",
"build": "npm exec tsc --build",
"clean": "npm exec tsc --build --clean",
"bootstrap": "npm run build && npm run start",
"lint": "npm exec eslint . && npm exec prettier --check .",
"format": "npm exec eslint --fix . && npm exec prettier --write . > /dev/null"
},
"license": "MIT",
"keywords": [
"codeforces",
"toolkit"
],
"repository": {
"type": "git",
"url": "git+https://github.com/unknowableshade/StyleForces.git"
},
"author": {
"name": "unknowableshade",
"email": "60275123+unknowableshade@users.noreply.github.com",
"url": "https://ermnvldmr.com"
},
"bugs": {
"url": "https://github.com/unknowableshade/StyleForces/issues"
},
"readme": "https://github.com/unknowableshade/StyleForces#readme",
"engines": {
"node": "18.x.x",
"npm": "*"
},
"devDependencies": {
"@types/cheerio": "^0.22.31",
"@types/node": "^20.3.3",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-simple-import-sort": "^10.0.0",
"prettier": "^3.0.0",
"typescript": "^5.1.6"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/node": "^18.0.6",
"pkg": "^5.8.0",
"typescript": "^4.7.4"
"cheerio": "^1.0.0-rc.12"
}
}
+104
View File
@@ -0,0 +1,104 @@
import * as cheerio from "cheerio";
import { execFile as execFileCallback } from "child_process";
import { readFile, writeFile } from "fs/promises";
import path from "path";
import { parseArgs, promisify } from "util";
import { ExtendedSubmission, isErrnoException, isExecFileError } from "../lib/types.js";
const execFile = promisify(execFileCallback);
export const HELP = `
Usage: ... copyDetect [options...]
Options:
-d <STRING> : Path to the directory with submissions.
-l <STRING> : Language tokenize during copydetection.
-o <STRING> : Path to the resulted report. (default: './result.html')
Example: ... copyDetect -d ./data -l cpp -o ./result.html
`;
function error(msg: string) {
console.log(msg);
console.log("Use -h: to get usage help.");
}
export async function execute() {
const {
values: { dataDir, lang, outFile }
} = parseArgs({
options: {
dataDir: {
type: "string",
short: "d",
default: "./result"
},
lang: {
type: "string",
short: "l",
default: "cpp"
},
outFile: {
type: "string",
short: "o",
default: "./result.html"
}
},
args: process.argv.slice(3)
});
if (!dataDir || !lang || !outFile) {
error("Arguments don't seem to be correct.");
return;
}
try {
await execFile("copydetect", ["-t", dataDir, "-e", "src", "-o", lang, "-O", outFile, "-a"]);
} catch (err) {
if (isErrnoException(err)) {
error("copydetect cannot be spawned. Check your environment.");
return;
}
if (isExecFileError(err)) {
error(`copydetect binary said: ${err.stderr}`);
return;
}
}
const $ = cheerio.load(await readFile(outFile));
$(`<h6 style="text-align: center;">Generated on: ${new Date().toString()}</h6>`).insertAfter(
"div.container h1"
);
for (const p of $("tbody.table-light tr td p")) {
const first = $(p).children("i")[0];
const second = $(p).children("i")[1];
const firstPath = path.parse($(first).text());
const secondPath = path.parse($(second).text());
const firstData = JSON.parse(
(await readFile(path.join(firstPath.dir, `${firstPath.name}.json`))).toString()
) as ExtendedSubmission;
const secondData = JSON.parse(
(await readFile(path.join(secondPath.dir, `${secondPath.name}.json`))).toString()
) as ExtendedSubmission;
$(p).prepend(
`<b>${firstData.author.members[0].handle} - ${secondData.author.members[0].handle}</b><br>`
);
$(first).replaceWith(`<a href="${firstData.url}">${firstData.id}</a>`);
$(second).replaceWith(`<a href="${secondData.url}">${secondData.id}</a>`);
}
try {
await writeFile(outFile, $.html());
console.log("✓ Successfully generated report file.");
console.log(`➜ ${outFile}`);
} catch {
console.log("Cannot make report file.");
}
}
+136
View File
@@ -0,0 +1,136 @@
import { mkdir, readFile, writeFile } from "fs/promises";
import path from "path";
import { parseArgs } from "util";
import * as codeforces from "../lib/codeforces.js";
import Submission from "../lib/submission.js";
import { BaseProblem, isErrnoException } from "../lib/types.js";
type SubmissionIndex = {
[handle: string]: BaseProblem[];
};
export const HELP = `
Usage: ... fetchOk [options...]
Options:
-i (STRING) : Contest ID.
-g <STRING> : Group ID (if in group).
-c <INTEGER> : Positive amount of "OK" submissions to fetch. (default: 100)
-l <INTEGER> : Positive amouut of submissions to lookup. (default: 200)
-a <INTEGER> : Positive amount of submissions to skip. (default: 1)
-o <STRING> : Path to the directory to write submissions to. (default: './result')
Example: ... fetchOk -i someId -g anotherId -c 50 -l 100 -a 10 -o './result'
`;
function error(msg: string) {
console.log(msg);
console.log("Use -h: to get usage help.");
}
export async function execute() {
const {
values: { contestId, groupId, countArg, lookupArg, afterArg, outDir }
} = parseArgs({
options: {
contestId: {
type: "string",
short: "i"
},
groupId: {
type: "string",
short: "g"
},
countArg: {
type: "string",
short: "c"
},
lookupArg: {
type: "string",
short: "l"
},
afterArg: {
type: "string",
short: "a"
},
outDir: {
type: "string",
short: "o",
default: "./output"
}
},
args: process.argv.slice(3)
});
const count = countArg && /^(0|[1-9]\d*)$/.test(countArg) ? parseInt(countArg) : 100;
const lookup = lookupArg && /^(0|[1-9]\d*)$/.test(lookupArg) ? parseInt(lookupArg) : 200;
const after = afterArg && /^(0|[1-9]\d*)$/.test(afterArg) ? parseInt(afterArg) : 1;
if (!contestId || !outDir) {
error("Arguments don't seem to be correct.");
return;
}
try {
await mkdir(outDir, { recursive: true });
} catch {
error("Out directory cannot be made.");
return;
}
const indexPath = path.join(outDir, "index.json");
let index: SubmissionIndex;
try {
index = JSON.parse((await readFile(indexPath)).toString()) as SubmissionIndex;
} catch {
index = {};
}
const status = (await codeforces.methods.contestStatus(contestId, after, lookup))
.filter((submission) => submission.verdict === "OK")
.slice(0, count);
for (const submission of status) {
if (!Object.hasOwn(index, submission.author.members[0].handle)) {
index[submission.author.members[0].handle] = [];
}
if (
index[submission.author.members[0].handle].find(
(problem) =>
problem.contestId === submission.contestId &&
problem.name === submission.problem.name
)
) {
continue;
}
try {
await Submission.fetch(submission, groupId).then((res) => res.save(outDir));
} catch (err) {
if (isErrnoException(error)) {
error(`Cannot write submission "${submission.id}".`);
return;
}
if (err instanceof Error) {
error(err.message);
return;
}
}
index[submission.author.members[0].handle].push(submission.problem);
}
console.log("✓ Successfully fetched submissions.");
console.log(`➜ ${outDir}`);
try {
await writeFile(indexPath, JSON.stringify(index));
console.log("✓ Index captured.");
} catch {
error("Index haven't been saved! Next run will overwrite submissions.");
return;
}
}
+139
View File
@@ -0,0 +1,139 @@
import { readFile, writeFile } from "fs/promises";
import { parseArgs } from "util";
interface Run {
contestant: string;
problemLetter: string;
timeMinutesFromStart: number;
success: boolean;
}
interface Output {
contestName: string;
freezeTimeMinutesFromStart: number;
problemLetters: string[];
contestants: string[];
runs: Run[];
}
export const HELP = `
Usage: ... logSerializer [options...]
Options:
-f (INTEGER) : Freeze time counting from start in minutes.
-l (STRING) : Path to the contest log file.
-d (STRING) : Path to the domain's users file.
-o <STRING> : Path to the resulted serialization. (default: './result.json')
Example: ... logSerializer -f 120 -l ./log.txt -d ./domain.txt -o ./result.json
`;
function error(msg: string) {
console.log(msg);
console.log("Use -h: to get usage help.");
}
export async function execute() {
const {
values: { freezeTime, logFile, domainFile, outFile }
} = parseArgs({
options: {
freezeTime: {
type: "string",
short: "f"
},
logFile: {
type: "string",
short: "l"
},
domainFile: {
type: "string",
short: "d"
},
outFile: {
type: "string",
short: "o",
default: "./result.json"
}
},
args: process.argv.slice(3)
});
if (!freezeTime || !logFile || !domainFile || !outFile) {
error("Arguments don't seem to be correct.");
return;
}
if (!/^(0|[1-9]\d*)$/.test(freezeTime)) {
error("Freezetime doesn't seem to be correct.");
return;
}
let log: string[];
let domain: string[];
try {
log = (await readFile(logFile, "utf-8")).trim().split("\n");
domain = (await readFile(domainFile, "utf-8")).trim().split("\n");
} catch {
error("Log/domain file is unreachable.");
return;
}
const names: Record<string, string> = {};
for (const user of domain) {
const values = user.split(" | ").map((value) => value.trim());
names[values[1]] = values[3];
}
const output: Output = {
contestName: "",
freezeTimeMinutesFromStart: parseInt(freezeTime) || 0,
problemLetters: [],
contestants: [],
runs: []
};
for (const entry of log) {
const cmd = entry.slice(0, entry.indexOf(" ")).trim();
const csv = entry.slice(entry.indexOf(" ") + 1).trim();
switch (cmd) {
case "@contest": {
output.contestName = csv.replace(/"/g, "");
break;
}
case "@p": {
const values = csv.split(",");
output.problemLetters.push(values[0]);
break;
}
case "@t": {
const values = csv.split(",");
output.contestants.push(names[values[3].split("=")[1]]);
break;
}
case "@s": {
const values = csv.split(",");
const run: Run = {
contestant: output.contestants[parseInt(values[0]) - 1],
problemLetter: values[1],
timeMinutesFromStart: Math.floor(parseInt(values[3]) / 60),
success: values[4] === "OK"
};
output.runs.push(run);
break;
}
}
}
try {
await writeFile(outFile, JSON.stringify(output));
console.log("✓ Successfully serialized contest log file.");
console.log(`➜ ${outFile}`);
} catch {
console.log("Cannot write result of serialization.");
}
}
+32
View File
@@ -0,0 +1,32 @@
import path from "path";
import { fileURLToPath } from "url";
const ROOT = path.dirname(fileURLToPath(import.meta.url));
const config = {
cfUrl: "https://codeforces.com",
cfEndpoint: "https://codeforces.com/api",
cfKey: process.env.CF_KEY,
cfSecret: process.env.CF_SECRET,
distDir: path.join(ROOT, "../data/"),
headers: {
Host: "codeforces.com",
Pragma: "no-cache",
"Cache-Control": "no-cache",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '""',
"Upgrade-Insecure-Requests": "1",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36",
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
Cookie: process.env.CF_COOKIE ?? ""
}
};
export default config;
+33 -79
View File
@@ -1,90 +1,44 @@
import { existsSync, readFileSync, writeFileSync } from "fs";
import * as copyDetect from "./command/copyDetect.js";
import * as fetchOk from "./command/fetchOk.js";
import * as logSerializer from "./command/logSerializer.js";
interface Run {
contestant: string;
problemLetter: string;
timeMinutesFromStart: number;
success: boolean;
}
const HELP = `
Usage: ... (command) [arguments...]
Commands:
- logSerializer : Convert contest log to JSON with freeze-time.
- fetchOk : Fetch every "OK" submission from contest.
- copyDetect : Compare submissions and generate copy report of them. (requires copydetect)
Environment:
CF_KEY : Codeforces API Key.
CF_SECRET : Codeforces API Secret.
CF_COOKIE : Cookies extracted from your session.
`;
interface Output {
contestName: string;
freezeTimeMinutesFromStart: number;
problemLetters: string[];
contestants: string[];
runs: Run[];
}
const help = !!process.argv.find((arg) => arg === "-h");
const pathToLog = process.argv[3];
const pathToUser = process.argv[4];
const freezeTime = process.argv[2];
console.log(pathToLog, pathToUser);
if (!existsSync(pathToLog) || !existsSync(pathToUser)) {
console.log("Cannot find path specified.")
}
const logs = readFileSync(pathToLog, "utf-8").trim().split("\n");
const users = readFileSync(pathToUser, "utf-8").trim().split("\n");
const names: Record<string, string> = {};
for (const user of users) {
const values = user.split(" | ").map(value => value.trim());
names[values[1]] = values[3];
}
const output: Output = {
contestName: "",
freezeTimeMinutesFromStart: parseInt(freezeTime) || 0,
problemLetters: [],
contestants: [],
runs: []
};
for (const log of logs) {
const cmd = log.slice(0, log.indexOf(" ")).trim();
const csv = log.slice(log.indexOf(" ") + 1).trim();
switch (cmd) {
case "@contest": {
output.contestName = csv.replace(/"/g, "");
switch (process.argv[2]) {
case "logSerializer":
if (help) {
console.log(logSerializer.HELP);
break;
}
case "@p": {
const values = csv.split(",");
output.problemLetters.push(values[0]);
logSerializer.execute();
break;
case "fetchOk":
if (help) {
console.log(fetchOk.HELP);
break;
}
case "@t": {
const values = csv.split(",");
output.contestants.push(names[values[3].split("=")[1]]);
fetchOk.execute();
break;
case "copyDetect":
if (help) {
console.log(copyDetect.HELP);
break;
}
case "@s": {
const values = csv.split(",");
const run: Run = {
contestant: output.contestants[parseInt(values[0]) - 1],
problemLetter: values[1],
timeMinutesFromStart: Math.floor(parseInt(values[3]) / 60),
success: values[4] === "OK"
}
output.runs.push(run);
copyDetect.execute();
break;
default:
console.log(HELP);
break;
}
}
}
try {
writeFileSync("output.json", JSON.stringify(output));
console.log("✓ Successfully converted contest log file.");
console.log("➜ output.json");
}
catch {
console.log("Cannot write to file: output.json");
}
+56
View File
@@ -0,0 +1,56 @@
import { createHash, randomBytes } from "crypto";
import config from "../config.js";
import { BaseSubmission } from "./types.js";
function hashedQuery(method: string, queries: [string, string][]): string {
const query =
"?" +
[
["apiKey", config.cfKey],
["time", (Date.now() / 1000).toFixed(0)]
]
.concat(queries)
.sort()
.map((pair) => pair.join("="))
.join("&");
const rand = randomBytes(3).toString("hex");
const sig =
rand +
createHash("sha512").update(`${rand}${method}${query}#${config.cfSecret}`).digest("hex");
return `${query}&apiSig=${sig}`;
}
export class CfApiError implements Error {
name = "CfApiError";
message: string;
constructor(message: string) {
this.message = message;
}
}
export const methods = {
contestStatus: async (contestId: string, from = 1, count = 10): Promise<BaseSubmission[]> => {
const method = "/contest.status";
const query = hashedQuery(method, [
["contestId", contestId],
["from", from.toString()],
["count", count.toString()]
]);
const url = config.cfEndpoint + method + query;
const data = await fetch(url).then((res) => res.json());
if (data.status !== "OK") {
throw new CfApiError(data.reason);
}
return data.result;
}
};
+65
View File
@@ -0,0 +1,65 @@
import * as cheerio from "cheerio";
import { mkdir, writeFile } from "fs/promises";
import path from "path";
import config from "../config.js";
import { BaseSubmission, ExtendedSubmission } from "./types.js";
function submissionUrl(id: string, contestId?: string, groupId?: string) {
const groupPath = groupId ? "/group/" + groupId : "";
const contestPath = contestId ? "/contest/" + contestId : "";
const submissionPath = "/submission/" + id;
return config.cfUrl + groupPath + contestPath + submissionPath;
}
export default class Submission {
public readonly data: ExtendedSubmission;
constructor(submission: ExtendedSubmission) {
this.data = submission;
}
public async ignore(): Promise<void> {
await fetch(this.data.url, {
headers: config.headers,
body: new URLSearchParams({
csrf_token: this.data.csrf,
action: "ignore",
submissionId: this.data.id.toString(),
submit: "Ignore"
}),
method: "POST"
});
}
public async save(dir: string): Promise<void> {
const dist = path.join(dir, this.data.id.toString());
await mkdir(dist, { recursive: true });
await writeFile(path.join(dist, `${this.data.id}.json`), JSON.stringify(this.data));
await writeFile(path.join(dist, `${this.data.id}.src`), this.data.source);
}
static async fetch(submission: BaseSubmission, groupId?: string): Promise<Submission> {
const url = submissionUrl(
submission.id.toString(),
submission.contestId?.toString(),
groupId
);
const html = await fetch(url, {
headers: config.headers
}).then((res) => res.text());
const $ = cheerio.load(html);
try {
const source = $("#program-source-text").text();
const csrf = $("form.submission-action-form input[name=csrf_token]").attr().value;
return new Submission({ ...submission, source, csrf, url, groupId });
} catch {
throw new Error("Cannot access source code of the submission.");
}
}
}
+136
View File
@@ -0,0 +1,136 @@
type ArbitraryObject = { [key: string]: unknown };
function isArbitraryObject(potentialObject: unknown): potentialObject is ArbitraryObject {
return !!potentialObject && typeof potentialObject === "object";
}
export type ParticipantType =
| "CONTESTANT"
| "PRACTICE"
| "VIRTUAL"
| "MANAGER"
| "OUT_OF_COMPETITION";
export type ProblemType = "PROGRAMMING" | "QUESTION";
export type VerdictType =
| "FAILED"
| "OK"
| "PARTIAL"
| "COMPILATION_ERROR"
| "RUNTIME_ERROR"
| "WRONG_ANSWER"
| "PRESENTATION_ERROR"
| "TIME_LIMIT_EXCEEDED"
| "MEMORY_LIMIT_EXCEEDED"
| "IDLENESS_LIMIT_EXCEEDED"
| "SECURITY_VIOLATED"
| "CRASHED"
| "INPUT_PREPARATION_CRASHED"
| "CHALLENGED"
| "SKIPPED"
| "TESTING"
| "REJECTED";
export type TestSetType =
| "SAMPLES"
| "PRETESTS"
| "TESTS"
| "CHALLENGES"
| "TESTS1"
| "TESTS2"
| "TESTS3"
| "TESTS4"
| "TESTS5"
| "TESTS6"
| "TESTS7"
| "TESTS8"
| "TESTS9"
| "TESTS10";
export interface BaseProblem {
contestId?: number;
problemsetName: string;
index: string;
name: string;
type: ProblemType;
tags: string[];
points?: number;
rating?: number;
}
export interface BaseMember {
handle: string;
name?: string;
}
export interface BaseParty {
contestId?: number;
members: BaseMember[];
participantType: ParticipantType;
ghost: boolean;
startTimeSeconds?: number;
teamId?: number;
teamName?: string;
room?: number;
}
export interface BaseSubmission {
id: number;
contestId?: number;
creationTimeSeconds: number;
relativeTimeSeconds: number;
problem: BaseProblem;
author: BaseParty;
programmingLanguage: string;
verdict?: VerdictType;
testset: TestSetType;
passedTestCount: number;
timeConsumedMillis: number;
memoryConsumedBytes: number;
points?: number;
}
export interface ExtendedSubmission extends BaseSubmission {
source: string;
csrf: string;
url: string;
groupId?: string;
}
export interface ErrnoException extends Error {
errno?: number;
code?: string;
path?: string;
syscall?: string;
}
export function isErrnoException(error: unknown): error is ErrnoException {
return (
isArbitraryObject(error) &&
error instanceof Error &&
(typeof error.errno === "number" || typeof error.errno === "undefined") &&
(typeof error.code === "string" || typeof error.code === "undefined") &&
(typeof error.path === "string" || typeof error.path === "undefined") &&
(typeof error.syscall === "string" || typeof error.syscall === "undefined")
);
}
export interface ExecFileError extends Error {
cmd: string;
code: number;
killed: boolean;
signal: object;
stderr: string;
stdout: string;
}
export function isExecFileError(error: unknown): error is ExecFileError {
return (
isArbitraryObject(error) &&
error instanceof Error &&
typeof error.cwd === "string" &&
typeof error.code === "number" &&
typeof error.killed === "boolean" &&
typeof error.signal === "object" &&
typeof error.stderr === "string" &&
typeof error.stdout === "string"
);
}
+3 -3
View File
@@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
@@ -25,7 +25,7 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs" /* Specify what module code is generated. */,
"module": "ESNext" /* Specify what module code is generated. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
@@ -47,7 +47,7 @@
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
"sourceMap": true /* Create source map files for emitted JavaScript files. */,
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
// "removeComments": true, /* Disable emitting comments. */