From 87357ecb774c9e3ca1b6e2a0d771bd9ece4b9e6c Mon Sep 17 00:00:00 2001 From: ouyangjunyi Date: Wed, 16 Mar 2022 20:11:01 +0800 Subject: [PATCH 1/5] bug-fix: submission api changed --- .eslintrc.js | 46 +- .vscode/launch.json | 65 +-- lib/commands/submission.js | 2 +- lib/helper.js | 272 ++++++------ lib/plugins/leetcode.js | 672 ++++++++++++++++------------- package-lock.json | 838 +++++++++++++++++++++++-------------- package.json | 4 +- 7 files changed, 1105 insertions(+), 794 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 5ef04108..3e00956a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,37 +1,13 @@ module.exports = { - "env": { - "browser": false, - "es6": true, - "mocha": true, - "node": true - }, - "extends": [ - "google", - "eslint:recommended" - ], - "rules": { - "block-spacing": [2, "always"], - "brace-style": [2, "1tbs", { "allowSingleLine": true }], - "camelcase": [2, {properties: "never"}], - "comma-dangle": 0, - "curly": 0, - "key-spacing": [2, {align: "value"}], - "max-len": [1, 120], - "no-control-regex": 0, - "no-console": 1, - "no-empty": [2, { "allowEmptyCatch": true }], - "no-eval": 1, // we use it on purpose - "no-loop-func": 1, - "no-multi-spaces": 0, - "no-proto": 1, - "no-unused-expressions": 1, - "no-unused-vars": 1, - "no-var": 0, - "no-warning-comments": 0, - "prefer-rest-params": 0, - "prefer-spread": 0, - "quote-props": 1, - "quotes": [2, "single", {avoidEscape: true}], - "require-jsdoc": 0, - } + env: { + browser: false, + es6: true, + mocha: true, + node: true, + }, + parserOptions: { + ecmaVersion: 8, + }, + extends: [], + rules: {}, }; diff --git a/.vscode/launch.json b/.vscode/launch.json index c4d2ab92..8f803f95 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,30 +1,37 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch Program", - "program": "${workspaceFolder}/bin/leetcode", - "args": ["show", "1", "--solution"] - }, - { - "type": "node", - "request": "launch", - "name": "Mocha Tests", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "tdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/test/plugins" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceFolder}/bin/leetcode", + "args": ["show", "1", "--solution"] + }, + { + "type": "node", + "request": "launch", + "name": "mine", + "program": "${workspaceFolder}/bin/leetcode", + "args": ["submission", "-l", "C++", "94"] + }, + { + "type": "node", + "request": "launch", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "-u", + "tdd", + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/test/plugins" + ], + "internalConsoleOptions": "openOnSessionStart" + } + ] +} diff --git a/lib/commands/submission.js b/lib/commands/submission.js index 547e3061..2b033f4c 100644 --- a/lib/commands/submission.js +++ b/lib/commands/submission.js @@ -114,7 +114,7 @@ function exportSubmission(problem, argv, cb) { if (e) return cb(e); const opts = { - lang: submission.lang, + lang: submission.lang=='C++'?'cpp':submission.lang, code: submission.code, tpl: argv.extra ? 'detailed' : 'codeonly' }; diff --git a/lib/helper.js b/lib/helper.js index 9c5ff43f..f753db72 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -1,210 +1,242 @@ -'use strict'; -var _ = require('underscore'); -var ora = require('ora'); +"use strict"; +var _ = require("underscore"); +var ora = require("ora"); -var file = require('./file'); +var file = require("./file"); const UNITS_SIZE = [ - {unit: 'B', name: 'Bytes', count: 1024}, - {unit: 'K', name: 'KBytes', count: 1024}, - {unit: 'M', name: 'MBytes', count: 1024}, - {unit: 'G', name: 'GBytes', count: -1} + { unit: "B", name: "Bytes", count: 1024 }, + { unit: "K", name: "KBytes", count: 1024 }, + { unit: "M", name: "MBytes", count: 1024 }, + { unit: "G", name: "GBytes", count: -1 }, ]; const UNITS_TIME = [ - {unit: 's', name: 'seconds', count: 60}, - {unit: 'm', name: 'minutes', count: 60}, - {unit: 'h', name: 'hours', count: 24}, - {unit: 'd', name: 'days', count: 7}, - {unit: 'w', name: 'weeks', count: 4}, - {unit: 'm', name: 'months', count: 12}, - {unit: 'y', name: 'years', count: -1} + { unit: "s", name: "seconds", count: 60 }, + { unit: "m", name: "minutes", count: 60 }, + { unit: "h", name: "hours", count: 24 }, + { unit: "d", name: "days", count: 7 }, + { unit: "w", name: "weeks", count: 4 }, + { unit: "m", name: "months", count: 12 }, + { unit: "y", name: "years", count: -1 }, ]; function getUnit(units, v) { for (let i = 0; i < units.length; ++i) { - if (units[i].count <= 0 || v < units[i].count) - return [v, units[i]]; + if (units[i].count <= 0 || v < units[i].count) return [v, units[i]]; v /= units[i].count; } } const LANGS = [ - {lang: 'bash', ext: '.sh', style: '#'}, - {lang: 'c', ext: '.c', style: 'c'}, - {lang: 'cpp', ext: '.cpp', style: 'c'}, - {lang: 'csharp', ext: '.cs', style: 'c'}, - {lang: 'golang', ext: '.go', style: 'c'}, - {lang: 'java', ext: '.java', style: 'c'}, - {lang: 'javascript', ext: '.js', style: 'c'}, - {lang: 'kotlin', ext: '.kt', style: 'c'}, - {lang: 'mysql', ext: '.sql', style: '--'}, - {lang: 'php', ext: '.php', style: 'c'}, - {lang: 'python', ext: '.py', style: '#'}, - {lang: 'python3', ext: '.py', style: '#'}, - {lang: 'ruby', ext: '.rb', style: '#'}, - {lang: 'rust', ext: '.rs', style: 'c'}, - {lang: 'scala', ext: '.scala', style: 'c'}, - {lang: 'swift', ext: '.swift', style: 'c'}, - {lang: 'typescript', ext: '.ts', style: 'c'} + { lang: "bash", ext: ".sh", style: "#" }, + { lang: "c", ext: ".c", style: "c" }, + { lang: "cpp", ext: ".cpp", style: "c" }, + { lang: "csharp", ext: ".cs", style: "c" }, + { lang: "golang", ext: ".go", style: "c" }, + { lang: "java", ext: ".java", style: "c" }, + { lang: "javascript", ext: ".js", style: "c" }, + { lang: "kotlin", ext: ".kt", style: "c" }, + { lang: "mysql", ext: ".sql", style: "--" }, + { lang: "php", ext: ".php", style: "c" }, + { lang: "python", ext: ".py", style: "#" }, + { lang: "python3", ext: ".py", style: "#" }, + { lang: "ruby", ext: ".rb", style: "#" }, + { lang: "rust", ext: ".rs", style: "c" }, + { lang: "scala", ext: ".scala", style: "c" }, + { lang: "swift", ext: ".swift", style: "c" }, + { lang: "typescript", ext: ".ts", style: "c" }, ]; const h = {}; h.KEYS = { - user: '../user', - stat: '../stat', - plugins: '../../plugins', - problems: 'problems', - translation: 'translationConfig', - problem: p => p.fid + '.' + p.slug + '.' + p.category + user: "../user", + stat: "../stat", + plugins: "../../plugins", + problems: "problems", + translation: "translationConfig", + problem: (p) => p.fid + "." + p.slug + "." + p.category, }; -h.prettyState = function(state) { +h.prettyState = function (state) { switch (state) { - case 'ac': return this.prettyText('', true); - case 'notac': return this.prettyText('', false); - default: return ' '; + case "ac": + return this.prettyText("", true); + case "notac": + return this.prettyText("", false); + default: + return " "; } }; -h.prettyText = function(text, yesNo) { - const chalk = require('./chalk'); - const icon = require('./icon'); +h.prettyText = function (text, yesNo) { + const chalk = require("./chalk"); + const icon = require("./icon"); switch (yesNo) { - case true: return chalk.green(icon.yes + text); - case false: return chalk.red(icon.no + text); - default: return text; + case true: + return chalk.green(icon.yes + text); + case false: + return chalk.red(icon.no + text); + default: + return text; } }; -h.prettySize = function(n) { +h.prettySize = function (n) { const res = getUnit(UNITS_SIZE, n); return res[0].toFixed(2) + res[1].unit; }; -h.prettyTime = function(n) { +h.prettyTime = function (n) { const res = getUnit(UNITS_TIME, n); - return res[0].toFixed(0) + ' ' + res[1].name; + return res[0].toFixed(0) + " " + res[1].name; }; -h.prettyLevel = function(level) { - const chalk = require('./chalk'); +h.prettyLevel = function (level) { + const chalk = require("./chalk"); switch (level.toLowerCase().trim()) { - case 'easy': return chalk.green(level); - case 'medium': return chalk.yellow(level); - case 'hard': return chalk.red(level); - default: return level; + case "easy": + return chalk.green(level); + case "medium": + return chalk.yellow(level); + case "hard": + return chalk.red(level); + default: + return level; } }; -h.levelToName = function(level) { +h.levelToName = function (level) { switch (level) { - case 1: return 'Easy'; - case 2: return 'Medium'; - case 3: return 'Hard'; - default: return ' '; + case 1: + return "Easy"; + case 2: + return "Medium"; + case 3: + return "Hard"; + default: + return " "; } }; -h.statusToName = function(sc) { +h.statusToName = function (sc) { switch (sc) { - case 10: return 'Accepted'; - case 11: return 'Wrong Answer'; - case 12: return 'Memory Limit Exceeded'; - case 13: return 'Output Limit Exceeded'; - case 14: return 'Time Limit Exceeded'; - case 15: return 'Runtime Error'; - case 16: return 'Internal Error'; - case 20: return 'Compile Error'; - case 21: return 'Unknown Error'; - default: return 'Unknown'; + case 10: + return "Accepted"; + case 11: + return "Wrong Answer"; + case 12: + return "Memory Limit Exceeded"; + case 13: + return "Output Limit Exceeded"; + case 14: + return "Time Limit Exceeded"; + case 15: + return "Runtime Error"; + case 16: + return "Internal Error"; + case 20: + return "Compile Error"; + case 21: + return "Unknown Error"; + default: + return "Unknown"; } }; -h.langToExt = function(lang) { - const res = LANGS.find(x => x.lang === lang); - return res ? res.ext : '.raw'; +h.langToExt = function (lang) { + const res = LANGS.find( + (x) => x.lang === lang || (x.lang == "cpp" && lang == "C++") + ); + return res ? res.ext : ".raw"; }; -h.extToLang = function(fullpath) { - const res = LANGS.find(x => fullpath.endsWith(x.ext)); - return res ? res.lang : 'unknown'; +h.extToLang = function (fullpath) { + const res = LANGS.find((x) => fullpath.endsWith(x.ext)); + return res ? res.lang : "unknown"; }; -h.langToCommentStyle = function(lang) { - const res = LANGS.find(x => x.lang === lang); +h.langToCommentStyle = function (lang) { + const res = LANGS.find((x) => x.lang === lang); - return (res && res.style === 'c') ? - {start: '/*', line: ' *', end: ' */', singleLine: '//'} : - {start: res.style, line: res.style, end: res.style, singleLine: res.style}; + return res && res.style === "c" + ? { start: "/*", line: " *", end: " */", singleLine: "//" } + : { + start: res.style, + line: res.style, + end: res.style, + singleLine: res.style, + }; }; -h.readStdin = function(cb) { +h.readStdin = function (cb) { const stdin = process.stdin; const bufs = []; - console.log('NOTE: to finish the input, press ' + - (file.isWindows() ? ' and ' : '')); + console.log( + "NOTE: to finish the input, press " + + (file.isWindows() ? " and " : "") + ); - stdin.on('readable', function() { + stdin.on("readable", function () { const data = stdin.read(); if (data) { // windows doesn't treat ctrl-D as EOF - if (file.isWindows() && data.toString() === '\x04\r\n') { - stdin.emit('end'); + if (file.isWindows() && data.toString() === "\x04\r\n") { + stdin.emit("end"); } else { bufs.push(data); } } }); - stdin.on('end', function() { + stdin.on("end", function () { cb(null, Buffer.concat(bufs).toString()); }); - stdin.on('error', cb); + stdin.on("error", cb); }; -h.getSetCookieValue = function(resp, key) { - const cookies = resp.headers['set-cookie']; +h.getSetCookieValue = function (resp, key) { + const cookies = resp.headers["set-cookie"]; if (!cookies) return null; for (let i = 0; i < cookies.length; ++i) { - const sections = cookies[i].split(';'); + const sections = cookies[i].split(";"); for (let j = 0; j < sections.length; ++j) { - const kv = sections[j].trim().split('='); + const kv = sections[j].trim().split("="); if (kv[0] === key) return kv[1]; } } return null; }; -h.printSafeHTTP = function(msg) { - return msg.replace(/(Cookie\s*:\s*)'.*?'/, '$1') - .replace(/('X-CSRFToken'\s*:\s*)'.*?'/, '$1') - .replace(/('set-cookie'\s*:\s*)\[.*?\]/, '$1'); +h.printSafeHTTP = function (msg) { + return msg + .replace(/(Cookie\s*:\s*)'.*?'/, "$1") + .replace(/('X-CSRFToken'\s*:\s*)'.*?'/, "$1") + .replace(/('set-cookie'\s*:\s*)\[.*?\]/, "$1"); }; -h.spin = function(s) { - return ora(require('./chalk').gray(s)).start(); +h.spin = function (s) { + return ora(require("./chalk").gray(s)).start(); }; const COLORS = { - blue: {fg: 'white', bg: 'bgBlue'}, - cyan: {fg: 'white', bg: 'bgCyan'}, - gray: {fg: 'white', bg: 'bgGray'}, - green: {fg: 'black', bg: 'bgGreen'}, - magenta: {fg: 'white', bg: 'bgMagenta'}, - red: {fg: 'white', bg: 'bgRed'}, - yellow: {fg: 'black', bg: 'bgYellow'}, - white: {fg: 'black', bg: 'bgWhite'} -}; -h.badge = function(s, color) { - s = ' ' + s + ' '; - if (color === 'random') - color = _.chain(COLORS).keys().sample().value(); - const c = COLORS[color || 'blue']; - - const chalk = require('./chalk'); + blue: { fg: "white", bg: "bgBlue" }, + cyan: { fg: "white", bg: "bgCyan" }, + gray: { fg: "white", bg: "bgGray" }, + green: { fg: "black", bg: "bgGreen" }, + magenta: { fg: "white", bg: "bgMagenta" }, + red: { fg: "white", bg: "bgRed" }, + yellow: { fg: "black", bg: "bgYellow" }, + white: { fg: "black", bg: "bgWhite" }, +}; +h.badge = function (s, color) { + s = " " + s + " "; + if (color === "random") color = _.chain(COLORS).keys().sample().value(); + const c = COLORS[color || "blue"]; + + const chalk = require("./chalk"); return chalk[c.fg][c.bg](s); }; diff --git a/lib/plugins/leetcode.js b/lib/plugins/leetcode.js index 9e810146..7e240fc2 100644 --- a/lib/plugins/leetcode.js +++ b/lib/plugins/leetcode.js @@ -1,88 +1,99 @@ -'use strict'; -var util = require('util'); - -var _ = require('underscore'); -var request = require('request'); -var prompt = require('prompt'); - -var config = require('../config'); -var h = require('../helper'); -var file = require('../file'); -var log = require('../log'); -var Plugin = require('../plugin'); -var Queue = require('../queue'); -var session = require('../session'); - -const plugin = new Plugin(10, 'leetcode', '', - 'Plugin to talk with leetcode APIs.'); +"use strict"; +var util = require("util"); + +var _ = require("underscore"); +var request = require("request"); +var prompt = require("prompt"); + +var config = require("../config"); +var h = require("../helper"); +var file = require("../file"); +var log = require("../log"); +var Plugin = require("../plugin"); +var Queue = require("../queue"); +var session = require("../session"); + +const plugin = new Plugin( + 10, + "leetcode", + "", + "Plugin to talk with leetcode APIs." +); var spin; // update options with user credentials -plugin.signOpts = function(opts, user) { - opts.headers.Cookie = 'LEETCODE_SESSION=' + user.sessionId + - ';csrftoken=' + user.sessionCSRF + ';'; - opts.headers['X-CSRFToken'] = user.sessionCSRF; - opts.headers['X-Requested-With'] = 'XMLHttpRequest'; +plugin.signOpts = function (opts, user) { + opts.headers.Cookie = + "LEETCODE_SESSION=" + + user.sessionId + + ";csrftoken=" + + user.sessionCSRF + + ";"; + opts.headers["X-CSRFToken"] = user.sessionCSRF; + opts.headers["X-Requested-With"] = "XMLHttpRequest"; }; -plugin.makeOpts = function(url) { +plugin.makeOpts = function (url) { const opts = {}; opts.url = url; opts.headers = {}; - if (session.isLogin()) - plugin.signOpts(opts, session.getUser()); + if (session.isLogin()) plugin.signOpts(opts, session.getUser()); return opts; }; -plugin.checkError = function(e, resp, expectedStatus) { +plugin.checkError = function (e, resp, expectedStatus) { if (!e && resp && resp.statusCode !== expectedStatus) { const code = resp.statusCode; - log.debug('http error: ' + code); + log.debug("http error: " + code); if (code === 403 || code === 401) { e = session.errors.EXPIRED; } else { - e = {msg: 'http error', statusCode: code}; + e = { msg: "http error", statusCode: code }; } } return e; }; -plugin.init = function() { - config.app = 'leetcode'; +plugin.init = function () { + config.app = "leetcode"; }; plugin.getProblems = function (needTranslation, cb) { - log.debug('running leetcode.getProblems'); + log.debug("running leetcode.getProblems"); let problems = []; - const getCategory = function(category, queue, cb) { - plugin.getCategoryProblems(category, function(e, _problems) { + const getCategory = function (category, queue, cb) { + plugin.getCategoryProblems(category, function (e, _problems) { if (e) { - log.debug(category + ': failed to getProblems: ' + e.msg); + log.debug(category + ": failed to getProblems: " + e.msg); } else { - log.debug(category + ': getProblems got ' + _problems.length + ' problems'); + log.debug( + category + ": getProblems got " + _problems.length + " problems" + ); problems = problems.concat(_problems); } return cb(e); }); }; - spin = h.spin('Downloading problems'); + spin = h.spin("Downloading problems"); const q = new Queue(config.sys.categories, {}, getCategory); - q.run(null, function(e) { + q.run(null, function (e) { spin.stop(); return cb(e, problems); }); }; -plugin.getCategoryProblems = function(category, cb) { - log.debug('running leetcode.getCategoryProblems: ' + category); - const opts = plugin.makeOpts(config.sys.urls.problems.replace('$category', category)); +plugin.getCategoryProblems = function (category, cb) { + log.debug("running leetcode.getCategoryProblems: " + category); + const opts = plugin.makeOpts( + config.sys.urls.problems.replace("$category", category) + ); - spin.text = 'Downloading category ' + category; - request(opts, function(e, resp, body) { + spin.text = "Downloading category " + category; + request(opts, function (e, resp, body) { e = plugin.checkError(e, resp, 200); if (e) return cb(e); @@ -91,36 +102,39 @@ plugin.getCategoryProblems = function(category, cb) { // leetcode permits anonymous access to the problem list // while we require login first to make a better experience. if (json.user_name.length === 0) { - log.debug('no user info in list response, maybe session expired...'); + log.debug("no user info in list response, maybe session expired..."); return cb(session.errors.EXPIRED); } const problems = json.stat_status_pairs - .filter((p) => !p.stat.question__hide) - .map(function(p) { - return { - state: p.status || 'None', - id: p.stat.question_id, - fid: p.stat.frontend_question_id, - name: p.stat.question__title, - slug: p.stat.question__title_slug, - link: config.sys.urls.problem.replace('$slug', p.stat.question__title_slug), - locked: p.paid_only, - percent: p.stat.total_acs * 100 / p.stat.total_submitted, - level: h.levelToName(p.difficulty.level), - starred: p.is_favor, - category: json.category_slug - }; - }); + .filter((p) => !p.stat.question__hide) + .map(function (p) { + return { + state: p.status || "None", + id: p.stat.question_id, + fid: p.stat.frontend_question_id, + name: p.stat.question__title, + slug: p.stat.question__title_slug, + link: config.sys.urls.problem.replace( + "$slug", + p.stat.question__title_slug + ), + locked: p.paid_only, + percent: (p.stat.total_acs * 100) / p.stat.total_submitted, + level: h.levelToName(p.difficulty.level), + starred: p.is_favor, + category: json.category_slug, + }; + }); return cb(null, problems); }); }; -plugin.getProblem = function(problem, needTranslation, cb) { - log.debug('running leetcode.getProblem'); +plugin.getProblem = function (problem, needTranslation, cb) { + log.debug("running leetcode.getProblem"); const user = session.getUser(); - if (problem.locked && !user.paid) return cb('failed to load locked problem!'); + if (problem.locked && !user.paid) return cb("failed to load locked problem!"); const opts = plugin.makeOpts(config.sys.urls.graphql); opts.headers.Origin = config.sys.urls.base; @@ -129,39 +143,40 @@ plugin.getProblem = function(problem, needTranslation, cb) { opts.json = true; opts.body = { query: [ - 'query getQuestionDetail($titleSlug: String!) {', - ' question(titleSlug: $titleSlug) {', - ' content', - ' stats', - ' likes', - ' dislikes', - ' codeDefinition', - ' sampleTestCase', - ' enableRunCode', - ' metaData', - ' translatedContent', - ' }', - '}' - ].join('\n'), - variables: {titleSlug: problem.slug}, - operationName: 'getQuestionDetail' + "query getQuestionDetail($titleSlug: String!) {", + " question(titleSlug: $titleSlug) {", + " content", + " stats", + " likes", + " dislikes", + " codeDefinition", + " sampleTestCase", + " enableRunCode", + " metaData", + " translatedContent", + " }", + "}", + ].join("\n"), + variables: { titleSlug: problem.slug }, + operationName: "getQuestionDetail", }; - const spin = h.spin('Downloading ' + problem.slug); - request.post(opts, function(e, resp, body) { + const spin = h.spin("Downloading " + problem.slug); + request.post(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); const q = body.data.question; - if (!q) return cb('failed to load problem!'); + if (!q) return cb("failed to load problem!"); problem.totalAC = JSON.parse(q.stats).totalAccepted; problem.totalSubmit = JSON.parse(q.stats).totalSubmission; problem.likes = q.likes; problem.dislikes = q.dislikes; - problem.desc = (q.translatedContent && needTranslation) ? q.translatedContent : q.content; + problem.desc = + q.translatedContent && needTranslation ? q.translatedContent : q.content; problem.templates = JSON.parse(q.codeDefinition); problem.testcase = q.sampleTestCase; @@ -175,7 +190,7 @@ plugin.getProblem = function(problem, needTranslation, cb) { }; function runCode(opts, problem, cb) { - opts.method = 'POST'; + opts.method = "POST"; opts.headers.Origin = config.sys.urls.base; opts.headers.Referer = problem.link; opts.json = true; @@ -183,28 +198,27 @@ function runCode(opts, problem, cb) { opts.body = opts.body || {}; _.extendOwn(opts.body, { - lang: problem.lang, + lang: problem.lang, question_id: parseInt(problem.id, 10), - test_mode: false, - typed_code: file.codeData(problem.file) + test_mode: false, + typed_code: file.codeData(problem.file), }); - const spin = h.spin('Sending code to judge'); - request(opts, function(e, resp, body) { + const spin = h.spin("Sending code to judge"); + request(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); if (body.error) { - if (!body.error.includes('too soon')) - return cb(body.error); + if (!body.error.includes("too soon")) return cb(body.error); // hit 'run code too soon' error, have to wait a bit log.debug(body.error); // linear wait ++opts._delay; - log.debug('Will retry after %d seconds...', opts._delay); + log.debug("Will retry after %d seconds...", opts._delay); const reRun = _.partial(runCode, opts, problem, cb); return setTimeout(reRun, opts._delay * 1000); @@ -219,17 +233,17 @@ function runCode(opts, problem, cb) { function verifyResult(task, queue, cb) { const opts = queue.ctx.opts; - opts.method = 'GET'; - opts.url = config.sys.urls.verify.replace('$id', task.id); + opts.method = "GET"; + opts.url = config.sys.urls.verify.replace("$id", task.id); - const spin = h.spin('Waiting for judge result'); - request(opts, function(e, resp, body) { + const spin = h.spin("Waiting for judge result"); + request(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); let result = JSON.parse(body); - if (result.state === 'SUCCESS') { + if (result.state === "SUCCESS") { result = formatResult(result); _.extendOwn(result, task); queue.ctx.results.push(result); @@ -242,28 +256,28 @@ function verifyResult(task, queue, cb) { function formatResult(result) { const x = { - ok: result.run_success, - lang: result.lang, - runtime: result.status_runtime || '', - runtime_percentile: result.runtime_percentile || '', - memory: result.status_memory || '', - memory_percentile: result.memory_percentile || '', - state: result.status_msg, - testcase: util.inspect(result.input || result.last_testcase || ''), - passed: result.total_correct || 0, - total: result.total_testcases || 0 + ok: result.run_success, + lang: result.lang, + runtime: result.status_runtime || "", + runtime_percentile: result.runtime_percentile || "", + memory: result.status_memory || "", + memory_percentile: result.memory_percentile || "", + state: result.status_msg, + testcase: util.inspect(result.input || result.last_testcase || ""), + passed: result.total_correct || 0, + total: result.total_testcases || 0, }; x.error = _.chain(result) - .pick((v, k) => /_error$/.test(k) && v.length > 0) - .values() - .value(); + .pick((v, k) => /_error$/.test(k) && v.length > 0) + .values() + .value(); if (/[runcode|interpret].*/.test(result.submission_id)) { // It's testing let output = result.code_output || []; if (Array.isArray(output)) { - output = output.join('\n'); + output = output.join("\n"); } x.stdout = util.inspect(output); x.answer = result.code_answer; @@ -278,74 +292,108 @@ function formatResult(result) { // make sure we pass eveything! if (x.passed !== x.total) x.ok = false; - if (x.state !== 'Accepted') x.ok = false; + if (x.state !== "Accepted") x.ok = false; if (x.error.length > 0) x.ok = false; return x; } -plugin.testProblem = function(problem, cb) { - log.debug('running leetcode.testProblem'); - const opts = plugin.makeOpts(config.sys.urls.test.replace('$slug', problem.slug)); - opts.body = {data_input: problem.testcase}; +plugin.testProblem = function (problem, cb) { + log.debug("running leetcode.testProblem"); + const opts = plugin.makeOpts( + config.sys.urls.test.replace("$slug", problem.slug) + ); + opts.body = { data_input: problem.testcase }; - runCode(opts, problem, function(e, task) { + runCode(opts, problem, function (e, task) { if (e) return cb(e); - const tasks = [ - {type: 'Actual', id: task.interpret_id}, - ]; + const tasks = [{ type: "Actual", id: task.interpret_id }]; // Used by LeetCode-CN if (task.interpret_expected_id) { - tasks.push({type: 'Expected', id: task.interpret_expected_id}); + tasks.push({ type: "Expected", id: task.interpret_expected_id }); } - const q = new Queue(tasks, {opts: opts, results: []}, verifyResult); - q.run(null, function(e, ctx) { + const q = new Queue(tasks, { opts: opts, results: [] }, verifyResult); + q.run(null, function (e, ctx) { return cb(e, ctx.results); }); }); }; -plugin.submitProblem = function(problem, cb) { - log.debug('running leetcode.submitProblem'); - const opts = plugin.makeOpts(config.sys.urls.submit.replace('$slug', problem.slug)); - opts.body = {judge_type: 'large'}; +plugin.submitProblem = function (problem, cb) { + log.debug("running leetcode.submitProblem"); + const opts = plugin.makeOpts( + config.sys.urls.submit.replace("$slug", problem.slug) + ); + opts.body = { judge_type: "large" }; - runCode(opts, problem, function(e, task) { + runCode(opts, problem, function (e, task) { if (e) return cb(e); - const tasks = [{type: 'Actual', id: task.submission_id}]; - const q = new Queue(tasks, {opts: opts, results: []}, verifyResult); - q.run(null, function(e, ctx) { + const tasks = [{ type: "Actual", id: task.submission_id }]; + const q = new Queue(tasks, { opts: opts, results: [] }, verifyResult); + q.run(null, function (e, ctx) { return cb(e, ctx.results); }); }); }; -plugin.getSubmissions = function(problem, cb) { - log.debug('running leetcode.getSubmissions'); - const opts = plugin.makeOpts(config.sys.urls.submissions.replace('$slug', problem.slug)); - opts.headers.Referer = config.sys.urls.problem.replace('$slug', problem.slug); +plugin.getSubmissions = async (problem, cb) => { + log.debug("running leetcode.getSubmissions"); + const opts = plugin.makeOpts( + config.sys.urls.submissions.replace("$slug", problem.slug) + ); + opts.headers.Referer = config.sys.urls.problem.replace("$slug", problem.slug); - request(opts, function(e, resp, body) { + request(opts, function (e, resp, body) { e = plugin.checkError(e, resp, 200); if (e) return cb(e); // FIXME: this only return the 1st 20 submissions, we should get next if necessary. const submissions = JSON.parse(body).submissions_dump; - for (const submission of submissions) - submission.id = _.last(_.compact(submission.url.split('/'))); - - return cb(null, submissions); + Promise.all( + submissions.map(async (submission) => { + submission.id = _.last(_.compact(submission.url.split("/"))); + const codeOpts = plugin.makeOpts(config.sys.urls.graphql); + codeOpts.headers.Origin = config.sys.urls.base; + codeOpts.headers.Referer = config.sys.urls.problem.replace( + "$slug", + problem.slug + ); + codeOpts.json = true; + codeOpts.body = { + query: [ + "query mySubmissionDetail($id: ID!) {", + "submissionDetail(submissionId: $id) { code} ", + "}", + ].join("\n"), + variables: { id: submission.id }, + }; + await new Promise((res, rej) => { + request.post(codeOpts, function (e, resp, body) { + submission.code = body.data.submissionDetail.code; + res(); + }); + }); + }) + ) + .then(() => { + return cb(null, submissions); + }) + .catch((err) => { + console.log(err); + }); }); }; -plugin.getSubmission = function(submission, cb) { - log.debug('running leetcode.getSubmission'); - const opts = plugin.makeOpts(config.sys.urls.submission.replace('$id', submission.id)); +plugin.getSubmission = function (submission, cb) { + log.debug("running leetcode.getSubmission"); + const opts = plugin.makeOpts( + config.sys.urls.submission.replace("$id", submission.id) + ); - request(opts, function(e, resp, body) { + request(opts, function (e, resp, body) { e = plugin.checkError(e, resp, 200); if (e) return cb(e); @@ -358,23 +406,25 @@ plugin.getSubmission = function(submission, cb) { }); }; -plugin.starProblem = function(problem, starred, cb) { - log.debug('running leetcode.starProblem'); +plugin.starProblem = function (problem, starred, cb) { + log.debug("running leetcode.starProblem"); const user = session.getUser(); - const operationName = starred ? 'addQuestionToFavorite' : 'removeQuestionFromFavorite'; + const operationName = starred + ? "addQuestionToFavorite" + : "removeQuestionFromFavorite"; const opts = plugin.makeOpts(config.sys.urls.graphql); opts.headers.Origin = config.sys.urls.base; opts.headers.Referer = problem.link; opts.json = true; opts.body = { - query: `mutation ${operationName}($favoriteIdHash: String!, $questionId: String!) {\n ${operationName}(favoriteIdHash: $favoriteIdHash, questionId: $questionId) {\n ok\n error\n favoriteIdHash\n questionId\n __typename\n }\n}\n`, - variables: {favoriteIdHash: user.hash, questionId: '' + problem.id}, - operationName: operationName + query: `mutation ${operationName}($favoriteIdHash: String!, $questionId: String!) {\n ${operationName}(favoriteIdHash: $favoriteIdHash, questionId: $questionId) {\n ok\n error\n favoriteIdHash\n questionId\n __typename\n }\n}\n`, + variables: { favoriteIdHash: user.hash, questionId: "" + problem.id }, + operationName: operationName, }; - const spin = h.spin(starred? 'star': 'unstar' + 'problem'); - request.post(opts, function(e, resp, body) { + const spin = h.spin(starred ? "star" : "unstar" + "problem"); + request.post(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); @@ -382,12 +432,12 @@ plugin.starProblem = function(problem, starred, cb) { }); }; -plugin.getFavorites = function(cb) { - log.debug('running leetcode.getFavorites'); +plugin.getFavorites = function (cb) { + log.debug("running leetcode.getFavorites"); const opts = plugin.makeOpts(config.sys.urls.favorites); - const spin = h.spin('Retrieving user favorites'); - request(opts, function(e, resp, body) { + const spin = h.spin("Retrieving user favorites"); + request(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); @@ -397,26 +447,26 @@ plugin.getFavorites = function(cb) { }); }; -plugin.getUserInfo = function(cb) { - log.debug('running leetcode.getUserInfo'); +plugin.getUserInfo = function (cb) { + log.debug("running leetcode.getUserInfo"); const opts = plugin.makeOpts(config.sys.urls.graphql); opts.headers.Origin = config.sys.urls.base; opts.headers.Referer = config.sys.urls.base; opts.json = true; opts.body = { query: [ - '{', - ' user {', - ' username', - ' isCurrentUserPremium', - ' }', - '}' - ].join('\n'), - variables: {} + "{", + " user {", + " username", + " isCurrentUserPremium", + " }", + "}", + ].join("\n"), + variables: {}, }; - const spin = h.spin('Retrieving user profile'); - request.post(opts, function(e, resp, body) { + const spin = h.spin("Retrieving user profile"); + request.post(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); @@ -432,8 +482,8 @@ function runSession(method, data, cb) { opts.method = method; opts.body = data; - const spin = h.spin('Waiting session result'); - request(opts, function(e, resp, body) { + const spin = h.spin("Waiting session result"); + request(opts, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e && e.statusCode === 302) e = session.errors.EXPIRED; @@ -442,79 +492,83 @@ function runSession(method, data, cb) { }); } -plugin.getSessions = function(cb) { - log.debug('running leetcode.getSessions'); - runSession('POST', {}, cb); +plugin.getSessions = function (cb) { + log.debug("running leetcode.getSessions"); + runSession("POST", {}, cb); }; -plugin.activateSession = function(session, cb) { - log.debug('running leetcode.activateSession'); - const data = {func: 'activate', target: session.id}; - runSession('PUT', data, cb); +plugin.activateSession = function (session, cb) { + log.debug("running leetcode.activateSession"); + const data = { func: "activate", target: session.id }; + runSession("PUT", data, cb); }; -plugin.createSession = function(name, cb) { - log.debug('running leetcode.createSession'); - const data = {func: 'create', name: name}; - runSession('PUT', data, cb); +plugin.createSession = function (name, cb) { + log.debug("running leetcode.createSession"); + const data = { func: "create", name: name }; + runSession("PUT", data, cb); }; -plugin.deleteSession = function(session, cb) { - log.debug('running leetcode.deleteSession'); - const data = {target: session.id}; - runSession('DELETE', data, cb); +plugin.deleteSession = function (session, cb) { + log.debug("running leetcode.deleteSession"); + const data = { target: session.id }; + runSession("DELETE", data, cb); }; -plugin.signin = function(user, cb) { - const isCN = config.app === 'leetcode.cn'; - const spin = isCN ? h.spin('Signing in leetcode-cn.com') : h.spin('Signing in leetcode.com'); - request(config.sys.urls.login, function(e, resp, body) { +plugin.signin = function (user, cb) { + const isCN = config.app === "leetcode.cn"; + const spin = isCN + ? h.spin("Signing in leetcode-cn.com") + : h.spin("Signing in leetcode.com"); + request(config.sys.urls.login, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200); if (e) return cb(e); - user.loginCSRF = h.getSetCookieValue(resp, 'csrftoken'); + user.loginCSRF = h.getSetCookieValue(resp, "csrftoken"); const opts = { - url: config.sys.urls.login, + url: config.sys.urls.login, headers: { - Origin: config.sys.urls.base, + Origin: config.sys.urls.base, Referer: config.sys.urls.login, - Cookie: 'csrftoken=' + user.loginCSRF + ';' + Cookie: "csrftoken=" + user.loginCSRF + ";", }, form: { csrfmiddlewaretoken: user.loginCSRF, - login: user.login, - password: user.pass - } + login: user.login, + password: user.pass, + }, }; - request.post(opts, function(e, resp, body) { + request.post(opts, function (e, resp, body) { if (e) return cb(e); - if (resp.statusCode !== 302) return cb('invalid password?'); + if (resp.statusCode !== 302) return cb("invalid password?"); - user.sessionCSRF = h.getSetCookieValue(resp, 'csrftoken'); - user.sessionId = h.getSetCookieValue(resp, 'LEETCODE_SESSION'); + user.sessionCSRF = h.getSetCookieValue(resp, "csrftoken"); + user.sessionId = h.getSetCookieValue(resp, "LEETCODE_SESSION"); session.saveUser(user); return cb(null, user); }); }); }; -plugin.getUser = function(user, cb) { - plugin.getFavorites(function(e, favorites) { +plugin.getUser = function (user, cb) { + plugin.getFavorites(function (e, favorites) { if (!e) { - const f = favorites.favorites.private_favorites.find((f) => f.name === 'Favorite'); + const f = favorites.favorites.private_favorites.find( + (f) => f.name === "Favorite" + ); if (f) { user.hash = f.id_hash; user.name = favorites.user_name; } else { - log.warn('Favorite not found?'); + log.warn("Favorite not found?"); } } else { - log.warn('Failed to retrieve user favorites: ' + e); + log.warn("Failed to retrieve user favorites: " + e); } - plugin.getUserInfo(function(e, _user) { + plugin.getUserInfo(function (e, _user) { if (!e) { user.paid = _user.isCurrentUserPremium; user.name = _user.username; @@ -525,9 +579,9 @@ plugin.getUser = function(user, cb) { }); }; -plugin.login = function(user, cb) { - log.debug('running leetcode.login'); - plugin.signin(user, function(e, user) { +plugin.login = function (user, cb) { + log.debug("running leetcode.login"); + plugin.signin(user, function (e, user) { if (e) return cb(e); plugin.getUser(user, cb); }); @@ -539,19 +593,19 @@ function parseCookie(cookie, body, cb) { const reCsrfResult = csrfPattern.exec(cookie); const reSessionResult = SessionPattern.exec(cookie); if (reSessionResult === null || reCsrfResult === null) { - return cb('invalid cookie?'); + return cb("invalid cookie?"); } return { - sessionId: reSessionResult[1], + sessionId: reSessionResult[1], sessionCSRF: reCsrfResult[1], }; } function requestLeetcodeAndSave(request, leetcodeUrl, user, cb) { - request.get({url: leetcodeUrl}, function(e, resp, body) { + request.get({ url: leetcodeUrl }, function (e, resp, body) { const redirectUri = resp.request.uri.href; if (redirectUri !== config.sys.urls.leetcode_redirect) { - return cb('Login failed. Please make sure the credential is correct.'); + return cb("Login failed. Please make sure the credential is correct."); } const cookieData = parseCookie(resp.request.headers.cookie, body, cb); user.sessionId = cookieData.sessionId; @@ -561,7 +615,7 @@ function requestLeetcodeAndSave(request, leetcodeUrl, user, cb) { }); } -plugin.cookieLogin = function(user, cb) { +plugin.cookieLogin = function (user, cb) { const cookieData = parseCookie(user.cookie, cb); user.sessionId = cookieData.sessionId; user.sessionCSRF = cookieData.sessionCSRF; @@ -569,139 +623,155 @@ plugin.cookieLogin = function(user, cb) { plugin.getUser(user, cb); }; -plugin.githubLogin = function(user, cb) { +plugin.githubLogin = function (user, cb) { const urls = config.sys.urls; const leetcodeUrl = urls.github_login; - const _request = request.defaults({jar: true}); - _request(urls.github_login_request, function(e, resp, body) { - const authenticityToken = body.match(/name="authenticity_token" value="(.*?)"/); + const _request = request.defaults({ jar: true }); + _request(urls.github_login_request, function (e, resp, body) { + const authenticityToken = body.match( + /name="authenticity_token" value="(.*?)"/ + ); let gaId = body.match(/name="ga_id" value="(.*?)"/); if (!gaId) { - gaId = ''; + gaId = ""; } let requiredField = body.match(/name="required_field_(.*?)"/); const timestamp = body.match(/name="timestamp" value="(.*?)"/); const timestampSecret = body.match(/name="timestamp_secret" value="(.*?)"/); if (!(authenticityToken && timestamp && timestampSecret && requiredField)) { - return cb('Get GitHub payload failed'); + return cb("Get GitHub payload failed"); } - requiredField = 'required_field_' + requiredField[1]; + requiredField = "required_field_" + requiredField[1]; const options = { - url: urls.github_session_request, - method: 'POST', + url: urls.github_session_request, + method: "POST", headers: { - 'Content-Type': 'application/x-www-form-urlencoded', + "Content-Type": "application/x-www-form-urlencoded", }, followAllRedirects: true, - form: { - 'login': user.login, - 'password': user.pass, - 'authenticity_token': authenticityToken[1], - 'commit': encodeURIComponent('Sign in'), - 'ga_id': gaId, - 'webauthn-support': 'supported', - 'webauthn-iuvpaa-support': 'unsupported', - 'return_to': '', - 'requiredField': '', - 'timestamp': timestamp[1], - 'timestamp_secret': timestampSecret[1], + form: { + login: user.login, + password: user.pass, + authenticity_token: authenticityToken[1], + commit: encodeURIComponent("Sign in"), + ga_id: gaId, + "webauthn-support": "supported", + "webauthn-iuvpaa-support": "unsupported", + return_to: "", + requiredField: "", + timestamp: timestamp[1], + timestamp_secret: timestampSecret[1], }, }; - _request(options, function(e, resp, body) { + _request(options, function (e, resp, body) { if (resp.statusCode !== 200) { - return cb('GitHub login failed'); + return cb("GitHub login failed"); } if (resp.request.uri.href !== urls.github_tf_redirect) { return requestLeetcodeAndSave(_request, leetcodeUrl, user, cb); } prompt.colors = false; - prompt.message = ''; + prompt.message = ""; prompt.start(); - prompt.get([ - { - name: 'twoFactorCode', - required: true - } - ], function(e, result) { - if (e) return log.fail(e); - const authenticityTokenTwoFactor = body.match(/name="authenticity_token" value="(.*?)"/); - if (authenticityTokenTwoFactor === null) { - return cb('Get GitHub two-factor token failed'); - } - const optionsTwoFactor = { - url: urls.github_tf_session_request, - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - followAllRedirects: true, - form: { - 'otp': result.twoFactorCode, - 'authenticity_token': authenticityTokenTwoFactor[1], - 'utf8': encodeURIComponent('✓'), + prompt.get( + [ + { + name: "twoFactorCode", + required: true, }, - }; - _request(optionsTwoFactor, function(e, resp, body) { - if (resp.request.uri.href === urls.github_tf_session_request) { - return cb('Invalid two-factor code please check'); + ], + function (e, result) { + if (e) return log.fail(e); + const authenticityTokenTwoFactor = body.match( + /name="authenticity_token" value="(.*?)"/ + ); + if (authenticityTokenTwoFactor === null) { + return cb("Get GitHub two-factor token failed"); } - requestLeetcodeAndSave(_request, leetcodeUrl, user, cb); - }); - }); + const optionsTwoFactor = { + url: urls.github_tf_session_request, + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + followAllRedirects: true, + form: { + otp: result.twoFactorCode, + authenticity_token: authenticityTokenTwoFactor[1], + utf8: encodeURIComponent("✓"), + }, + }; + _request(optionsTwoFactor, function (e, resp, body) { + if (resp.request.uri.href === urls.github_tf_session_request) { + return cb("Invalid two-factor code please check"); + } + requestLeetcodeAndSave(_request, leetcodeUrl, user, cb); + }); + } + ); }); }); }; -plugin.linkedinLogin = function(user, cb) { +plugin.linkedinLogin = function (user, cb) { const urls = config.sys.urls; const leetcodeUrl = urls.linkedin_login; const _request = request.defaults({ - jar: true, + jar: true, headers: { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36' - } + "User-Agent": + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36", + }, }); - _request(urls.linkedin_login_request, function(e, resp, body) { - if ( resp.statusCode !== 200) { - return cb('Get LinkedIn session failed'); + _request(urls.linkedin_login_request, function (e, resp, body) { + if (resp.statusCode !== 200) { + return cb("Get LinkedIn session failed"); } - const csrfToken = body.match(/input type="hidden" name="csrfToken" value="(.*?)"/); - const loginCsrfToken = body.match(/input type="hidden" name="loginCsrfParam" value="(.*?)"/); - const sIdString = body.match(/input type="hidden" name="sIdString" value="(.*?)"/); - const pageInstance = body.match(/input type="hidden" name="pageInstance" value="(.*?)"/); + const csrfToken = body.match( + /input type="hidden" name="csrfToken" value="(.*?)"/ + ); + const loginCsrfToken = body.match( + /input type="hidden" name="loginCsrfParam" value="(.*?)"/ + ); + const sIdString = body.match( + /input type="hidden" name="sIdString" value="(.*?)"/ + ); + const pageInstance = body.match( + /input type="hidden" name="pageInstance" value="(.*?)"/ + ); if (!(csrfToken && loginCsrfToken && sIdString && pageInstance)) { - return cb('Get LinkedIn payload failed'); + return cb("Get LinkedIn payload failed"); } const options = { - url: urls.linkedin_session_request, - method: 'POST', + url: urls.linkedin_session_request, + method: "POST", headers: { - 'Content-Type': 'application/x-www-form-urlencoded', + "Content-Type": "application/x-www-form-urlencoded", }, followAllRedirects: true, - form: { - 'csrfToken': csrfToken[1], - 'session_key': user.login, - 'ac': 2, - 'sIdString': sIdString[1], - 'parentPageKey': 'd_checkpoint_lg_consumerLogin', - 'pageInstance': pageInstance[1], - 'trk': 'public_profile_nav-header-signin', - 'authUUID': '', - 'session_redirect': 'https://www.linkedin.com/feed/', - 'loginCsrfParam': loginCsrfToken[1], - 'fp_data': 'default', - '_d': 'd', - 'showGoogleOneTapLogin': true, - 'controlId': 'd_checkpoint_lg_consumerLogin-login_submit_button', - 'session_password': user.pass, - 'loginFlow': 'REMEMBER_ME_OPTIN' + form: { + csrfToken: csrfToken[1], + session_key: user.login, + ac: 2, + sIdString: sIdString[1], + parentPageKey: "d_checkpoint_lg_consumerLogin", + pageInstance: pageInstance[1], + trk: "public_profile_nav-header-signin", + authUUID: "", + session_redirect: "https://www.linkedin.com/feed/", + loginCsrfParam: loginCsrfToken[1], + fp_data: "default", + _d: "d", + showGoogleOneTapLogin: true, + controlId: "d_checkpoint_lg_consumerLogin-login_submit_button", + session_password: user.pass, + loginFlow: "REMEMBER_ME_OPTIN", }, }; - _request(options, function(e, resp, body) { + _request(options, function (e, resp, body) { if (resp.statusCode !== 200) { - return cb('LinkedIn login failed'); + return cb("LinkedIn login failed"); } requestLeetcodeAndSave(_request, leetcodeUrl, user, cb); }); diff --git a/package-lock.json b/package-lock.json index 7dce5cd3..b9babb0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,15 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/core": { "version": "7.10.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.3.tgz", @@ -195,17 +186,6 @@ "@babel/types": "^7.10.1" } }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, "@babel/parser": { "version": "7.10.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.3.tgz", @@ -304,6 +284,111 @@ "to-fast-properties": "^2.0.0" } }, + "@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -440,9 +525,9 @@ } }, "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, "aggregate-error": { @@ -605,12 +690,6 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -858,12 +937,6 @@ "supports-color": "^5.3.0" } }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -1100,16 +1173,40 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "css-select": { @@ -1302,12 +1399,6 @@ "safer-buffer": "^2.1.0" } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1352,106 +1443,352 @@ } }, "eslint": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz", - "integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.0.2", - "text-table": "^0.2.0" + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "minimist": "^1.2.5" + "estraverse": "^5.1.0" } }, - "strip-ansi": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + }, + "dependencies": { + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "argparse": "^2.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, "eslint-config-google": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.11.0.tgz", - "integrity": "sha512-z541Fs5TFaY7/35v/z100InQ2f3V2J7e3u/0yKrnImgsHjh6JWgSRngfC/mZepn/+XN16jUydt64k//kxXc1fw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", "dev": true }, "eslint-scope": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.2.tgz", - "integrity": "sha512-5q1+B/ogmHl8+paxtOKx38Z8LtWkVGuNt3+GQNErqwLl6ViNp/gdJGMCjZNxZ8j/VYjDNZ2Fo+eQc1TAVPIzbg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "dependencies": { + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } @@ -1463,20 +1800,26 @@ "dev": true }, "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" }, "dependencies": { "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true } } @@ -1526,17 +1869,6 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -1651,6 +1983,12 @@ "write": "^0.2.1" } }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2060,11 +2398,29 @@ "dev": true }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2096,85 +2452,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" }, - "inquirer": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", - "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.11", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "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": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", - "dev": true, - "requires": { - "ansi-regex": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", - "dev": true - } - } - } - } - }, "into-stream": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-5.1.1.tgz", @@ -2559,6 +2836,12 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -3085,12 +3368,6 @@ "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=" }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "nock": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/nock/-/nock-10.0.2.tgz", @@ -3556,6 +3833,23 @@ "release-zalgo": "^1.0.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parse5": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", @@ -3579,9 +3873,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { @@ -4021,9 +4315,9 @@ "dev": true }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "release-zalgo": { @@ -4449,15 +4743,6 @@ "rx-lite": "*" } }, - "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4542,25 +4827,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "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": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4735,52 +5001,6 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "optional": true }, - "table": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", - "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", - "dev": true, - "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", - "dev": true - }, - "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": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz", - "integrity": "sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.0.0" - } - }, - "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", - "dev": true, - "requires": { - "ansi-regex": "^4.0.0" - } - } - } - }, "tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -4919,12 +5139,6 @@ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", "optional": true }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5059,6 +5273,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -5152,6 +5372,12 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/package.json b/package.json index 93c650b6..610ddde4 100644 --- a/package.json +++ b/package.json @@ -64,9 +64,9 @@ "yargs": "^15.4.1" }, "devDependencies": { + "eslint": "^8.11.0", + "eslint-config-google": "^0.14.0", "chai": "4.2.0", - "eslint": "5.9.0", - "eslint-config-google": "0.11.0", "mocha": "^8.3.2", "nock": "10.0.2", "nyc": "^15.1.0", From fc91bbbf07972f7f8b0e198cb2fed985235aea1f Mon Sep 17 00:00:00 2001 From: ouyangjunyi Date: Sat, 19 Mar 2022 17:40:43 +0800 Subject: [PATCH 2/5] test --- .vscode/launch.json | 2 +- README.md | 2 + lib/commands/submission.js | 111 ++++++++++++++++++------------------- 3 files changed, 57 insertions(+), 58 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f803f95..0d7aba4e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "request": "launch", "name": "mine", "program": "${workspaceFolder}/bin/leetcode", - "args": ["submission", "-l", "C++", "94"] + "args": ["submission", "-l", "C++", "-o", "submissions", "94"] }, { "type": "node", diff --git a/README.md b/README.md index 686755c9..4890047b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ # leetcode-cli +node版本支持:v12.22.11 + > Note: This repository is forked from [leetcode-cli](https://github.com/skygragon/leetcode-cli) for temporary usage. > Note: Copy cookie from webbrowser and Using **leetcode user -c** can temporary fix can't [login problem](https://github.com/jdneo/vscode-leetcode/issues/478). diff --git a/lib/commands/submission.js b/lib/commands/submission.js index 2b033f4c..4e9e11ab 100644 --- a/lib/commands/submission.js +++ b/lib/commands/submission.js @@ -15,42 +15,42 @@ var session = require('../session'); const cmd = { command: 'submission [keyword]', aliases: ['pull'], - desc: 'Download submission code', - builder: function(yargs) { + desc: 'Download submission code', + builder: function (yargs) { return yargs .option('a', { - alias: 'all', - type: 'boolean', - default: false, + alias: 'all', + type: 'boolean', + default: false, describe: 'Download all questions' }) .option('l', { - alias: 'lang', - type: 'string', - default: 'all', + alias: 'lang', + type: 'string', + default: 'all', describe: 'Filter by programming language' }) .option('o', { - alias: 'outdir', - type: 'string', + alias: 'outdir', + type: 'string', describe: 'Where to save submission code', - default: '.' + default: '.' }) .option('x', { - alias: 'extra', - type: 'boolean', - default: false, + alias: 'extra', + type: 'boolean', + default: false, describe: 'Show extra question details in submission code' }) .option('T', { - alias: 'dontTranslate', - type: 'boolean', - default: false, + alias: 'dontTranslate', + type: 'boolean', + default: false, describe: 'Set to true to disable endpoint\'s translation', }) .positional('keyword', { - type: 'string', - default: '', + type: 'string', + default: '', describe: 'Download specific question by id' }) .example(chalk.yellow('leetcode submission -a -o mydir'), 'Download all to folder mydir') @@ -69,13 +69,13 @@ function doTask(problem, queue, cb) { // - yellow: not ac-ed, fresh download // - white: existed already, skip download log.printf('[%=4s] %-60s %s', problem.fid, problem.name, - (e ? chalk.red('ERROR: ' + (e.msg || e)) : msg)); + (e ? chalk.red('ERROR: ' + (e.msg || e)) : msg)); if (cb) cb(e); } if (argv.extra) { // have to get problem details, e.g. problem description. - core.getProblem(problem.fid, !argv.dontTranslate, function(e, problem) { + core.getProblem(problem.fid, !argv.dontTranslate, function (e, problem) { if (e) return cb(e); exportSubmission(problem, argv, onTaskDone); }); @@ -85,52 +85,49 @@ function doTask(problem, queue, cb) { } function exportSubmission(problem, argv, cb) { - core.getSubmissions(problem, function(e, submissions) { + core.getSubmissions(problem, function (e, submissions) { if (e) return cb(e); if (submissions.length === 0) return cb('No submissions?'); // get obj list contain required filetype - submissions = submissions.filter(x => argv.lang === 'all' || argv.lang === x.lang); - if (submissions.length === 0) - return cb('No submissions in required language.'); - - // if no accepted, use the latest non-accepted one - const submission = submissions.find(x => x.status_display === 'Accepted') || submissions[0]; - submission.ac = (submission.status_display === 'Accepted'); - - const data = _.extend({}, submission, problem); - data.sid = submission.id; - data.ac = submission.ac ? 'ac' : 'notac'; - const basename = file.fmt(config.file.submission, data); - const f = path.join(argv.outdir, basename + h.langToExt(submission.lang)); - - file.mkdir(argv.outdir); - // skip the existing cached submissions - if (file.exist(f)) - return cb(null, chalk.underline(f)); - - core.getSubmission(submission, function(e, submission) { - if (e) return cb(e); - - const opts = { - lang: submission.lang=='C++'?'cpp':submission.lang, - code: submission.code, - tpl: argv.extra ? 'detailed' : 'codeonly' - }; - file.write(f, core.exportProblem(problem, opts)); - cb(null, submission.ac ? chalk.green.underline(f) - : chalk.yellow.underline(f)); - }); + submissions.map(submission => { + if ((argv.lang === 'all' || argv.lang === submission.lang) && submission.status_display === 'Accepted') { + submission.ac = true; + const data = _.extend({}, submission, problem); + // data.ac = true; + data.sid = submission.id; + const basename = file.fmt(config.file.submission, data); + const f = path.join(argv.outdir, basename + h.langToExt(submission.lang)); + + file.mkdir(argv.outdir); + // skip the existing cached submissions + if (file.exist(f)) + return cb(null, chalk.underline(f)); + + core.getSubmission(submission, function (e, submission) { + if (e) return cb(e); + + const opts = { + lang: submission.lang == 'C++' ? 'cpp' : submission.lang, + code: submission.code, + tpl: argv.extra ? 'detailed' : 'codeonly' + }; + file.write(f, core.exportProblem(problem, opts)); + cb(null, submission.ac ? chalk.green.underline(f) + : chalk.yellow.underline(f)); + }) + } + }) }); } -cmd.handler = function(argv) { +cmd.handler = function (argv) { session.argv = argv; - const q = new Queue(null, {argv: argv}, doTask); + const q = new Queue(null, { argv: argv }, doTask); if (argv.all) { - core.getProblems(function(e, problems) { + core.getProblems(function (e, problems) { if (e) return log.fail(e); problems = problems.filter(x => x.state === 'ac' || x.state === 'notac'); q.addTasks(problems).run(); @@ -141,7 +138,7 @@ cmd.handler = function(argv) { if (!argv.keyword) return log.fail('missing keyword?'); - core.getProblem(argv.keyword, !argv.dontTranslate, function(e, problem) { + core.getProblem(argv.keyword, !argv.dontTranslate, function (e, problem) { if (e) return log.fail(e); q.addTask(problem).run(); }); From 9dbf1e56c3bb301d99ce5a633ef118df77616c1f Mon Sep 17 00:00:00 2001 From: ouyangjunyi Date: Sat, 19 Mar 2022 20:23:28 +0800 Subject: [PATCH 3/5] bug-fix: submission sync to async && approve accept --- .vscode/launch.json | 11 ++++++- lib/commands/submission.js | 67 +++++++++++++++++++------------------- lib/plugins/leetcode.js | 52 ++++++++++++----------------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 0d7aba4e..9ad1fbc8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,16 @@ "request": "launch", "name": "mine", "program": "${workspaceFolder}/bin/leetcode", - "args": ["submission", "-l", "C++", "-o", "submissions", "94"] + "args": [ + "submission", + "-c", + "true", + "-l", + "C++", + "-o", + "submissions", + "94" + ] }, { "type": "node", diff --git a/lib/commands/submission.js b/lib/commands/submission.js index 4e9e11ab..f2dc2026 100644 --- a/lib/commands/submission.js +++ b/lib/commands/submission.js @@ -36,6 +36,12 @@ const cmd = { describe: 'Where to save submission code', default: '.' }) + .option('c', { + alias: 'accept', + type: 'boolean', + describe: 'choose accept', + default: false + }) .option('x', { alias: 'extra', type: 'boolean', @@ -85,40 +91,35 @@ function doTask(problem, queue, cb) { } function exportSubmission(problem, argv, cb) { - core.getSubmissions(problem, function (e, submissions) { + core.getSubmissions(problem, function (e, submission) { if (e) return cb(e); - if (submissions.length === 0) - return cb('No submissions?'); - - // get obj list contain required filetype - submissions.map(submission => { - if ((argv.lang === 'all' || argv.lang === submission.lang) && submission.status_display === 'Accepted') { - submission.ac = true; - const data = _.extend({}, submission, problem); - // data.ac = true; - data.sid = submission.id; - const basename = file.fmt(config.file.submission, data); - const f = path.join(argv.outdir, basename + h.langToExt(submission.lang)); - - file.mkdir(argv.outdir); - // skip the existing cached submissions - if (file.exist(f)) - return cb(null, chalk.underline(f)); - - core.getSubmission(submission, function (e, submission) { - if (e) return cb(e); - - const opts = { - lang: submission.lang == 'C++' ? 'cpp' : submission.lang, - code: submission.code, - tpl: argv.extra ? 'detailed' : 'codeonly' - }; - file.write(f, core.exportProblem(problem, opts)); - cb(null, submission.ac ? chalk.green.underline(f) - : chalk.yellow.underline(f)); - }) - } - }) + + if ((argv.lang === 'all' || argv.lang === submission.lang)) { + submission.ac = submission.status_display === 'Accepted'; + if (argv.accept && !submission.ac) return; + const data = _.extend({}, submission, problem); + data.sid = submission.id; + const basename = file.fmt(config.file.submission, data); + const f = path.join(argv.outdir, basename + h.langToExt(submission.lang)); + + file.mkdir(argv.outdir); + // skip the existing cached submissions + if (file.exist(f)) + return cb(null, chalk.underline(f)); + + core.getSubmission(submission, function (e, submission) { + if (e) return cb(e); + + const opts = { + lang: submission.lang == 'C++' ? 'cpp' : submission.lang, + code: submission.code, + tpl: argv.extra ? 'detailed' : 'codeonly' + }; + file.write(f, core.exportProblem(problem, opts)); + cb(null, submission.ac ? chalk.green.underline(f) + : chalk.yellow.underline(f)); + }) + } }); } diff --git a/lib/plugins/leetcode.js b/lib/plugins/leetcode.js index 7e240fc2..1ad0d7fc 100644 --- a/lib/plugins/leetcode.js +++ b/lib/plugins/leetcode.js @@ -352,38 +352,28 @@ plugin.getSubmissions = async (problem, cb) => { // FIXME: this only return the 1st 20 submissions, we should get next if necessary. const submissions = JSON.parse(body).submissions_dump; - Promise.all( - submissions.map(async (submission) => { - submission.id = _.last(_.compact(submission.url.split("/"))); - const codeOpts = plugin.makeOpts(config.sys.urls.graphql); - codeOpts.headers.Origin = config.sys.urls.base; - codeOpts.headers.Referer = config.sys.urls.problem.replace( - "$slug", - problem.slug - ); - codeOpts.json = true; - codeOpts.body = { - query: [ - "query mySubmissionDetail($id: ID!) {", - "submissionDetail(submissionId: $id) { code} ", - "}", - ].join("\n"), - variables: { id: submission.id }, - }; - await new Promise((res, rej) => { - request.post(codeOpts, function (e, resp, body) { - submission.code = body.data.submissionDetail.code; - res(); - }); - }); - }) - ) - .then(() => { - return cb(null, submissions); - }) - .catch((err) => { - console.log(err); + submissions.map(async (submission) => { + submission.id = _.last(_.compact(submission.url.split("/"))); + const codeOpts = plugin.makeOpts(config.sys.urls.graphql); + codeOpts.headers.Origin = config.sys.urls.base; + codeOpts.headers.Referer = config.sys.urls.problem.replace( + "$slug", + problem.slug + ); + codeOpts.json = true; + codeOpts.body = { + query: [ + "query mySubmissionDetail($id: ID!) {", + "submissionDetail(submissionId: $id) { code} ", + "}", + ].join("\n"), + variables: { id: submission.id }, + }; + request.post(codeOpts, function (e, resp, body) { + submission.code = body.data.submissionDetail.code; + cb(null, submission) }); + }); }); }; From 825f7606331dd8a488cb44c706299643fd0af452 Mon Sep 17 00:00:00 2001 From: ouyangjunyi Date: Mon, 4 Apr 2022 13:39:13 +0800 Subject: [PATCH 4/5] get problem locked ok --- lib/plugins/leetcode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/leetcode.js b/lib/plugins/leetcode.js index 1ad0d7fc..c5e8686f 100644 --- a/lib/plugins/leetcode.js +++ b/lib/plugins/leetcode.js @@ -134,7 +134,7 @@ plugin.getCategoryProblems = function (category, cb) { plugin.getProblem = function (problem, needTranslation, cb) { log.debug("running leetcode.getProblem"); const user = session.getUser(); - if (problem.locked && !user.paid) return cb("failed to load locked problem!"); + // if (problem.locked && !user.paid) return cb("failed to load locked problem!"); const opts = plugin.makeOpts(config.sys.urls.graphql); opts.headers.Origin = config.sys.urls.base; From dc692681997c4d9ac0f4566066f194876ef7c561 Mon Sep 17 00:00:00 2001 From: ouyangjunyi Date: Tue, 10 May 2022 22:07:55 +0800 Subject: [PATCH 5/5] fix: update cn domain --- lib/plugins/leetcode.cn.js | 38 +++++++++++++++++++------------------- lib/plugins/leetcode.js | 4 +--- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/plugins/leetcode.cn.js b/lib/plugins/leetcode.cn.js index 77639c7d..a7ca53e8 100644 --- a/lib/plugins/leetcode.cn.js +++ b/lib/plugins/leetcode.cn.js @@ -17,24 +17,24 @@ var plugin = new Plugin(15, 'leetcode.cn', '2018.11.25', plugin.init = function() { config.app = 'leetcode.cn'; - config.sys.urls.base = 'https://leetcode-cn.com'; - config.sys.urls.login = 'https://leetcode-cn.com/accounts/login/'; - config.sys.urls.problems = 'https://leetcode-cn.com/api/problems/$category/'; - config.sys.urls.problem = 'https://leetcode-cn.com/problems/$slug/description/'; - config.sys.urls.graphql = 'https://leetcode-cn.com/graphql'; - config.sys.urls.problem_detail = 'https://leetcode-cn.com/graphql'; - config.sys.urls.test = 'https://leetcode-cn.com/problems/$slug/interpret_solution/'; - config.sys.urls.session = 'https://leetcode-cn.com/session/'; - config.sys.urls.submit = 'https://leetcode-cn.com/problems/$slug/submit/'; - config.sys.urls.submissions = 'https://leetcode-cn.com/api/submissions/$slug'; - config.sys.urls.submission = 'https://leetcode-cn.com/submissions/detail/$id/'; - config.sys.urls.verify = 'https://leetcode-cn.com/submissions/detail/$id/check/'; - config.sys.urls.favorites = 'https://leetcode-cn.com/list/api/questions'; - config.sys.urls.favorite_delete = 'https://leetcode-cn.com/list/api/questions/$hash/$id'; + config.sys.urls.base = 'https://leetcode.cn'; + config.sys.urls.login = 'https://leetcode.cn/accounts/login/'; + config.sys.urls.problems = 'https://leetcode.cn/api/problems/$category/'; + config.sys.urls.problem = 'https://leetcode.cn/problems/$slug/description/'; + config.sys.urls.graphql = 'https://leetcode.cn/graphql'; + config.sys.urls.problem_detail = 'https://leetcode.cn/graphql'; + config.sys.urls.test = 'https://leetcode.cn/problems/$slug/interpret_solution/'; + config.sys.urls.session = 'https://leetcode.cn/session/'; + config.sys.urls.submit = 'https://leetcode.cn/problems/$slug/submit/'; + config.sys.urls.submissions = 'https://leetcode.cn/api/submissions/$slug'; + config.sys.urls.submission = 'https://leetcode.cn/submissions/detail/$id/'; + config.sys.urls.verify = 'https://leetcode.cn/submissions/detail/$id/check/'; + config.sys.urls.favorites = 'https://leetcode.cn/list/api/questions'; + config.sys.urls.favorite_delete = 'https://leetcode.cn/list/api/questions/$hash/$id'; // third parties - config.sys.urls.github_login = 'https://leetcode-cn.com/accounts/github/login/?next=%2F'; - config.sys.urls.linkedin_login = 'https://leetcode-cn.com/accounts/linkedin_oauth2/login/?next=%2F'; - config.sys.urls.leetcode_redirect = 'https://leetcode-cn.com/'; + config.sys.urls.github_login = 'https://leetcode.cn/accounts/github/login/?next=%2F'; + config.sys.urls.linkedin_login = 'https://leetcode.cn/accounts/linkedin_oauth2/login/?next=%2F'; + config.sys.urls.leetcode_redirect = 'https://leetcode.cn/'; }; // FIXME: refactor those @@ -101,7 +101,7 @@ plugin.getProblemsTitle = function(cb) { const opts = makeOpts(config.sys.urls.graphql); opts.headers.Origin = config.sys.urls.base; - opts.headers.Referer = 'https://leetcode-cn.com/api/problems/algorithms/'; + opts.headers.Referer = 'https://leetcode.cn/api/problems/algorithms/'; opts.json = true; opts.body = { @@ -133,4 +133,4 @@ plugin.getProblemsTitle = function(cb) { }); }; -module.exports = plugin; +module.exports = plugin; \ No newline at end of file diff --git a/lib/plugins/leetcode.js b/lib/plugins/leetcode.js index c5e8686f..4395b791 100644 --- a/lib/plugins/leetcode.js +++ b/lib/plugins/leetcode.js @@ -507,9 +507,7 @@ plugin.deleteSession = function (session, cb) { plugin.signin = function (user, cb) { const isCN = config.app === "leetcode.cn"; - const spin = isCN - ? h.spin("Signing in leetcode-cn.com") - : h.spin("Signing in leetcode.com"); + const spin = isCN ? h.spin('Signing in leetcode.cn') : h.spin('Signing in leetcode.com'); request(config.sys.urls.login, function (e, resp, body) { spin.stop(); e = plugin.checkError(e, resp, 200);