Skip to content

Commit af54ce2

Browse files
committed
merge from upstream
2 parents 9caf9bc + c5f6b89 commit af54ce2

19 files changed

+1218
-451
lines changed

lib/cache.js

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ cache.init = function() {
99
file.mkdir(file.cacheDir());
1010
};
1111

12+
cache.deleteAll = function () {
13+
cache.list().forEach(value => {
14+
cache.del(value.name);
15+
})
16+
};
17+
1218
cache.get = function(k) {
1319
const fullpath = file.cacheFile(k);
1420
if (!file.exist(fullpath)) return null;

lib/commands/list.js

+34-28
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,40 @@ const cmd = {
1414
desc: 'List questions',
1515
builder: function(yargs) {
1616
return yargs
17-
.option('q', core.filters.query)
18-
.option('s', {
19-
alias: 'stat',
20-
type: 'boolean',
21-
default: false,
22-
describe: 'Show statistics of listed questions'
23-
})
24-
.option('t', core.filters.tag)
25-
.option('x', {
26-
alias: 'extra',
27-
type: 'boolean',
28-
default: false,
29-
describe: 'Show extra details: category, companies, tags.'
30-
})
31-
.option('c', core.filters.category)
32-
.positional('keyword', {
33-
type: 'string',
34-
default: '',
35-
describe: 'Filter questions by keyword'
36-
})
37-
.example(chalk.yellow('leetcode list'), 'List all questions')
38-
.example(chalk.yellow('leetcode list -x'), 'Show extra info of questions, e.g. tags')
39-
.example('', '')
40-
.example(chalk.yellow('leetcode list array'), 'List questions that has "array" in name')
41-
.example(chalk.yellow('leetcode list -q eD'), 'List questions that with easy level and not done')
42-
.example(chalk.yellow('leetcode list -t google'), 'List questions from Google company (require plugin)')
43-
.example(chalk.yellow('leetcode list -t stack'), 'List questions realted to stack (require plugin)')
44-
.example(chalk.yellow('leetcode list -c lcof'), 'List questions from category (require plugin)');
17+
.option('q', core.filters.query)
18+
.option('s', {
19+
alias: 'stat',
20+
type: 'boolean',
21+
default: false,
22+
describe: 'Show statistics of listed questions'
23+
})
24+
.option('t', core.filters.tag)
25+
.option('x', {
26+
alias: 'extra',
27+
type: 'boolean',
28+
default: false,
29+
describe: 'Show extra details: category, companies, tags.'
30+
})
31+
.option('T', {
32+
alias: 'dontTranslate',
33+
type: 'boolean',
34+
default: false,
35+
describe: 'Set to true to disable endpoint\'s translation',
36+
})
37+
.option('c', core.filters.category)
38+
.positional('keyword', {
39+
type: 'string',
40+
default: '',
41+
describe: 'Filter questions by keyword'
42+
})
43+
.example(chalk.yellow('leetcode list'), 'List all questions')
44+
.example(chalk.yellow('leetcode list -x'), 'Show extra info of questions, e.g. tags')
45+
.example('', '')
46+
.example(chalk.yellow('leetcode list array'), 'List questions that has "array" in name')
47+
.example(chalk.yellow('leetcode list -q eD'), 'List questions that with easy level and not done')
48+
.example(chalk.yellow('leetcode list -t google'), 'List questions from Google company (require plugin)')
49+
.example(chalk.yellow('leetcode list -t stack'), 'List questions realted to stack (require plugin)')
50+
.example(chalk.yellow('leetcode list -c lcof'), 'List questions from category (require plugin)');
4551
}
4652
};
4753

lib/commands/show.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ const cmd = {
5757
default: false,
5858
describe: 'Show extra question details in source code'
5959
})
60+
.option('T', {
61+
alias: 'dontTranslate',
62+
type: 'boolean',
63+
default: false,
64+
describe: 'Set to true to disable endpoint\'s translation',
65+
})
6066
.positional('keyword', {
6167
type: 'string',
6268
default: '',
@@ -175,7 +181,7 @@ cmd.handler = function(argv) {
175181
session.argv = argv;
176182
if (argv.keyword.length > 0) {
177183
// show specific one
178-
core.getProblem(argv.keyword, function(e, problem) {
184+
core.getProblem(argv.keyword, !argv.dontTranslate, function(e, problem) {
179185
if (e) return log.fail(e);
180186
showProblem(problem, argv);
181187
});
@@ -194,7 +200,7 @@ cmd.handler = function(argv) {
194200
if (problems.length === 0) return log.fail('Problem not found!');
195201

196202
const problem = _.sample(problems);
197-
core.getProblem(problem, function(e, problem) {
203+
core.getProblem(problem, !argv.dontTranslate, function(e, problem) {
198204
if (e) return log.fail(e);
199205
showProblem(problem, argv);
200206
});

lib/commands/star.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ const cmd = {
2929

3030
cmd.handler = function(argv) {
3131
session.argv = argv;
32-
core.getProblem(argv.keyword, function(e, problem) {
32+
// translation doesn't affect question lookup
33+
core.getProblem(argv.keyword, true, function(e, problem) {
3334
if (e) return log.fail(e);
3435

3536
core.starProblem(problem, !argv.delete, function(e, starred) {

lib/commands/submission.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ const cmd = {
4242
default: false,
4343
describe: 'Show extra question details in submission code'
4444
})
45+
.option('T', {
46+
alias: 'dontTranslate',
47+
type: 'boolean',
48+
default: false,
49+
describe: 'Set to true to disable endpoint\'s translation',
50+
})
4551
.positional('keyword', {
4652
type: 'string',
4753
default: '',
@@ -69,7 +75,7 @@ function doTask(problem, queue, cb) {
6975

7076
if (argv.extra) {
7177
// have to get problem details, e.g. problem description.
72-
core.getProblem(problem.fid, function(e, problem) {
78+
core.getProblem(problem.fid, !argv.dontTranslate, function(e, problem) {
7379
if (e) return cb(e);
7480
exportSubmission(problem, argv, onTaskDone);
7581
});
@@ -135,7 +141,7 @@ cmd.handler = function(argv) {
135141
if (!argv.keyword)
136142
return log.fail('missing keyword?');
137143

138-
core.getProblem(argv.keyword, function(e, problem) {
144+
core.getProblem(argv.keyword, !argv.dontTranslate, function(e, problem) {
139145
if (e) return log.fail(e);
140146
q.addTask(problem).run();
141147
});

lib/commands/submit.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ cmd.handler = function(argv) {
4949

5050
const meta = file.meta(argv.filename);
5151

52-
core.getProblem(meta.id, function(e, problem) {
52+
// translation doesn't affect problem lookup
53+
core.getProblem(meta.id, true, function(e, problem) {
5354
if (e) return log.fail(e);
5455

5556
problem.file = argv.filename;

lib/commands/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function runTest(argv) {
6060

6161
const meta = file.meta(argv.filename);
6262

63-
core.getProblem(meta.id, function(e, problem) {
63+
core.getProblem(meta.id, true, function(e, problem) {
6464
if (e) return log.fail(e);
6565

6666
if (!problem.testable)

lib/core.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const QUERY_HANDLERS = {
6767
};
6868

6969
core.filterProblems = function(opts, cb) {
70-
this.getProblems(function(e, problems) {
70+
this.getProblems(!opts.dontTranslate, function(e, problems) {
7171
if (e) return cb(e);
7272
for (const q of (opts.query || '').split('')) {
7373
const f = QUERY_HANDLERS[q];
@@ -93,11 +93,11 @@ core.filterProblems = function(opts, cb) {
9393
});
9494
};
9595

96-
core.getProblem = function(keyword, cb) {
96+
core.getProblem = function(keyword, needTranslation, cb) {
9797
if (keyword.id)
98-
return core.next.getProblem(keyword, cb);
98+
return core.next.getProblem(keyword, needTranslation, cb);
9999

100-
this.getProblems(function(e, problems) {
100+
this.getProblems(needTranslation, function(e, problems) {
101101
if (e) return cb(e);
102102

103103
keyword = Number(keyword) || keyword;
@@ -106,7 +106,7 @@ core.getProblem = function(keyword, cb) {
106106
return x.id + '' === keyword + '' || x.fid + '' === keyword + '' || x.fid + '' === metaFid + '' || x.name === keyword || x.slug === keyword;
107107
});
108108
if (!problem) return cb('Problem not found!');
109-
core.next.getProblem(problem, cb);
109+
core.next.getProblem(problem, needTranslation, cb);
110110
});
111111
};
112112

lib/helper.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ const LANGS = [
5252
const h = {};
5353

5454
h.KEYS = {
55-
user: '../user',
56-
stat: '../stat',
57-
plugins: '../../plugins',
58-
problems: 'problems',
59-
problem: p => p.fid + '.' + p.slug + '.' + p.category
55+
user: '../user',
56+
stat: '../stat',
57+
plugins: '../../plugins',
58+
problems: 'problems',
59+
translation: 'translationConfig',
60+
problem: p => p.id + '.' + p.slug + '.' + p.category
6061
};
6162

6263
h.prettyState = function(state) {

lib/plugins/cache.js

+19-4
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,37 @@ var session = require('../session');
99

1010
const plugin = new Plugin(50, 'cache', '', 'Plugin to provide local cache.');
1111

12-
plugin.getProblems = function(cb) {
12+
// this function will clear all caches if needTranslation is different than stored
13+
// it will also store the new needTranslation into cache automatically
14+
function clearCacheIfTchanged(needTranslation) {
15+
const translationConfig = cache.get(h.KEYS.translation);
16+
if (!translationConfig || translationConfig['useEndpointTranslation'] != needTranslation) {
17+
// cache doesn't have the key => old cache version, need to update
18+
// or cache does have the key but it contains a different value
19+
cache.deleteAll();
20+
cache.set(h.KEYS.translation, { useEndpointTranslation: needTranslation });
21+
log.debug('cache cleared: -T option changed');
22+
}
23+
}
24+
25+
plugin.getProblems = function (needTranslation, cb) {
26+
clearCacheIfTchanged(needTranslation);
1327
const problems = cache.get(h.KEYS.problems);
1428
if (problems) {
1529
log.debug('cache hit: problems.json');
1630
return cb(null, problems);
1731
}
1832

19-
plugin.next.getProblems(function(e, problems) {
33+
plugin.next.getProblems(needTranslation, function(e, problems) {
2034
if (e) return cb(e);
2135

2236
cache.set(h.KEYS.problems, problems);
2337
return cb(null, problems);
2438
});
2539
};
2640

27-
plugin.getProblem = function(problem, cb) {
41+
plugin.getProblem = function (problem, needTranslation, cb) {
42+
clearCacheIfTchanged(needTranslation);
2843
const k = h.KEYS.problem(problem);
2944
const _problem = cache.get(k);
3045
if (_problem) {
@@ -42,7 +57,7 @@ plugin.getProblem = function(problem, cb) {
4257
}
4358
}
4459

45-
plugin.next.getProblem(problem, function(e, _problem) {
60+
plugin.next.getProblem(problem, needTranslation, function(e, _problem) {
4661
if (e) return cb(e);
4762

4863
plugin.saveProblem(_problem);

lib/plugins/company.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1511,8 +1511,8 @@ var TAGS = {
15111511
'1148': ['math']
15121512
};
15131513

1514-
plugin.getProblems = function(cb) {
1515-
plugin.next.getProblems(function(e, problems) {
1514+
plugin.getProblems = function(needTranslation, cb) {
1515+
plugin.next.getProblems(needTranslation, function(e, problems) {
15161516
if (e) return cb(e);
15171517

15181518
problems.forEach(function(problem) {

lib/plugins/leetcode.cn.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,29 @@ function checkError(e, resp, expectedStatus) {
7070
return e;
7171
}
7272

73-
plugin.getProblems = function(cb) {
74-
plugin.next.getProblems(function(e, problems) {
73+
// overloading getProblems here to make sure everything related
74+
// to listing out problems can have a chance to be translated.
75+
// NOTE: Details of the problem is translated inside leetcode.js
76+
plugin.getProblems = function (needTranslation, cb) {
77+
plugin.next.getProblems(needTranslation, function(e, problems) {
7578
if (e) return cb(e);
7679

77-
plugin.getProblemsTitle(function(e, titles) {
78-
if (e) return cb(e);
80+
if (needTranslation) {
81+
// only translate titles of the list if user requested
82+
plugin.getProblemsTitle(function (e, titles) {
83+
if (e) return cb(e);
7984

80-
problems.forEach(function(problem) {
81-
const title = titles[problem.id];
82-
if (title)
83-
problem.name = title;
84-
});
85+
problems.forEach(function (problem) {
86+
const title = titles[problem.id];
87+
if (title)
88+
problem.name = title;
89+
});
8590

91+
return cb(null, problems);
92+
});
93+
} else {
8694
return cb(null, problems);
87-
});
95+
}
8896
});
8997
};
9098

lib/plugins/leetcode.js

+5-11
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ plugin.init = function() {
5454
config.app = 'leetcode';
5555
};
5656

57-
plugin.getProblems = function(cb) {
57+
plugin.getProblems = function (needTranslation, cb) {
5858
log.debug('running leetcode.getProblems');
5959
let problems = [];
6060
const getCategory = function(category, queue, cb) {
@@ -117,7 +117,7 @@ plugin.getCategoryProblems = function(category, cb) {
117117
});
118118
};
119119

120-
plugin.getProblem = function(problem, cb) {
120+
plugin.getProblem = function(problem, needTranslation, cb) {
121121
log.debug('running leetcode.getProblem');
122122
const user = session.getUser();
123123
if (problem.locked && !user.paid) return cb('failed to load locked problem!');
@@ -161,7 +161,7 @@ plugin.getProblem = function(problem, cb) {
161161
problem.likes = q.likes;
162162
problem.dislikes = q.dislikes;
163163

164-
problem.desc = q.translatedContent ? q.translatedContent : q.content;
164+
problem.desc = (q.translatedContent && needTranslation) ? q.translatedContent : q.content;
165165

166166
problem.templates = JSON.parse(q.codeDefinition);
167167
problem.testcase = q.sampleTestCase;
@@ -534,15 +534,9 @@ plugin.login = function(user, cb) {
534534
};
535535

536536
function parseCookie(cookie, body, cb) {
537-
const isCN = config.app === 'leetcode.cn';
538537
const SessionPattern = /LEETCODE_SESSION=(.+?)(;|$)/;
539-
let csrfPattern;
540-
if (isCN) {
541-
csrfPattern = /name="csrfmiddlewaretoken" value="(.*?)"/;
542-
} else {
543-
csrfPattern = /csrftoken=(.+?)(;|$)/;
544-
}
545-
const reCsrfResult = csrfPattern.exec(isCN? body: cookie);
538+
const csrfPattern = /csrftoken=(.+?)(;|$)/;
539+
const reCsrfResult = csrfPattern.exec(cookie);
546540
const reSessionResult = SessionPattern.exec(cookie);
547541
if (reSessionResult === null || reCsrfResult === null) {
548542
return cb('invalid cookie?');

lib/plugins/solution.discuss.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ function getSolution(problem, lang, cb) {
7171
});
7272
}
7373

74-
plugin.getProblem = function(problem, cb) {
75-
plugin.next.getProblem(problem, function(e, problem) {
74+
plugin.getProblem = function(problem, needTranslation, cb) {
75+
plugin.next.getProblem(problem, needTranslation, function(e, problem) {
7676
if (e || !session.argv.solution) return cb(e, problem);
7777

7878
var lang = session.argv.lang;

0 commit comments

Comments
 (0)