linguist-js 2.4.0 → 2.4.1
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/helpers/walk-tree.js +7 -6
- package/dist/index.js +37 -34
- package/license.md +1 -1
- package/package.json +2 -2
- package/readme.md +1 -2
- package/dist/helpers/convert-glob.js +0 -11
|
@@ -8,9 +8,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const allFiles = new Set();
|
|
9
9
|
const allFolders = new Set();
|
|
10
10
|
/** Generate list of files in a directory. */
|
|
11
|
-
function walk(root, folders,
|
|
12
|
-
// Switch out paths that expect being in root
|
|
13
|
-
ignored = ignored.map(match => match.replace(/^\^/, '^\\./'));
|
|
11
|
+
function walk(root, folders, gitignores, regexIgnores) {
|
|
14
12
|
// Walk tree of a folder
|
|
15
13
|
if (folders.length === 1) {
|
|
16
14
|
const folder = folders[0];
|
|
@@ -27,7 +25,10 @@ function walk(root, folders, ignored = []) {
|
|
|
27
25
|
// Create absolute path for disc operations
|
|
28
26
|
const path = path_1.default.resolve(root, file).replace(/\\/g, '/');
|
|
29
27
|
// Skip if nonexistant or ignored
|
|
30
|
-
|
|
28
|
+
const nonExistant = !fs_1.default.existsSync(path);
|
|
29
|
+
const isGitIgnored = gitignores.test(file.replace('./', '')).ignored;
|
|
30
|
+
const isRegexIgnored = regexIgnores.find(match => file.replace('./', '').match(match));
|
|
31
|
+
if (nonExistant || isGitIgnored || isRegexIgnored)
|
|
31
32
|
continue;
|
|
32
33
|
// Add absolute folder path to list
|
|
33
34
|
allFolders.add(path_1.default.resolve(folder).replace(/\\/g, '/'));
|
|
@@ -35,7 +36,7 @@ function walk(root, folders, ignored = []) {
|
|
|
35
36
|
if (file.endsWith('/')) {
|
|
36
37
|
// Recurse into subfolders
|
|
37
38
|
allFolders.add(path);
|
|
38
|
-
walk(root, [path],
|
|
39
|
+
walk(root, [path], gitignores, regexIgnores);
|
|
39
40
|
}
|
|
40
41
|
else {
|
|
41
42
|
// Add relative file path to list
|
|
@@ -46,7 +47,7 @@ function walk(root, folders, ignored = []) {
|
|
|
46
47
|
// Recurse into all folders
|
|
47
48
|
else {
|
|
48
49
|
for (const path of folders) {
|
|
49
|
-
walk(root, [path],
|
|
50
|
+
walk(root, [path], gitignores, regexIgnores);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
// 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,7 +13,6 @@ 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
17
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
19
18
|
var _t, _u, _v;
|
|
@@ -25,7 +24,7 @@ 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 = {};
|
|
@@ -38,13 +37,18 @@ async function analyse(input, opts = {}) {
|
|
|
38
37
|
unknown: { count: 0, bytes: 0, extensions: {}, filenames: {} },
|
|
39
38
|
};
|
|
40
39
|
// Prepare list of ignored files
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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, '/');
|
|
48
52
|
// Load file paths and folders
|
|
49
53
|
let files, folders;
|
|
50
54
|
if (useRawContent) {
|
|
@@ -54,10 +58,7 @@ async function analyse(input, opts = {}) {
|
|
|
54
58
|
}
|
|
55
59
|
else {
|
|
56
60
|
// Uses directory on disc
|
|
57
|
-
|
|
58
|
-
const resolvedInput = input.map(path => path_1.default.resolve(path).replace(/\\/g, '/'));
|
|
59
|
-
const commonRoot = (input.length > 1 ? (0, common_path_prefix_1.default)(resolvedInput) : resolvedInput[0]).replace(/\/?$/, '');
|
|
60
|
-
const data = (0, walk_tree_1.default)(commonRoot, input, ignoredFiles);
|
|
61
|
+
const data = (0, walk_tree_1.default)(commonRoot, input, gitignores, regexIgnores);
|
|
61
62
|
files = data.files;
|
|
62
63
|
folders = data.folders;
|
|
63
64
|
}
|
|
@@ -79,40 +80,36 @@ async function analyse(input, opts = {}) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
|
-
// Load gitattributes
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const customText = [];
|
|
83
|
+
// Load gitignores and gitattributes
|
|
84
|
+
const customBinary = (0, ignore_1.default)();
|
|
85
|
+
const customText = (0, ignore_1.default)();
|
|
86
86
|
if (!useRawContent && opts.checkAttributes) {
|
|
87
87
|
for (const folder of folders) {
|
|
88
88
|
// Skip if folder is marked in gitattributes
|
|
89
|
-
if (
|
|
89
|
+
if (relPath(folder) && gitignores.test(relPath(folder)).ignored)
|
|
90
90
|
continue;
|
|
91
91
|
// Parse gitignores
|
|
92
92
|
const ignoresFile = path_1.default.join(folder, '.gitignore');
|
|
93
93
|
if (opts.checkIgnored && fs_1.default.existsSync(ignoresFile)) {
|
|
94
94
|
const ignoresData = await (0, read_file_1.default)(ignoresFile);
|
|
95
|
-
|
|
96
|
-
const ignoredPaths = ignoresList.map(path => (0, convert_glob_1.default)(path).source);
|
|
97
|
-
customIgnored.push(...ignoredPaths);
|
|
95
|
+
gitignores.add(ignoresData);
|
|
98
96
|
}
|
|
99
97
|
// Parse gitattributes
|
|
100
98
|
const attributesFile = path_1.default.join(folder, '.gitattributes');
|
|
101
99
|
if (opts.checkAttributes && fs_1.default.existsSync(attributesFile)) {
|
|
102
100
|
const attributesData = await (0, read_file_1.default)(attributesFile);
|
|
103
|
-
const relPathToRegex = (path) => (0, convert_glob_1.default)(path).source.substr(1).replace(folder, '');
|
|
104
101
|
// Explicit text/binary associations
|
|
105
102
|
const contentTypeMatches = attributesData.matchAll(/^(\S+).*?(-?binary|-?text)(?!=auto)/gm);
|
|
106
103
|
for (const [_line, path, type] of contentTypeMatches) {
|
|
107
104
|
if (['text', '-binary'].includes(type))
|
|
108
|
-
customText.
|
|
105
|
+
customText.add(path);
|
|
109
106
|
if (['-text', 'binary'].includes(type))
|
|
110
|
-
customBinary.
|
|
107
|
+
customBinary.add(path);
|
|
111
108
|
}
|
|
112
109
|
// Custom vendor options
|
|
113
110
|
const vendorMatches = attributesData.matchAll(/^(\S+).*[^-]linguist-(vendored|generated|documentation)(?!=false)/gm);
|
|
114
111
|
for (const [_line, path] of vendorMatches) {
|
|
115
|
-
|
|
112
|
+
gitignores.add(path);
|
|
116
113
|
}
|
|
117
114
|
// Custom file associations
|
|
118
115
|
const customLangMatches = attributesData.matchAll(/^(\S+).*[^-]linguist-language=(\S+)/gm);
|
|
@@ -123,17 +120,22 @@ async function analyse(input, opts = {}) {
|
|
|
123
120
|
if (overrideLang)
|
|
124
121
|
forcedLang = overrideLang[0];
|
|
125
122
|
}
|
|
126
|
-
const fullPath = folder +
|
|
123
|
+
const fullPath = relPath(folder) + '/' + path;
|
|
127
124
|
overrides[fullPath] = forcedLang;
|
|
128
125
|
}
|
|
129
126
|
}
|
|
130
127
|
}
|
|
131
128
|
}
|
|
132
129
|
// Check vendored files
|
|
133
|
-
if (!
|
|
130
|
+
if (!opts.keepVendored) {
|
|
134
131
|
// Filter out any files that match a vendor file path
|
|
135
|
-
|
|
136
|
-
|
|
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
|
+
}
|
|
137
139
|
}
|
|
138
140
|
// Load all files and parse languages
|
|
139
141
|
const addResult = (file, result) => {
|
|
@@ -166,7 +168,7 @@ async function analyse(input, opts = {}) {
|
|
|
166
168
|
if (!opts.quick && (hasShebang || hasModeline)) {
|
|
167
169
|
const matches = [];
|
|
168
170
|
for (const [lang, data] of Object.entries(langData)) {
|
|
169
|
-
const langMatcher = (lang) => `\\b${lang.toLowerCase().replace(/\W/g, '\\$&')}\\
|
|
171
|
+
const langMatcher = (lang) => `\\b${lang.toLowerCase().replace(/\W/g, '\\$&')}(?![\\w#+*]|-\*-)`;
|
|
170
172
|
// Check for interpreter match
|
|
171
173
|
const matchesInterpretor = (_f = data.interpreters) === null || _f === void 0 ? void 0 : _f.some(interpreter => firstLine.match(`\\b${interpreter}\\b`));
|
|
172
174
|
// Check modeline declaration
|
|
@@ -188,7 +190,8 @@ async function analyse(input, opts = {}) {
|
|
|
188
190
|
}
|
|
189
191
|
// Check override for manual language classification
|
|
190
192
|
if (!useRawContent && !opts.quick && opts.checkAttributes) {
|
|
191
|
-
const
|
|
193
|
+
const isOverridden = (path) => (0, ignore_1.default)().add(path).test(relPath(file)).ignored;
|
|
194
|
+
const match = overridesArray.find(item => isOverridden(item[0]));
|
|
192
195
|
if (match) {
|
|
193
196
|
const forcedLang = match[1];
|
|
194
197
|
addResult(file, forcedLang);
|
|
@@ -226,8 +229,8 @@ async function analyse(input, opts = {}) {
|
|
|
226
229
|
}
|
|
227
230
|
// Skip binary files
|
|
228
231
|
if (!useRawContent && !opts.keepBinary) {
|
|
229
|
-
const isCustomText = customText.
|
|
230
|
-
const isCustomBinary = customBinary.
|
|
232
|
+
const isCustomText = customText.test(relPath(file)).ignored;
|
|
233
|
+
const isCustomBinary = customBinary.test(relPath(file)).ignored;
|
|
231
234
|
const isBinaryExt = binary_extensions_1.default.some(ext => file.endsWith('.' + ext));
|
|
232
235
|
if (!isCustomText && (isCustomBinary || isBinaryExt || await (0, isbinaryfile_1.isBinaryFile)(file))) {
|
|
233
236
|
continue;
|
package/license.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linguist-js",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
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": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"commander": "^9.0.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"
|
package/readme.md
CHANGED
|
@@ -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):
|
|
@@ -160,7 +159,7 @@ linguist --help
|
|
|
160
159
|
Requires `--json` to be specified.
|
|
161
160
|
- `--quick`:
|
|
162
161
|
Whether to skip the checking of `.gitattributes` and `.gitignore` files for manual language classifications.
|
|
163
|
-
Alias for `--checkAttributes=false --checkIgnored=false --checkHeuristics=false --
|
|
162
|
+
Alias for `--checkAttributes=false --checkIgnored=false --checkHeuristics=false --checkShebang=false --checkModeline=false`.
|
|
164
163
|
- `--keepVendored`:
|
|
165
164
|
Whether to include vendored files (auto-generated files, dependencies folder, etc).
|
|
166
165
|
- `--keepBinary`:
|
|
@@ -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;
|