linguist-js 2.2.0 → 2.2.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/cli.js CHANGED
@@ -64,6 +64,7 @@ if (args.analyze)
64
64
  let count = 0;
65
65
  if (sortedEntries.length === 0)
66
66
  console.log(` None`);
67
+ // List parsed results
67
68
  for (const [lang, { bytes, color }] of sortedEntries) {
68
69
  const fmtd = {
69
70
  index: (++count).toString().padStart(2, ' '),
@@ -75,6 +76,7 @@ if (args.analyze)
75
76
  console.log(` ${fmtd.index}. ${fmtd.icon} ${fmtd.lang} ${fmtd.percent}% ${fmtd.bytes} B`);
76
77
  }
77
78
  console.log(` Total: ${totalBytes.toLocaleString()} B`);
79
+ // List unknown files/extensions
78
80
  if (unknown.bytes > 0) {
79
81
  console.log(`\n Unknown files and extensions:`);
80
82
  for (const [name, bytes] of Object.entries(unknown.filenames)) {
@@ -101,6 +103,6 @@ if (args.analyze)
101
103
  }
102
104
  })();
103
105
  else {
104
- console.log(`Welcome to linguist-js, the JavaScript port of GitHub's language analyzer.`);
106
+ console.log(`Welcome to linguist-js, a JavaScript port of GitHub's language analyzer.`);
105
107
  console.log(`Type 'linguist --help' for a list of commands.`);
106
108
  }
@@ -4,12 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fs_1 = __importDefault(require("fs"));
7
- /** Read part of a file on disc. */
7
+ /**
8
+ * Read part of a file on disc.
9
+ * @throws 'EPERM' if the file is not readable.
10
+ */
8
11
  async function readFile(filename, onlyFirstLine = false) {
9
12
  const chunkSize = 100;
10
13
  const stream = fs_1.default.createReadStream(filename, { highWaterMark: chunkSize });
11
14
  let content = '';
12
- for await (const data of stream) {
15
+ for await (const data of stream) { // may throw
13
16
  content += data.toString();
14
17
  if (onlyFirstLine && content.includes('\n')) {
15
18
  return content.split(/\r?\n/)[0];
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ async function analyse(input, opts = {}) {
69
69
  const attributesData = await (0, read_file_1.default)(attributesFile);
70
70
  const relPathToRegex = (path) => (0, convert_glob_1.default)(path).source.substr(1).replace(folder, '');
71
71
  // Explicit text/binary associations
72
- const contentTypeMatches = attributesData.matchAll(/^(\S+).*?(-?binary|-?text)/gm);
72
+ const contentTypeMatches = attributesData.matchAll(/^(\S+).*?(-?binary|-?text)(?!=auto)/gm);
73
73
  for (const [_line, path, type] of contentTypeMatches) {
74
74
  if (['text', '-binary'].includes(type))
75
75
  customText.push(relPathToRegex(path));
@@ -117,16 +117,18 @@ async function analyse(input, opts = {}) {
117
117
  for (const file of files) {
118
118
  if (!fs_1.default.existsSync(file) || fs_1.default.lstatSync(file).isDirectory())
119
119
  continue;
120
+ const firstLine = await (0, read_file_1.default)(file, true).catch(() => null);
121
+ // Skip if file is unreadable
122
+ if (firstLine === null)
123
+ continue;
120
124
  // Check shebang line for explicit classification
121
- if (!opts.quick && opts.checkShebang) {
122
- const firstLine = await (0, read_file_1.default)(file, true);
123
- if (firstLine.startsWith('#!')) {
124
- const matches = Object.entries(langData).filter(([, data]) => { var _a; return (_a = data.interpreters) === null || _a === void 0 ? void 0 : _a.some(interpreter => firstLine.match('\\b' + interpreter + '\\b')); });
125
- if (matches.length) {
126
- const forcedLang = matches[0][0];
127
- addResult(file, forcedLang);
128
- continue;
129
- }
125
+ if (!opts.quick && opts.checkShebang && firstLine.startsWith('#!')) {
126
+ // Find matching interpreters
127
+ const matches = Object.entries(langData).filter(([, data]) => { var _a; return (_a = data.interpreters) === null || _a === void 0 ? void 0 : _a.some(interpreter => firstLine.match('\\b' + interpreter + '\\b')); });
128
+ if (matches.length) {
129
+ // Add explicitly-identified language
130
+ const forcedLang = matches[0][0];
131
+ addResult(file, forcedLang);
130
132
  }
131
133
  }
132
134
  // Check override for manual language classification
@@ -196,7 +198,9 @@ async function analyse(input, opts = {}) {
196
198
  if (heuristic.named_pattern)
197
199
  normalise(heuristicsData.named_patterns[heuristic.named_pattern]);
198
200
  // Check file contents and apply heuristic patterns
199
- const fileContent = await (0, read_file_1.default)(file);
201
+ const fileContent = await (0, read_file_1.default)(file).catch(() => null);
202
+ if (fileContent === null)
203
+ continue;
200
204
  if (!patterns.length || patterns.some(pattern => (0, convert_pcre_1.default)(pattern).test(fileContent))) {
201
205
  results.files.results[file] = heuristic.language;
202
206
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linguist-js",
3
- "version": "2.2.0",
3
+ "version": "2.2.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": {
@@ -37,8 +37,8 @@
37
37
  "homepage": "https://github.com/Nixinova/Linguist#readme",
38
38
  "dependencies": {
39
39
  "binary-extensions": "^2.2.0",
40
- "commander": "^8.3.0",
41
- "cross-fetch": "^3.1.4",
40
+ "commander": "^9.0.0",
41
+ "cross-fetch": "^3.1.5",
42
42
  "glob-to-regexp": "~0.4.1",
43
43
  "isbinaryfile": "^4.0.8",
44
44
  "js-yaml": "^4.1.0",
@@ -48,7 +48,7 @@
48
48
  "@types/glob-to-regexp": "ts4.4",
49
49
  "@types/js-yaml": "ts4.4",
50
50
  "@types/node": "ts4.4",
51
- "deep-object-diff": "^1.1.0",
52
- "typescript": "~4.5.4"
51
+ "deep-object-diff": "^1.1.7",
52
+ "typescript": "~4.5.5"
53
53
  }
54
54
  }