Skip to content

Commit 76e9352

Browse files
SethFalcovitorhcl
andcommitted
chore: add jsdoc types and typechecking
Co-authored-by: Vitor Henrique <[email protected]>
1 parent 9fd7b2f commit 76e9352

23 files changed

+315
-186
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ jobs:
3737
node-version: ${{ matrix.node-version }}
3838

3939
- run: npm ci
40+
- run: npm run typecheck
4041
- run: npm run test:all

lib/cache.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class Cache {
1515
}
1616

1717
/**
18-
* Fetch stats from the cache folder.
18+
* Fetch stats from the cache folder for getting its last modified time
19+
* (mtime).
20+
*
1921
* @returns {Promise<any>} A promise with the stats of the cache folder.
2022
*/
2123
lastUpdated() {
@@ -24,8 +26,8 @@ class Cache {
2426

2527
/**
2628
* Fetch a page from cache using preferred language and preferred platform.
27-
* @param page {} A
28-
* @returns {Promise<unknown>}
29+
* @param {string} page
30+
* @returns {Promise<string>}
2931
*/
3032
getPage(page) {
3133
let preferredPlatform = platforms.getPreferredPlatformFolder(this.config);
@@ -52,8 +54,10 @@ class Cache {
5254
}
5355

5456
/**
55-
* Update the cache folder and returns the English entries.
56-
* @returns {Promise<any>} A promise with the index.
57+
* Update the cache folder using a temporary directory, update the index and
58+
* return it.
59+
*
60+
* @returns {Promise<any>} The index.
5761
*/
5862
update() {
5963
// Temporary folder path: /tmp/tldr/{randomName}
@@ -82,7 +86,6 @@ class Cache {
8286
index.rebuildPagesIndex(),
8387
]);
8488
})
85-
8689
.then(([_, shortIndex]) => {
8790
return shortIndex;
8891
});

lib/completion.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Completion {
2222

2323
appendScript(script) {
2424
const rcFilePath = this.getFilePath();
25-
return new Promise((resolve, reject) => {
25+
return new Promise((/** @type {(v?: never) => void} */ resolve, reject) => {
2626
fs.appendFile(rcFilePath, `\n${script}\n`, (err) => {
2727
if (err) {
2828
reject((new CompletionScriptError(`Error appending to ${rcFilePath}: ${err.message}`)));
@@ -79,4 +79,4 @@ fi
7979
}
8080
}
8181

82-
module.exports = Completion;
82+
module.exports = Completion;

lib/config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ exports.get = () => {
1111
const DEFAULT = path.join(__dirname, '..', 'config.json');
1212
const CUSTOM = path.join(osHomedir(), '.tldrrc');
1313

14-
let defaultConfig = JSON.parse(fs.readFileSync(DEFAULT));
14+
let defaultConfig = JSON.parse(fs.readFileSync(DEFAULT, 'utf-8'));
1515
defaultConfig.cache = path.join(osHomedir(), '.tldr');
1616

1717
let customConfig = {};
1818
try {
19-
customConfig = JSON.parse(fs.readFileSync(CUSTOM));
19+
customConfig = JSON.parse(fs.readFileSync(CUSTOM, 'utf-8'));
2020
} catch (ex) {
2121
if (ex instanceof SyntaxError) {
2222
throw new Error('The content of .tldrrc is not a valid JSON object:\n' + ex);

lib/index.js

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ let shortIndex = null;
1010
const pagesPath = path.join(config.get().cache, 'cache');
1111
const shortIndexFile = path.join(pagesPath, 'shortIndex.json');
1212

13+
/**
14+
* @param {string} page
15+
* @param {string|undefined} preferredPlatform
16+
* @param {string} preferredLanguage
17+
* @returns {Promise<?string>}
18+
*/
1319
function findPage(page, preferredPlatform, preferredLanguage) {
1420
// Load the index
1521
return getShortIndex()
@@ -33,7 +39,7 @@ function findPage(page, preferredPlatform, preferredLanguage) {
3339
ll = preferredLanguage.substring(0, preferredLanguage.indexOf('_'));
3440
}
3541
if (!hasLang(targets, preferredLanguage)) {
36-
preferredLanguage = ll;
42+
preferredLanguage = /** @type {string} */ (ll);
3743
}
3844

3945
// Page resolution logic:
@@ -93,7 +99,8 @@ function hasLang(targets, preferredLanguage) {
9399

94100
/**
95101
* Check if a page is in the index.
96-
* @returns {boolean} A boolean that indicates if the page is present.
102+
*
103+
* @returns {boolean} The presence of the page in the index.
97104
*/
98105
function hasPage(page) {
99106
// hasPage is always called after the index is created,
@@ -106,23 +113,21 @@ function hasPage(page) {
106113
}
107114

108115
/**
109-
* Return all commands available in the local cache.
110-
* @returns {Promise<string[]>} A promise with the commands from cache.
116+
* Return all commands available in the local index.
117+
* @returns {Promise<string[]>} A promise with the commands from the index.
111118
*/
112119
function commands() {
113120
return getShortIndex().then((idx) => {
114121
return Object.keys(idx).sort();
115122
});
116123
}
117124

118-
// Return all commands for a given platform.
119-
// P.S. - The platform 'common' is always included.
120125
/**
121-
* Return all commands for a given platform.
126+
* Return all commands for a given platform. The 'common' platform is always
127+
* included.
122128
*
123-
* The 'common' platform is always included.
124-
* @param platform {string} The platform.
125-
* @returns {Promise<string[]>} A promise with the commands for a given platform.
129+
* @param {string} platform The desired platform.
130+
* @returns {Promise<string[]>} The commands for a given platform.
126131
*/
127132
function commandsFor(platform) {
128133
return getShortIndex()
@@ -171,9 +176,9 @@ function rebuildPagesIndex() {
171176
}
172177

173178
/**
174-
* Return the index.
179+
* Return the index, that contains all available commands with their target os
180+
* and platform. If the index is not loaded, read the file and load it.
175181
*
176-
* If the index is not loaded, read the file and load it.
177182
* @returns {Promise<any>} The index entries.
178183
*/
179184
function getShortIndex() {

lib/parser.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function unhtml(text){
1717

1818
exports.parse = (markdown) => {
1919
// Creating the page structure
20+
/** @type {Required<import('./tldr').TldrPage> & { examples: any[] }} */
2021
let page = {
2122
name: '',
2223
description: '',

lib/remote.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const axios = require('axios');
88

99
/**
1010
* Download the zip file from GitHub and extract it to folder.
11-
* @param path {string} Path to destination folder.
11+
* @param {string} loc Path to a directory on disk.
12+
* @param {string} lang Language/locale code.
1213
* @returns {Promise<void>} A promise when the operation is completed.
1314
*/
1415
exports.download = (loc, lang) => {
@@ -25,7 +26,7 @@ exports.download = (loc, lang) => {
2526
headers: { 'User-Agent' : 'tldr-node-client' },
2627
timeout: REQUEST_TIMEOUT,
2728
}).then((response) => {
28-
return new Promise((resolve, reject) => {
29+
return new Promise((/** @type {(v?: never) => void} */ resolve, reject) => {
2930
let fileName = path.join(loc, 'download_' + lang + '.zip');
3031

3132
const writer = fs.createWriteStream(fileName);

lib/render.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
const Theme = require('./theme');
44
const he = require('he'); // Import the 'he' library
55

6-
// The page structure is passed to this function, and then the theme is applied
7-
// to different parts of the page and rendered to the console
6+
/**
7+
* Page structure is passed to this function, and then the theme is applied to
8+
* different parts of the page and rendered to the console.
9+
*
10+
* @param {import('./tldr').TldrPage} page
11+
* @param {any} config
12+
* @returns {string|void}
13+
*/
814
exports.toANSI = (page, config) => {
915
// Creating the theme object
1016
let themeOptions = config.themes[config.theme];

lib/search.js

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,53 @@ const utils = require('./utils');
99
const index = require('./index');
1010
const platforms = require('./platforms');
1111

12+
/**
13+
* @typedef {object} Corpus
14+
* @property {Record<string, Record<string, number>>} fileWords
15+
* @property {Record<string, number>} fileLengths
16+
* @property {Record<string, string[]>} invertedIndex
17+
* @property {any} allTokens
18+
* @property {Record<string, Record<string, number>>} tfidf
19+
*
20+
* @typedef {object} Query
21+
* @property {?string} raw
22+
* @property {?string[]} tokens
23+
* @property {Record<string, number>} frequency
24+
* @property {Record<string, number>} score
25+
* @property {QueryRank[]} ranks
26+
*
27+
* @typedef {object} QueryRank
28+
* @property {string} file
29+
* @property {number} score
30+
*/
31+
1232
const CACHE_FOLDER = path.join(config.get().cache, 'cache');
1333

1434
const filepath = CACHE_FOLDER + '/search-corpus.json';
1535

16-
let corpus = {};
17-
18-
corpus.fileWords = {};
19-
corpus.fileLengths = {};
20-
corpus.invertedIndex = {};
21-
corpus.allTokens = new Set();
22-
corpus.tfidf = {};
2336

24-
let query = {};
37+
/** @type {Corpus} */
38+
let corpus = {
39+
fileWords: {},
40+
fileLengths: {},
41+
invertedIndex: {},
42+
allTokens: new Set(),
43+
tfidf: {},
44+
};
2545

26-
query.raw = null;
27-
query.tokens = null;
28-
query.frequency = {};
29-
query.score = {};
30-
query.ranks = [];
46+
/** @type {Query} */
47+
let query = {
48+
raw: null,
49+
tokens: null,
50+
frequency: {},
51+
score: {},
52+
ranks: [],
53+
};
3154

55+
/**
56+
* @param {string} data
57+
* @returns {string[]}
58+
*/
3259
let getTokens = (data) => {
3360
let tokenizer = new natural.WordTokenizer();
3461
let tokens = tokenizer.tokenize(data);
@@ -139,6 +166,9 @@ let readCorpus = () => {
139166
});
140167
};
141168

169+
/**
170+
* @param {string} rawquery
171+
*/
142172
let processQuery = (rawquery) => {
143173
query.raw = rawquery;
144174
query.tokens = getTokens(rawquery);
@@ -156,10 +186,9 @@ let processQuery = (rawquery) => {
156186
query.score = {};
157187
query.tokens.forEach((word) => {
158188
if (corpus.invertedIndex[word]) {
159-
let logbase = 10;
160189
let df = corpus.invertedIndex[word].length;
161-
let idf = Math.log(numberOfFiles / df, logbase);
162-
let wordWeight = idf * (1 + Math.log(query.frequency[word], logbase));
190+
let idf = Math.log10(numberOfFiles / df);
191+
let wordWeight = idf * (1 + Math.log10(query.frequency[word]));
163192
corpus.invertedIndex[word].forEach((file) => {
164193
let fileWeight = corpus.tfidf[file][word];
165194
if (query.score[file]) {
@@ -209,7 +238,7 @@ exports.printResults = (results, config) => {
209238
outputs.add(output);
210239
});
211240

212-
console.log('Searching for:', query.raw.trim());
241+
console.log('Searching for:', /** @type {string} */ (query.raw).trim());
213242
console.log();
214243
Array.from(outputs).forEach((elem) => {
215244
console.log(elem);
@@ -220,7 +249,7 @@ exports.printResults = (results, config) => {
220249
};
221250

222251
exports.createIndex = () => {
223-
return utils.glob(CACHE_FOLDER + '/pages/**/*.md', {})
252+
return utils.glob(CACHE_FOLDER + '/pages/**/*.md')
224253
.then((files) => {
225254
let promises = [];
226255
files.forEach((file) => {
@@ -246,6 +275,10 @@ exports.createIndex = () => {
246275
});
247276
};
248277

278+
/**
279+
* @param {string} rawquery
280+
* @returns
281+
*/
249282
exports.getResults = (rawquery) => {
250283
query.ranks = [];
251284
return readCorpus()

0 commit comments

Comments
 (0)