linguist-js 2.3.2 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -0
- package/dist/helpers/walk-tree.js +14 -8
- package/dist/index.js +83 -50
- package/dist/types.d.ts +1 -0
- package/license.md +1 -1
- package/package.json +5 -5
- package/readme.md +14 -8
- package/dist/helpers/convert-glob.js +0 -11
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,7 @@ commander_1.program
|
|
|
26
26
|
.option('-I|--checkIgnored [bool]', 'Force the checking of gitignore files', true)
|
|
27
27
|
.option('-H|--checkHeuristics [bool]', 'Apply heuristics to ambiguous languages', true)
|
|
28
28
|
.option('-S|--checkShebang [bool]', 'Check shebang lines for explicit classification', true)
|
|
29
|
+
.option('-M|--checkModeline [bool]', 'Check modelines for explicit classification', true)
|
|
29
30
|
.helpOption(`-h|--help`, 'Display this help message')
|
|
30
31
|
.version(VERSION, '-v|--version', 'Display the installed version of linguist-js');
|
|
31
32
|
commander_1.program.parse(process.argv);
|
|
@@ -5,12 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const fs_1 = __importDefault(require("fs"));
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
let allFiles;
|
|
9
|
+
let allFolders;
|
|
10
10
|
/** Generate list of files in a directory. */
|
|
11
|
-
function walk(root, folders,
|
|
12
|
-
//
|
|
13
|
-
|
|
11
|
+
function walk(init, root, folders, gitignores, regexIgnores) {
|
|
12
|
+
// Initialise files and folders lists
|
|
13
|
+
if (init) {
|
|
14
|
+
allFiles = new Set();
|
|
15
|
+
allFolders = new Set();
|
|
16
|
+
}
|
|
14
17
|
// Walk tree of a folder
|
|
15
18
|
if (folders.length === 1) {
|
|
16
19
|
const folder = folders[0];
|
|
@@ -27,7 +30,10 @@ function walk(root, folders, ignored = []) {
|
|
|
27
30
|
// Create absolute path for disc operations
|
|
28
31
|
const path = path_1.default.resolve(root, file).replace(/\\/g, '/');
|
|
29
32
|
// Skip if nonexistant or ignored
|
|
30
|
-
|
|
33
|
+
const nonExistant = !fs_1.default.existsSync(path);
|
|
34
|
+
const isGitIgnored = gitignores.test(file.replace('./', '')).ignored;
|
|
35
|
+
const isRegexIgnored = regexIgnores.find(match => file.replace('./', '').match(match));
|
|
36
|
+
if (nonExistant || isGitIgnored || isRegexIgnored)
|
|
31
37
|
continue;
|
|
32
38
|
// Add absolute folder path to list
|
|
33
39
|
allFolders.add(path_1.default.resolve(folder).replace(/\\/g, '/'));
|
|
@@ -35,7 +41,7 @@ function walk(root, folders, ignored = []) {
|
|
|
35
41
|
if (file.endsWith('/')) {
|
|
36
42
|
// Recurse into subfolders
|
|
37
43
|
allFolders.add(path);
|
|
38
|
-
walk(root, [path],
|
|
44
|
+
walk(false, root, [path], gitignores, regexIgnores);
|
|
39
45
|
}
|
|
40
46
|
else {
|
|
41
47
|
// Add relative file path to list
|
|
@@ -46,7 +52,7 @@ function walk(root, folders, ignored = []) {
|
|
|
46
52
|
// Recurse into all folders
|
|
47
53
|
else {
|
|
48
54
|
for (const path of folders) {
|
|
49
|
-
walk(root, [path],
|
|
55
|
+
walk(false, root, [path], gitignores, regexIgnores);
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
// Return absolute files and folders lists
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
const fs_1 = __importDefault(require("fs"));
|
|
6
6
|
const path_1 = __importDefault(require("path"));
|
|
7
7
|
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
8
|
-
const
|
|
8
|
+
const ignore_1 = __importDefault(require("ignore"));
|
|
9
9
|
const common_path_prefix_1 = __importDefault(require("common-path-prefix"));
|
|
10
10
|
const binary_extensions_1 = __importDefault(require("binary-extensions"));
|
|
11
11
|
const isbinaryfile_1 = require("isbinaryfile");
|
|
@@ -13,10 +13,9 @@ const walk_tree_1 = __importDefault(require("./helpers/walk-tree"));
|
|
|
13
13
|
const load_data_1 = __importDefault(require("./helpers/load-data"));
|
|
14
14
|
const read_file_1 = __importDefault(require("./helpers/read-file"));
|
|
15
15
|
const convert_pcre_1 = __importDefault(require("./helpers/convert-pcre"));
|
|
16
|
-
const convert_glob_1 = __importDefault(require("./helpers/convert-glob"));
|
|
17
16
|
async function analyse(input, opts = {}) {
|
|
18
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
19
|
-
var
|
|
17
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
18
|
+
var _t, _u, _v;
|
|
20
19
|
const useRawContent = opts.fileContent !== undefined;
|
|
21
20
|
input = [input !== null && input !== void 0 ? input : []].flat();
|
|
22
21
|
opts.fileContent = [(_a = opts.fileContent) !== null && _a !== void 0 ? _a : []].flat();
|
|
@@ -25,10 +24,11 @@ async function analyse(input, opts = {}) {
|
|
|
25
24
|
const vendorData = await (0, load_data_1.default)('vendor.yml').then(js_yaml_1.default.load);
|
|
26
25
|
const docData = await (0, load_data_1.default)('documentation.yml').then(js_yaml_1.default.load);
|
|
27
26
|
const heuristicsData = await (0, load_data_1.default)('heuristics.yml').then(js_yaml_1.default.load);
|
|
28
|
-
const generatedData = await (0, load_data_1.default)('generated.rb').then(text => { var _a; return (_a = text.match(/(?<=name\.match\(\/).+?(?=(?<!\\)
|
|
27
|
+
const generatedData = await (0, load_data_1.default)('generated.rb').then(text => { var _a; return (_a = text.match(/(?<=name\.match\(\/).+?(?=(?<!\\)\/)/gm)) !== null && _a !== void 0 ? _a : []; });
|
|
29
28
|
const vendorPaths = [...vendorData, ...docData, ...generatedData];
|
|
30
29
|
// Setup main variables
|
|
31
30
|
const fileAssociations = {};
|
|
31
|
+
const definiteness = {};
|
|
32
32
|
const extensions = {};
|
|
33
33
|
const overrides = {};
|
|
34
34
|
const results = {
|
|
@@ -37,13 +37,18 @@ async function analyse(input, opts = {}) {
|
|
|
37
37
|
unknown: { count: 0, bytes: 0, extensions: {}, filenames: {} },
|
|
38
38
|
};
|
|
39
39
|
// Prepare list of ignored files
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
const gitignores = (0, ignore_1.default)();
|
|
41
|
+
const regexIgnores = [];
|
|
42
|
+
gitignores.add('/.git');
|
|
43
|
+
if (!opts.keepVendored)
|
|
44
|
+
regexIgnores.push(...vendorPaths.map(path => RegExp(path, 'i')));
|
|
45
|
+
if (opts.ignoredFiles)
|
|
46
|
+
gitignores.add(opts.ignoredFiles);
|
|
47
|
+
// Set a common root path so that vendor paths do not incorrectly match parent folders
|
|
48
|
+
const resolvedInput = input.map(path => path_1.default.resolve(path).replace(/\\/g, '/'));
|
|
49
|
+
const commonRoot = (input.length > 1 ? (0, common_path_prefix_1.default)(resolvedInput) : resolvedInput[0]).replace(/\/?$/, '');
|
|
50
|
+
const relPath = (file) => path_1.default.relative(commonRoot, file).replace(/\\/g, '/');
|
|
51
|
+
const unRelPath = (file) => path_1.default.resolve(commonRoot, file).replace(/\\/g, '/');
|
|
47
52
|
// Load file paths and folders
|
|
48
53
|
let files, folders;
|
|
49
54
|
if (useRawContent) {
|
|
@@ -53,15 +58,19 @@ async function analyse(input, opts = {}) {
|
|
|
53
58
|
}
|
|
54
59
|
else {
|
|
55
60
|
// Uses directory on disc
|
|
56
|
-
|
|
57
|
-
const resolvedInput = input.map(path => path_1.default.resolve(path).replace(/\\/g, '/'));
|
|
58
|
-
const commonRoot = (input.length > 1 ? (0, common_path_prefix_1.default)(resolvedInput) : resolvedInput[0]).replace(/\/?$/, '');
|
|
59
|
-
const data = (0, walk_tree_1.default)(commonRoot, input, ignoredFiles);
|
|
61
|
+
const data = (0, walk_tree_1.default)(true, commonRoot, input, gitignores, regexIgnores);
|
|
60
62
|
files = data.files;
|
|
61
63
|
folders = data.folders;
|
|
62
64
|
}
|
|
63
65
|
// Apply aliases
|
|
64
|
-
opts = {
|
|
66
|
+
opts = {
|
|
67
|
+
checkIgnored: !opts.quick,
|
|
68
|
+
checkAttributes: !opts.quick,
|
|
69
|
+
checkHeuristics: !opts.quick,
|
|
70
|
+
checkShebang: !opts.quick,
|
|
71
|
+
checkModeline: !opts.quick,
|
|
72
|
+
...opts
|
|
73
|
+
};
|
|
65
74
|
// Ignore specific languages
|
|
66
75
|
for (const lang of (_b = opts.ignoredLanguages) !== null && _b !== void 0 ? _b : []) {
|
|
67
76
|
for (const key in langData) {
|
|
@@ -71,40 +80,36 @@ async function analyse(input, opts = {}) {
|
|
|
71
80
|
}
|
|
72
81
|
}
|
|
73
82
|
}
|
|
74
|
-
// Load gitattributes
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const customText = [];
|
|
83
|
+
// Load gitignores and gitattributes
|
|
84
|
+
const customBinary = (0, ignore_1.default)();
|
|
85
|
+
const customText = (0, ignore_1.default)();
|
|
78
86
|
if (!useRawContent && opts.checkAttributes) {
|
|
79
87
|
for (const folder of folders) {
|
|
80
88
|
// Skip if folder is marked in gitattributes
|
|
81
|
-
if (
|
|
89
|
+
if (relPath(folder) && gitignores.ignores(relPath(folder)))
|
|
82
90
|
continue;
|
|
83
91
|
// Parse gitignores
|
|
84
92
|
const ignoresFile = path_1.default.join(folder, '.gitignore');
|
|
85
93
|
if (opts.checkIgnored && fs_1.default.existsSync(ignoresFile)) {
|
|
86
94
|
const ignoresData = await (0, read_file_1.default)(ignoresFile);
|
|
87
|
-
|
|
88
|
-
const ignoredPaths = ignoresList.map(path => (0, convert_glob_1.default)(path).source);
|
|
89
|
-
customIgnored.push(...ignoredPaths);
|
|
95
|
+
gitignores.add(ignoresData);
|
|
90
96
|
}
|
|
91
97
|
// Parse gitattributes
|
|
92
98
|
const attributesFile = path_1.default.join(folder, '.gitattributes');
|
|
93
99
|
if (opts.checkAttributes && fs_1.default.existsSync(attributesFile)) {
|
|
94
100
|
const attributesData = await (0, read_file_1.default)(attributesFile);
|
|
95
|
-
const relPathToRegex = (path) => (0, convert_glob_1.default)(path).source.substr(1).replace(folder, '');
|
|
96
101
|
// Explicit text/binary associations
|
|
97
102
|
const contentTypeMatches = attributesData.matchAll(/^(\S+).*?(-?binary|-?text)(?!=auto)/gm);
|
|
98
103
|
for (const [_line, path, type] of contentTypeMatches) {
|
|
99
104
|
if (['text', '-binary'].includes(type))
|
|
100
|
-
customText.
|
|
105
|
+
customText.add(path);
|
|
101
106
|
if (['-text', 'binary'].includes(type))
|
|
102
|
-
customBinary.
|
|
107
|
+
customBinary.add(path);
|
|
103
108
|
}
|
|
104
109
|
// Custom vendor options
|
|
105
110
|
const vendorMatches = attributesData.matchAll(/^(\S+).*[^-]linguist-(vendored|generated|documentation)(?!=false)/gm);
|
|
106
111
|
for (const [_line, path] of vendorMatches) {
|
|
107
|
-
|
|
112
|
+
gitignores.add(path);
|
|
108
113
|
}
|
|
109
114
|
// Custom file associations
|
|
110
115
|
const customLangMatches = attributesData.matchAll(/^(\S+).*[^-]linguist-language=(\S+)/gm);
|
|
@@ -115,17 +120,22 @@ async function analyse(input, opts = {}) {
|
|
|
115
120
|
if (overrideLang)
|
|
116
121
|
forcedLang = overrideLang[0];
|
|
117
122
|
}
|
|
118
|
-
const fullPath = folder +
|
|
123
|
+
const fullPath = relPath(folder) + '/' + path;
|
|
119
124
|
overrides[fullPath] = forcedLang;
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
// Check vendored files
|
|
125
|
-
if (!
|
|
130
|
+
if (!opts.keepVendored) {
|
|
126
131
|
// Filter out any files that match a vendor file path
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
if (useRawContent) {
|
|
133
|
+
files = gitignores.filter(files);
|
|
134
|
+
files = files.filter(file => !regexIgnores.find(match => match.test(file)));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
files = gitignores.filter(files.map(relPath)).map(unRelPath);
|
|
138
|
+
}
|
|
129
139
|
}
|
|
130
140
|
// Load all files and parse languages
|
|
131
141
|
const addResult = (file, result) => {
|
|
@@ -152,22 +162,40 @@ async function analyse(input, opts = {}) {
|
|
|
152
162
|
// Skip if file is unreadable
|
|
153
163
|
if (firstLine === null)
|
|
154
164
|
continue;
|
|
155
|
-
// Check
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
// Check first line for explicit classification
|
|
166
|
+
const hasShebang = opts.checkShebang && /^#!/.test(firstLine);
|
|
167
|
+
const hasModeline = opts.checkModeline && /-\*-|(syntax|filetype|ft)\s*=/.test(firstLine);
|
|
168
|
+
if (!opts.quick && (hasShebang || hasModeline)) {
|
|
169
|
+
const matches = [];
|
|
170
|
+
for (const [lang, data] of Object.entries(langData)) {
|
|
171
|
+
const langMatcher = (lang) => `\\b${lang.toLowerCase().replace(/\W/g, '\\$&')}(?![\\w#+*]|-\*-)`;
|
|
172
|
+
// Check for interpreter match
|
|
173
|
+
const matchesInterpretor = (_f = data.interpreters) === null || _f === void 0 ? void 0 : _f.some(interpreter => firstLine.match(`\\b${interpreter}\\b`));
|
|
174
|
+
// Check modeline declaration
|
|
175
|
+
const matchesLang = firstLine.toLowerCase().match(langMatcher(lang));
|
|
176
|
+
const matchesAlias = (_g = data.aliases) === null || _g === void 0 ? void 0 : _g.some(lang => firstLine.toLowerCase().match(langMatcher(lang)));
|
|
177
|
+
// Add language
|
|
178
|
+
if (opts.checkShebang && matchesInterpretor)
|
|
179
|
+
matches.push(lang);
|
|
180
|
+
if (opts.checkModeline && (matchesLang || matchesAlias))
|
|
181
|
+
matches.push(lang);
|
|
182
|
+
}
|
|
159
183
|
if (matches.length) {
|
|
160
184
|
// Add explicitly-identified language
|
|
161
|
-
const forcedLang = matches[0]
|
|
185
|
+
const forcedLang = matches[0];
|
|
162
186
|
addResult(file, forcedLang);
|
|
187
|
+
definiteness[file] = true;
|
|
188
|
+
continue;
|
|
163
189
|
}
|
|
164
190
|
}
|
|
165
191
|
// Check override for manual language classification
|
|
166
192
|
if (!useRawContent && !opts.quick && opts.checkAttributes) {
|
|
167
|
-
const
|
|
193
|
+
const isOverridden = (path) => (0, ignore_1.default)().add(path).ignores(relPath(file));
|
|
194
|
+
const match = overridesArray.find(item => isOverridden(item[0]));
|
|
168
195
|
if (match) {
|
|
169
196
|
const forcedLang = match[1];
|
|
170
197
|
addResult(file, forcedLang);
|
|
198
|
+
definiteness[file] = true;
|
|
171
199
|
continue;
|
|
172
200
|
}
|
|
173
201
|
}
|
|
@@ -175,7 +203,7 @@ async function analyse(input, opts = {}) {
|
|
|
175
203
|
let skipExts = false;
|
|
176
204
|
for (const lang in langData) {
|
|
177
205
|
// Check if filename is a match
|
|
178
|
-
const matchesName = (
|
|
206
|
+
const matchesName = (_h = langData[lang].filenames) === null || _h === void 0 ? void 0 : _h.some(name => path_1.default.basename(file.toLowerCase()) === name.toLowerCase());
|
|
179
207
|
if (matchesName) {
|
|
180
208
|
addResult(file, lang);
|
|
181
209
|
skipExts = true;
|
|
@@ -184,7 +212,7 @@ async function analyse(input, opts = {}) {
|
|
|
184
212
|
if (!skipExts)
|
|
185
213
|
for (const lang in langData) {
|
|
186
214
|
// Check if extension is a match
|
|
187
|
-
const matchesExt = (
|
|
215
|
+
const matchesExt = (_j = langData[lang].extensions) === null || _j === void 0 ? void 0 : _j.some(ext => file.toLowerCase().endsWith(ext.toLowerCase()));
|
|
188
216
|
if (matchesExt)
|
|
189
217
|
addResult(file, lang);
|
|
190
218
|
}
|
|
@@ -194,10 +222,15 @@ async function analyse(input, opts = {}) {
|
|
|
194
222
|
}
|
|
195
223
|
// Narrow down file associations to the best fit
|
|
196
224
|
for (const file in fileAssociations) {
|
|
225
|
+
// Skip if file has explicit association
|
|
226
|
+
if (definiteness[file]) {
|
|
227
|
+
results.files.results[file] = fileAssociations[file][0];
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
197
230
|
// Skip binary files
|
|
198
231
|
if (!useRawContent && !opts.keepBinary) {
|
|
199
|
-
const isCustomText = customText.
|
|
200
|
-
const isCustomBinary = customBinary.
|
|
232
|
+
const isCustomText = customText.ignores(relPath(file));
|
|
233
|
+
const isCustomBinary = customBinary.ignores(relPath(file));
|
|
201
234
|
const isBinaryExt = binary_extensions_1.default.some(ext => file.endsWith('.' + ext));
|
|
202
235
|
if (!isCustomText && (isCustomBinary || isBinaryExt || await (0, isbinaryfile_1.isBinaryFile)(file))) {
|
|
203
236
|
continue;
|
|
@@ -217,7 +250,7 @@ async function analyse(input, opts = {}) {
|
|
|
217
250
|
heuristic.language = heuristic.language[0];
|
|
218
251
|
}
|
|
219
252
|
// Make sure the results includes this language
|
|
220
|
-
const languageGroup = (
|
|
253
|
+
const languageGroup = (_k = langData[heuristic.language]) === null || _k === void 0 ? void 0 : _k.group;
|
|
221
254
|
const matchesLang = fileAssociations[file].includes(heuristic.language);
|
|
222
255
|
const matchesParent = languageGroup && fileAssociations[file].includes(languageGroup);
|
|
223
256
|
if (!matchesLang && !matchesParent)
|
|
@@ -230,7 +263,7 @@ async function analyse(input, opts = {}) {
|
|
|
230
263
|
if (heuristic.named_pattern)
|
|
231
264
|
normalise(heuristicsData.named_patterns[heuristic.named_pattern]);
|
|
232
265
|
// Check file contents and apply heuristic patterns
|
|
233
|
-
const fileContent = await (0, read_file_1.default)(file).catch(() => null);
|
|
266
|
+
const fileContent = opts.fileContent ? opts.fileContent[files.indexOf(file)] : await (0, read_file_1.default)(file).catch(() => null);
|
|
234
267
|
if (fileContent === null)
|
|
235
268
|
continue;
|
|
236
269
|
if (!patterns.length || patterns.some(pattern => (0, convert_pcre_1.default)(pattern).test(fileContent))) {
|
|
@@ -240,10 +273,10 @@ async function analyse(input, opts = {}) {
|
|
|
240
273
|
}
|
|
241
274
|
}
|
|
242
275
|
// If no heuristics, assign a language
|
|
243
|
-
(
|
|
276
|
+
(_l = (_t = results.files.results)[file]) !== null && _l !== void 0 ? _l : (_t[file] = fileAssociations[file][0]);
|
|
244
277
|
}
|
|
245
278
|
// Skip specified categories
|
|
246
|
-
if ((
|
|
279
|
+
if ((_m = opts.categories) === null || _m === void 0 ? void 0 : _m.length) {
|
|
247
280
|
const categories = ['data', 'markup', 'programming', 'prose'];
|
|
248
281
|
const hiddenCategories = categories.filter(cat => !opts.categories.includes(cat));
|
|
249
282
|
for (const [file, lang] of Object.entries(results.files.results)) {
|
|
@@ -275,21 +308,21 @@ async function analyse(input, opts = {}) {
|
|
|
275
308
|
for (const [file, lang] of Object.entries(results.files.results)) {
|
|
276
309
|
if (lang && !langData[lang])
|
|
277
310
|
continue;
|
|
278
|
-
const fileSize = (
|
|
311
|
+
const fileSize = (_q = (_p = (_o = opts.fileContent) === null || _o === void 0 ? void 0 : _o[files.indexOf(file)]) === null || _p === void 0 ? void 0 : _p.length) !== null && _q !== void 0 ? _q : fs_1.default.statSync(file).size;
|
|
279
312
|
results.files.bytes += fileSize;
|
|
280
313
|
// If no language found, add extension in other section
|
|
281
314
|
if (!lang) {
|
|
282
315
|
const ext = path_1.default.extname(file);
|
|
283
316
|
const unknownType = ext === '' ? 'filenames' : 'extensions';
|
|
284
317
|
const name = ext === '' ? path_1.default.basename(file) : ext;
|
|
285
|
-
(
|
|
318
|
+
(_r = (_u = results.unknown[unknownType])[name]) !== null && _r !== void 0 ? _r : (_u[name] = 0);
|
|
286
319
|
results.unknown[unknownType][name] += fileSize;
|
|
287
320
|
results.unknown.bytes += fileSize;
|
|
288
321
|
continue;
|
|
289
322
|
}
|
|
290
323
|
// Add language and bytes data to corresponding section
|
|
291
324
|
const { type } = langData[lang];
|
|
292
|
-
(
|
|
325
|
+
(_s = (_v = results.languages.results)[lang]) !== null && _s !== void 0 ? _s : (_v[lang] = { type, bytes: 0, color: langData[lang].color });
|
|
293
326
|
if (opts.childLanguages)
|
|
294
327
|
results.languages.results[lang].parent = langData[lang].group;
|
|
295
328
|
results.languages.results[lang].bytes += fileSize;
|
package/dist/types.d.ts
CHANGED
package/license.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linguist-js",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Analyse languages used in a folder. Powered by GitHub Linguist, although it doesn't need to be installed.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"prepare": "npm test && npm run perf",
|
|
14
14
|
"perf": "tsc && node test/perf",
|
|
15
|
-
"test": "tsc && node test/test"
|
|
15
|
+
"test": "tsc && node test/folder && echo --- && node test/unit"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"bin/",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"homepage": "https://github.com/Nixinova/Linguist#readme",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"binary-extensions": "^2.2.0",
|
|
40
|
-
"commander": "^9.
|
|
40
|
+
"commander": "^9.1.0",
|
|
41
41
|
"common-path-prefix": "^3.0.0",
|
|
42
42
|
"cross-fetch": "^3.1.5",
|
|
43
|
-
"
|
|
43
|
+
"ignore": "^5.2.0",
|
|
44
44
|
"isbinaryfile": "^4.0.8",
|
|
45
45
|
"js-yaml": "^4.1.0",
|
|
46
46
|
"node-cache": "^5.1.2"
|
|
@@ -50,6 +50,6 @@
|
|
|
50
50
|
"@types/js-yaml": "ts4.6",
|
|
51
51
|
"@types/node": "ts4.6",
|
|
52
52
|
"deep-object-diff": "^1.1.7",
|
|
53
|
-
"typescript": "~4.6.
|
|
53
|
+
"typescript": "~4.6.2"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/readme.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
[](https://github.com/Nixinova/Linguist/releases)
|
|
3
3
|
[](https://www.npmjs.com/package/linguist-js)
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# LinguistJS
|
|
6
6
|
|
|
7
7
|
Analyses the languages of all files in a given folder and collates the results.
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ Powered by [github-linguist](https://github.com/github/linguist), although it do
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
13
|
[Node.js](https://nodejs.org) must be installed to be able to use this.
|
|
14
|
-
|
|
14
|
+
LinguistJS is available [on npm](https://npmjs.com/package/linguist-js) as `linguist-js`.
|
|
15
15
|
|
|
16
16
|
Install locally using `npm install linguist-js` and import it into your code like so:
|
|
17
17
|
|
|
@@ -27,7 +27,7 @@ linguist --help
|
|
|
27
27
|
|
|
28
28
|
## Usage
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
LinguistJS contains one function which analyses a given folder.
|
|
31
31
|
|
|
32
32
|
As an example, take the following file structure:
|
|
33
33
|
|
|
@@ -40,7 +40,7 @@ As an example, take the following file structure:
|
|
|
40
40
|
| no-lang 10B
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
Running
|
|
43
|
+
Running LinguistJS on this folder will return the following JSON:
|
|
44
44
|
|
|
45
45
|
```json
|
|
46
46
|
{
|
|
@@ -78,7 +78,7 @@ Running Linguist on this folder will return the following JSON:
|
|
|
78
78
|
|
|
79
79
|
- File paths in the output use only forward slashes as delimiters, even on Windows.
|
|
80
80
|
- This tool does not work when offline.
|
|
81
|
-
- Do not rely on any language classification output from
|
|
81
|
+
- Do not rely on any language classification output from LinguistJS being unchanged between runs.
|
|
82
82
|
Language data is fetched each run from the latest classifications of [`github-linguist`](https://github.com/github/linguist).
|
|
83
83
|
This data is subject to change at any time and may change the results of a run even when using the same version of Linguist.
|
|
84
84
|
|
|
@@ -97,7 +97,6 @@ const { files, languages, unknown } = linguist(folder, options);
|
|
|
97
97
|
Analyse the language of all files found in a folder.
|
|
98
98
|
- `entry` (optional; string or string array):
|
|
99
99
|
The folder(s) to analyse (defaults to `./`).
|
|
100
|
-
Analyse multiple folders using the syntax `"{folder1,folder2,...}"`.
|
|
101
100
|
- `opts` (optional; object):
|
|
102
101
|
An object containing analyser options.
|
|
103
102
|
- `fileContent` (string or string array):
|
|
@@ -113,21 +112,26 @@ const { files, languages, unknown } = linguist(folder, options);
|
|
|
113
112
|
Whether to display sub-languages instead of their parents when possible (defaults to `false`).
|
|
114
113
|
- `quick` (boolean):
|
|
115
114
|
Whether to skip complex language analysis such as the checking of heuristics and gitattributes statements (defaults to `false`).
|
|
116
|
-
Alias for `checkAttributes:false, checkIgnored:false, checkHeuristics:false, checkShebang:false`.
|
|
115
|
+
Alias for `checkAttributes:false, checkIgnored:false, checkHeuristics:false, checkShebang:false, checkModeline:false`.
|
|
117
116
|
- `keepVendored` (boolean):
|
|
118
117
|
Whether to keep vendored files (dependencies, etc) (defaults to `false`).
|
|
118
|
+
Does nothing when `fileContent` is set.
|
|
119
119
|
- `keepBinary` (boolean):
|
|
120
120
|
Whether binary files should be included in the output (defaults to `false`).
|
|
121
121
|
- `relativePaths` (boolean):
|
|
122
122
|
Change the absolute file paths in the output to be relative to the current working directory (defaults to `false`).
|
|
123
123
|
- `checkAttributes` (boolean):
|
|
124
124
|
Force the checking of `.gitattributes` files (defaults to `true` unless `quick` is set).
|
|
125
|
+
Does nothing when `fileContent` is set.
|
|
125
126
|
- `checkIgnored` (boolean):
|
|
126
127
|
Force the checking of `.gitignore` files (defaults to `true` unless `quick` is set).
|
|
128
|
+
Does nothing when `fileContent` is set.
|
|
127
129
|
- `checkHeuristics` (boolean):
|
|
128
130
|
Apply heuristics to ambiguous languages (defaults to `true` unless `quick` is set).
|
|
129
131
|
- `checkShebang` (boolean):
|
|
130
132
|
Check shebang (`#!`) lines for explicit language classification (defaults to `true` unless `quick` is set).
|
|
133
|
+
- `checkModeline` (boolean):
|
|
134
|
+
Check modelines for explicit language classification (defaults to `true` unless `quick` is set).
|
|
131
135
|
|
|
132
136
|
### Command-line
|
|
133
137
|
|
|
@@ -155,7 +159,7 @@ linguist --help
|
|
|
155
159
|
Requires `--json` to be specified.
|
|
156
160
|
- `--quick`:
|
|
157
161
|
Whether to skip the checking of `.gitattributes` and `.gitignore` files for manual language classifications.
|
|
158
|
-
Alias for `--checkAttributes=false --checkIgnored=false --checkHeuristics=false --checkShebang=false`.
|
|
162
|
+
Alias for `--checkAttributes=false --checkIgnored=false --checkHeuristics=false --checkShebang=false --checkModeline=false`.
|
|
159
163
|
- `--keepVendored`:
|
|
160
164
|
Whether to include vendored files (auto-generated files, dependencies folder, etc).
|
|
161
165
|
- `--keepBinary`:
|
|
@@ -170,6 +174,8 @@ linguist --help
|
|
|
170
174
|
Apply heuristics to ambiguous languages (use alongside `--quick` to overwrite).
|
|
171
175
|
- `--checkShebang`:
|
|
172
176
|
Check shebang (`#!`) lines for explicit classification (use alongside `--quick` to overwrite).
|
|
177
|
+
- `--checkModeline`:
|
|
178
|
+
Check modelines for explicit classification (use alongside `--quick` to overwrite).
|
|
173
179
|
- `--help`:
|
|
174
180
|
Display a help message.
|
|
175
181
|
- `--version`:
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const glob_to_regexp_1 = __importDefault(require("glob-to-regexp"));
|
|
7
|
-
function parseGitGlob(path) {
|
|
8
|
-
const globPath = `**/${path}`.replace(/\\/g, '/').replace(/\[:(space|digit):\]/g, (_, val) => `\\${val[0]}`);
|
|
9
|
-
return (0, glob_to_regexp_1.default)(globPath, { globstar: true, extended: true });
|
|
10
|
-
}
|
|
11
|
-
exports.default = parseGitGlob;
|