linguist-js 2.2.1 → 2.3.0

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 CHANGED
@@ -54,7 +54,7 @@ if (args.analyze)
54
54
  const data = await (0, index_1.default)(root, args);
55
55
  const { files, languages, unknown } = data;
56
56
  // Get file count
57
- let totalFiles = (0, walk_tree_1.default)(root).files.length;
57
+ const totalFiles = (0, walk_tree_1.default)(root).files.length;
58
58
  // Print output
59
59
  if (!args.json) {
60
60
  const sortedEntries = Object.entries(languages.results).sort((a, b) => a[1].bytes < b[1].bytes ? +1 : -1);
package/dist/index.js CHANGED
@@ -14,8 +14,8 @@ const read_file_1 = __importDefault(require("./helpers/read-file"));
14
14
  const convert_pcre_1 = __importDefault(require("./helpers/convert-pcre"));
15
15
  const convert_glob_1 = __importDefault(require("./helpers/convert-glob"));
16
16
  async function analyse(input, opts = {}) {
17
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
18
- var _k, _l, _m;
17
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
18
+ var _r, _s, _t;
19
19
  const langData = await (0, load_data_1.default)('languages.yml').then(js_yaml_1.default.load);
20
20
  const vendorData = await (0, load_data_1.default)('vendor.yml').then(js_yaml_1.default.load);
21
21
  const heuristicsData = await (0, load_data_1.default)('heuristics.yml').then(js_yaml_1.default.load);
@@ -34,7 +34,16 @@ async function analyse(input, opts = {}) {
34
34
  opts.keepVendored ? [] : vendorData.map(path => RegExp(path)),
35
35
  (_b = (_a = opts.ignoredFiles) === null || _a === void 0 ? void 0 : _a.map(path => (0, glob_to_regexp_1.default)('*' + path + '*', { extended: true }))) !== null && _b !== void 0 ? _b : [],
36
36
  ].flat();
37
- let { files, folders } = (0, walk_tree_1.default)(input !== null && input !== void 0 ? input : '.', ignoredFiles);
37
+ let files, folders;
38
+ if (opts.fileContent) {
39
+ opts.fileContent = Array.isArray(opts.fileContent) ? opts.fileContent : [opts.fileContent];
40
+ files = [`${input}`];
41
+ folders = [''];
42
+ }
43
+ else {
44
+ const data = (0, walk_tree_1.default)(input !== null && input !== void 0 ? input : '.', ignoredFiles);
45
+ ({ files, folders } = data);
46
+ }
38
47
  // Apply aliases
39
48
  opts = { checkIgnored: !opts.quick, checkAttributes: !opts.quick, checkHeuristics: !opts.quick, checkShebang: !opts.quick, ...opts };
40
49
  // Ignore specific languages
@@ -50,7 +59,7 @@ async function analyse(input, opts = {}) {
50
59
  const customIgnored = [];
51
60
  const customBinary = [];
52
61
  const customText = [];
53
- if (!opts.quick) {
62
+ if (!opts.fileContent && !opts.quick) {
54
63
  for (const folder of folders) {
55
64
  // Skip if folder is marked in gitattributes
56
65
  if (customIgnored.some(path => (0, convert_glob_1.default)(path).test(folder)))
@@ -97,7 +106,7 @@ async function analyse(input, opts = {}) {
97
106
  }
98
107
  }
99
108
  // Check vendored files
100
- if (!opts.keepVendored) {
109
+ if (!opts.fileContent && !opts.keepVendored) {
101
110
  // Filter out any files that match a vendor file path
102
111
  const matcher = (match) => RegExp(match.replace(/\/$/, '/.+$').replace(/^\.\//, ''));
103
112
  files = files.filter(file => !customIgnored.some(pattern => matcher(pattern).test(file)));
@@ -115,9 +124,15 @@ async function analyse(input, opts = {}) {
115
124
  const overridesArray = Object.entries(overrides);
116
125
  // List all languages that could be associated with a given file
117
126
  for (const file of files) {
118
- if (!fs_1.default.existsSync(file) || fs_1.default.lstatSync(file).isDirectory())
119
- continue;
120
- const firstLine = await (0, read_file_1.default)(file, true).catch(() => null);
127
+ let firstLine;
128
+ if (opts.fileContent) {
129
+ firstLine = (_f = (_e = (_d = opts.fileContent) === null || _d === void 0 ? void 0 : _d[files.indexOf(file)]) === null || _e === void 0 ? void 0 : _e.split('\n')[0]) !== null && _f !== void 0 ? _f : null;
130
+ }
131
+ else {
132
+ if (!fs_1.default.existsSync(file) || fs_1.default.lstatSync(file).isDirectory())
133
+ continue;
134
+ firstLine = await (0, read_file_1.default)(file, true).catch(() => null);
135
+ }
121
136
  // Skip if file is unreadable
122
137
  if (firstLine === null)
123
138
  continue;
@@ -132,7 +147,7 @@ async function analyse(input, opts = {}) {
132
147
  }
133
148
  }
134
149
  // Check override for manual language classification
135
- if (!opts.quick && opts.checkAttributes) {
150
+ if (!opts.fileContent && !opts.quick && opts.checkAttributes) {
136
151
  const match = overridesArray.find(item => RegExp(item[0]).test(file));
137
152
  if (match) {
138
153
  const forcedLang = match[1];
@@ -144,7 +159,7 @@ async function analyse(input, opts = {}) {
144
159
  let skipExts = false;
145
160
  for (const lang in langData) {
146
161
  // Check if filename is a match
147
- const matchesName = (_d = langData[lang].filenames) === null || _d === void 0 ? void 0 : _d.some(name => path_1.default.basename(file.toLowerCase()) === name.toLowerCase());
162
+ const matchesName = (_g = langData[lang].filenames) === null || _g === void 0 ? void 0 : _g.some(name => path_1.default.basename(file.toLowerCase()) === name.toLowerCase());
148
163
  if (matchesName) {
149
164
  addResult(file, lang);
150
165
  skipExts = true;
@@ -153,7 +168,7 @@ async function analyse(input, opts = {}) {
153
168
  if (!skipExts)
154
169
  for (const lang in langData) {
155
170
  // Check if extension is a match
156
- const matchesExt = (_e = langData[lang].extensions) === null || _e === void 0 ? void 0 : _e.some(ext => file.toLowerCase().endsWith(ext.toLowerCase()));
171
+ const matchesExt = (_h = langData[lang].extensions) === null || _h === void 0 ? void 0 : _h.some(ext => file.toLowerCase().endsWith(ext.toLowerCase()));
157
172
  if (matchesExt)
158
173
  addResult(file, lang);
159
174
  }
@@ -164,7 +179,7 @@ async function analyse(input, opts = {}) {
164
179
  // Narrow down file associations to the best fit
165
180
  for (const file in fileAssociations) {
166
181
  // Skip binary files
167
- if (!opts.keepBinary) {
182
+ if (!opts.fileContent && !opts.keepBinary) {
168
183
  const isCustomText = customText.some(path => RegExp(path).test(file));
169
184
  const isCustomBinary = customBinary.some(path => RegExp(path).test(file));
170
185
  const isBinaryExt = binary_extensions_1.default.some(ext => file.endsWith('.' + ext));
@@ -208,10 +223,10 @@ async function analyse(input, opts = {}) {
208
223
  }
209
224
  }
210
225
  // If no heuristics, assign a language
211
- (_f = (_k = results.files.results)[file]) !== null && _f !== void 0 ? _f : (_k[file] = fileAssociations[file][0]);
226
+ (_j = (_r = results.files.results)[file]) !== null && _j !== void 0 ? _j : (_r[file] = fileAssociations[file][0]);
212
227
  }
213
228
  // Skip specified categories
214
- if ((_g = opts.categories) === null || _g === void 0 ? void 0 : _g.length) {
229
+ if ((_k = opts.categories) === null || _k === void 0 ? void 0 : _k.length) {
215
230
  const categories = ['data', 'markup', 'programming', 'prose'];
216
231
  const hiddenCategories = categories.filter(cat => !opts.categories.includes(cat));
217
232
  for (const [file, lang] of Object.entries(results.files.results)) {
@@ -229,7 +244,7 @@ async function analyse(input, opts = {}) {
229
244
  }
230
245
  }
231
246
  // Convert paths to relative
232
- if (opts.relativePaths) {
247
+ if (!opts.fileContent && opts.relativePaths) {
233
248
  const newMap = {};
234
249
  for (const [file, lang] of Object.entries(results.files.results)) {
235
250
  let relPath = path_1.default.relative(process.cwd(), file).replace(/\\/g, '/');
@@ -243,21 +258,21 @@ async function analyse(input, opts = {}) {
243
258
  for (const [file, lang] of Object.entries(results.files.results)) {
244
259
  if (lang && !langData[lang])
245
260
  continue;
246
- const fileSize = fs_1.default.statSync(file).size;
261
+ const fileSize = (_o = (_m = (_l = opts.fileContent) === null || _l === void 0 ? void 0 : _l[files.indexOf(file)]) === null || _m === void 0 ? void 0 : _m.length) !== null && _o !== void 0 ? _o : fs_1.default.statSync(file).size;
247
262
  results.files.bytes += fileSize;
248
263
  // If no language found, add extension in other section
249
264
  if (!lang) {
250
265
  const ext = path_1.default.extname(file);
251
266
  const unknownType = ext === '' ? 'filenames' : 'extensions';
252
267
  const name = ext === '' ? path_1.default.basename(file) : ext;
253
- (_h = (_l = results.unknown[unknownType])[name]) !== null && _h !== void 0 ? _h : (_l[name] = 0);
268
+ (_p = (_s = results.unknown[unknownType])[name]) !== null && _p !== void 0 ? _p : (_s[name] = 0);
254
269
  results.unknown[unknownType][name] += fileSize;
255
270
  results.unknown.bytes += fileSize;
256
271
  continue;
257
272
  }
258
273
  // Add language and bytes data to corresponding section
259
274
  const { type } = langData[lang];
260
- (_j = (_m = results.languages.results)[lang]) !== null && _j !== void 0 ? _j : (_m[lang] = { type, bytes: 0, color: langData[lang].color });
275
+ (_q = (_t = results.languages.results)[lang]) !== null && _q !== void 0 ? _q : (_t[lang] = { type, bytes: 0, color: langData[lang].color });
261
276
  if (opts.childLanguages)
262
277
  results.languages.results[lang].parent = langData[lang].group;
263
278
  results.languages.results[lang].bytes += fileSize;
package/dist/types.d.ts CHANGED
@@ -5,6 +5,7 @@ export declare type FilePath = string;
5
5
  export declare type Bytes = Integer;
6
6
  export declare type Integer = number;
7
7
  export interface Options {
8
+ fileContent?: string | string[];
8
9
  ignoredFiles?: string[];
9
10
  ignoredLanguages?: Language[];
10
11
  categories?: Category[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linguist-js",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
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": {
@@ -45,10 +45,10 @@
45
45
  "node-cache": "^5.1.2"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/glob-to-regexp": "ts4.4",
49
- "@types/js-yaml": "ts4.4",
50
- "@types/node": "ts4.4",
48
+ "@types/glob-to-regexp": "ts4.6",
49
+ "@types/js-yaml": "ts4.6",
50
+ "@types/node": "ts4.6",
51
51
  "deep-object-diff": "^1.1.7",
52
- "typescript": "~4.5.5"
52
+ "typescript": "~4.6.1-rc"
53
53
  }
54
54
  }
package/readme.md CHANGED
@@ -77,6 +77,7 @@ Running Linguist on this folder will return the following JSON:
77
77
  ### Notes
78
78
 
79
79
  - File paths in the output use only forward slashes as delimiters, even on Windows.
80
+ - This tool does not work when offline.
80
81
  - Do not rely on any language classification output from Linguist being unchanged between runs.
81
82
  Language data is fetched each run from the latest classifications of [`github-linguist`](https://github.com/github/linguist).
82
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.
@@ -99,6 +100,8 @@ const { files, languages, unknown } = linguist(folder, options);
99
100
  Analyse multiple folders using the syntax `"{folder1,folder2,...}"`.
100
101
  - `opts` (optional; object):
101
102
  An object containing analyser options.
103
+ - `fileContent` (string or string array):
104
+ Provides the file content associated with the file name(s) given as `entry` to analyse instead of reading from a folder on disk.
102
105
  - `ignoredFiles` (string array):
103
106
  A list of file path globs to explicitly ignore.
104
107
  - `ignoredLanguages` (string array):