linguist-js 2.9.2 → 3.0.0-pre

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.
Files changed (81) hide show
  1. package/bin/index.js +1 -1
  2. package/dist/analyser/classifiers/byAttributes.d.ts +3 -0
  3. package/dist/analyser/classifiers/byAttributes.js +13 -0
  4. package/dist/analyser/classifiers/byExtension.d.ts +3 -0
  5. package/dist/analyser/classifiers/byExtension.js +31 -0
  6. package/dist/analyser/classifiers/byFilename.d.ts +3 -0
  7. package/dist/analyser/classifiers/byFilename.js +10 -0
  8. package/dist/analyser/classifiers/byHeuristics.d.ts +3 -0
  9. package/dist/analyser/classifiers/byHeuristics.js +67 -0
  10. package/dist/analyser/classifiers/byModeline.d.ts +3 -0
  11. package/dist/analyser/classifiers/byModeline.js +22 -0
  12. package/dist/analyser/classifiers/byShebang.d.ts +3 -0
  13. package/dist/analyser/classifiers/byShebang.js +27 -0
  14. package/dist/analyser/index.d.ts +3 -0
  15. package/dist/analyser/index.js +12 -0
  16. package/dist/analyser/pipeline/aggregate.d.ts +2 -0
  17. package/dist/analyser/pipeline/aggregate.js +98 -0
  18. package/dist/analyser/pipeline/classify.d.ts +3 -0
  19. package/dist/analyser/pipeline/classify.js +31 -0
  20. package/dist/analyser/pipeline/filter.d.ts +2 -0
  21. package/dist/analyser/pipeline/filter.js +14 -0
  22. package/dist/analyser/pipeline/heuristics.d.ts +3 -0
  23. package/dist/analyser/pipeline/heuristics.js +12 -0
  24. package/dist/analyser/pipeline/normalise.d.ts +2 -0
  25. package/dist/analyser/pipeline/normalise.js +9 -0
  26. package/dist/cli/output/default.d.ts +3 -0
  27. package/dist/cli/output/default.js +106 -0
  28. package/dist/cli/output/tree.d.ts +3 -0
  29. package/dist/cli/output/tree.js +11 -0
  30. package/dist/cli/runCliAnalysis.d.ts +2 -0
  31. package/dist/cli/runCliAnalysis.js +26 -0
  32. package/dist/cli/utils.d.ts +2 -0
  33. package/dist/cli/utils.js +9 -0
  34. package/dist/cli.js +14 -143
  35. package/dist/entry/analyseFs.d.ts +2 -0
  36. package/dist/entry/analyseFs.js +11 -0
  37. package/dist/entry/analyseRaw.d.ts +4 -0
  38. package/dist/entry/analyseRaw.js +11 -0
  39. package/dist/index.d.ts +19 -4
  40. package/dist/index.js +18 -483
  41. package/dist/input/fromFilesystem.d.ts +4 -0
  42. package/dist/input/fromFilesystem.js +115 -0
  43. package/dist/input/fromRawContent.d.ts +2 -0
  44. package/dist/input/fromRawContent.js +19 -0
  45. package/dist/input/normaliseOpts.d.ts +2 -0
  46. package/dist/input/normaliseOpts.js +13 -0
  47. package/dist/program/classes/attributes.d.ts +11 -0
  48. package/dist/program/classes/attributes.js +37 -0
  49. package/dist/{helpers/load-data.d.ts → program/data/loadDataFiles.d.ts} +1 -1
  50. package/dist/program/data/loadDataFiles.js +32 -0
  51. package/dist/program/data/retrieveData.d.ts +12 -0
  52. package/dist/program/data/retrieveData.js +27 -0
  53. package/dist/{helpers/norm-path.d.ts → program/fs/normalisedPath.d.ts} +1 -0
  54. package/dist/program/fs/normalisedPath.js +17 -0
  55. package/dist/program/fs/readFile.js +17 -0
  56. package/dist/{helpers/walk-tree.d.ts → program/fs/walkTree.d.ts} +1 -1
  57. package/dist/{helpers/walk-tree.js → program/fs/walkTree.js} +22 -30
  58. package/dist/{helpers/parse-gitattributes.d.ts → program/parsing/parseGitattributes.d.ts} +2 -2
  59. package/dist/{helpers/parse-gitattributes.js → program/parsing/parseGitattributes.js} +4 -8
  60. package/dist/{helpers/parse-gitignore.js → program/parsing/parseGitignore.js} +1 -4
  61. package/dist/program/processFiles.d.ts +9 -0
  62. package/dist/program/processFiles.js +111 -0
  63. package/dist/{helpers/convert-pcre.js → program/utils/pcre.js} +1 -4
  64. package/dist/{schema.d.ts → types/schema.d.ts} +1 -1
  65. package/dist/types/schema.js +1 -0
  66. package/dist/{types.d.ts → types/types.d.ts} +35 -24
  67. package/dist/types/types.js +1 -0
  68. package/ext/generated.rb +6 -0
  69. package/ext/heuristics.yml +102 -11
  70. package/ext/languages.yml +518 -88
  71. package/ext/vendor.yml +1 -0
  72. package/package.json +14 -13
  73. package/readme.md +82 -87
  74. package/dist/helpers/load-data.js +0 -37
  75. package/dist/helpers/norm-path.js +0 -15
  76. package/dist/helpers/read-file.js +0 -23
  77. package/dist/schema.js +0 -2
  78. package/dist/types.js +0 -2
  79. /package/dist/{helpers/read-file.d.ts → program/fs/readFile.d.ts} +0 -0
  80. /package/dist/{helpers/parse-gitignore.d.ts → program/parsing/parseGitignore.d.ts} +0 -0
  81. /package/dist/{helpers/convert-pcre.d.ts → program/utils/pcre.d.ts} +0 -0
package/dist/cli.js CHANGED
@@ -1,20 +1,12 @@
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 VERSION = require('../package.json').version;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const commander_1 = require("commander");
10
- const index_1 = __importDefault(require("./index"));
11
- const norm_path_1 = require("./helpers/norm-path");
12
- const colouredMsg = ([r, g, b], msg) => `\u001B[${38};2;${r};${g};${b}m${msg}${'\u001b[0m'}`;
13
- const hexToRgb = (hex) => [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];
14
- commander_1.program
1
+ import { program } from 'commander';
2
+ import FS from 'node:fs';
3
+ import runCliAnalysis from './cli/runCliAnalysis.js';
4
+ const packageJson = JSON.parse(FS.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
5
+ const VERSION = packageJson.version;
6
+ program
15
7
  .name('linguist')
16
- .usage('--analyze [<folders...>] [<options...>]')
17
- .option('-a|--analyze|--analyse [folders...]', 'Analyse the languages of all files in a folder')
8
+ .usage('--analyse [<folders...>] [<options...>]')
9
+ .option('-a|--analyse [folders...]', 'Analyse the languages of all files in a folder')
18
10
  .option('-i|--ignoredFiles <files...>', `A list of file path globs to ignore`)
19
11
  .option('-l|--ignoredLanguages <languages...>', `A list of languages to ignore`)
20
12
  .option('-c|--categories <categories...>', 'Language categories to include in output')
@@ -37,8 +29,8 @@ commander_1.program
37
29
  .option('-M|--checkModeline [bool]', 'Check modelines for explicit classification', true)
38
30
  .helpOption(`-h|--help`, 'Display this help message')
39
31
  .version(VERSION, '-v|--version', 'Display the installed version of linguist-js');
40
- commander_1.program.parse(process.argv);
41
- const args = commander_1.program.opts();
32
+ program.parse(process.argv);
33
+ const args = program.opts();
42
34
  // Normalise arguments
43
35
  for (const arg in args) {
44
36
  const normalise = (val) => {
@@ -55,131 +47,10 @@ for (const arg in args) {
55
47
  args[arg] = normalise(args[arg]);
56
48
  }
57
49
  // Run Linguist
58
- if (args.analyze)
59
- (async () => {
60
- var _a;
61
- // Check arguments
62
- const validCategories = ['data', 'programming', 'prose', 'markup'];
63
- if ((_a = args.categories) === null || _a === void 0 ? void 0 : _a.some((category) => !validCategories.includes(category))) {
64
- console.log(`Error: '${args.categories.join(', ')}' contains an invalid category. Valid options: ${validCategories.join(', ')}.`);
65
- return;
66
- }
67
- // Fetch language data
68
- const root = args.analyze === true ? '.' : args.analyze;
69
- const data = await (0, index_1.default)(root, args);
70
- const { files, languages, unknown } = data;
71
- // Print output
72
- if (!args.json) {
73
- // Ignore languages with a bytes/% size less than the declared min size
74
- if (args.minSize) {
75
- const totalSize = languages.bytes;
76
- const minSizeAmt = parseFloat(args.minSize.replace(/[a-z]+$/i, '')); // '2KB' -> 2
77
- const minSizeUnit = args.minSize.replace(/^\d+/, '').toLowerCase(); // '2KB' -> 'kb'
78
- const checkBytes = minSizeUnit !== 'loc'; // whether to check bytes or loc
79
- const conversionFactors = {
80
- 'b': n => n,
81
- 'kb': n => n * 1e3,
82
- 'mb': n => n * 1e6,
83
- '%': n => n * totalSize / 100,
84
- 'loc': n => n,
85
- };
86
- const minBytesSize = conversionFactors[minSizeUnit](+minSizeAmt);
87
- const other = { bytes: 0, lines: { total: 0, content: 0, code: 0 } };
88
- // Apply specified minimums: delete language results that do not reach the threshold
89
- for (const [lang, data] of Object.entries(languages.results)) {
90
- const checkUnit = checkBytes ? data.bytes : data.lines.code;
91
- if (checkUnit < minBytesSize) {
92
- // Add to 'other' count
93
- other.bytes += data.bytes;
94
- other.lines.total += data.lines.total;
95
- other.lines.content += data.lines.content;
96
- other.lines.code += data.lines.code;
97
- // Remove language result
98
- delete languages.results[lang];
99
- }
100
- }
101
- if (other.bytes) {
102
- languages.results["Other"] = { ...other, type: null };
103
- }
104
- }
105
- const sortedEntries = Object.entries(languages.results).sort((a, b) => (a[1].bytes < b[1].bytes ? +1 : -1));
106
- const totalBytes = languages.bytes;
107
- console.log(`\n Analysed ${files.bytes.toLocaleString()} B from ${files.count} files with linguist-js`);
108
- console.log(`\n Language analysis results: \n`);
109
- let count = 0;
110
- if (sortedEntries.length === 0)
111
- console.log(` None`);
112
- // Collate files per language
113
- const filesPerLanguage = {};
114
- if (args.listFiles) {
115
- for (const language of Object.keys(languages.results)) {
116
- filesPerLanguage[language] = [];
117
- }
118
- for (const [file, lang] of Object.entries(files.results)) {
119
- if (lang)
120
- filesPerLanguage[lang].push(file);
121
- }
122
- }
123
- // List parsed results
124
- for (const [lang, { bytes, lines, color }] of sortedEntries) {
125
- const percent = (bytes) => bytes / (totalBytes || 1) * 100;
126
- const fmtd = {
127
- index: (++count).toString().padStart(2, ' '),
128
- lang: lang.padEnd(24, ' '),
129
- percent: percent(bytes).toFixed(2).padStart(5, ' '),
130
- bytes: bytes.toLocaleString().padStart(10, ' '),
131
- loc: lines.code.toLocaleString().padStart(10, ' '),
132
- icon: colouredMsg(hexToRgb(color !== null && color !== void 0 ? color : '#ededed'), '\u2588'),
133
- };
134
- console.log(` ${fmtd.index}. ${fmtd.icon} ${fmtd.lang} ${fmtd.percent}% ${fmtd.bytes} B ${fmtd.loc} LOC`);
135
- // If using `listFiles` option, list all files tagged as this language
136
- if (args.listFiles) {
137
- console.log(); // padding
138
- for (const file of filesPerLanguage[lang]) {
139
- let relFile = (0, norm_path_1.normPath)(path_1.default.relative(path_1.default.resolve('.'), file));
140
- if (!relFile.startsWith('../'))
141
- relFile = './' + relFile;
142
- const bytes = (await fs_1.default.promises.stat(file)).size;
143
- const fmtd2 = {
144
- file: relFile.padEnd(42, ' '),
145
- percent: percent(bytes).toFixed(2).padStart(5, ' '),
146
- bytes: bytes.toLocaleString().padStart(10, ' '),
147
- };
148
- console.log(` ${fmtd.icon} ${fmtd2.file} ${fmtd2.percent}% ${fmtd2.bytes} B`);
149
- }
150
- console.log(); // padding
151
- }
152
- }
153
- if (!args.listFiles)
154
- console.log(); // padding
155
- console.log(` Total: ${totalBytes.toLocaleString()} B`);
156
- // List unknown files/extensions
157
- if (unknown.bytes > 0) {
158
- console.log(`\n Unknown files and extensions:`);
159
- for (const [name, bytes] of Object.entries(unknown.filenames)) {
160
- console.log(` '${name}': ${bytes.toLocaleString()} B`);
161
- }
162
- for (const [ext, bytes] of Object.entries(unknown.extensions)) {
163
- console.log(` '*${ext}': ${bytes.toLocaleString()} B`);
164
- }
165
- console.log(` Total: ${unknown.bytes.toLocaleString()} B`);
166
- }
167
- }
168
- else if (args.tree) {
169
- const treeParts = args.tree.split('.');
170
- let nestedData = data;
171
- for (const part of treeParts) {
172
- if (!nestedData[part])
173
- throw Error(`TraversalError: Key '${part}' cannot be found on output object.`);
174
- nestedData = nestedData[part];
175
- }
176
- console.log(nestedData);
177
- }
178
- else {
179
- console.dir(data, { depth: null });
180
- }
181
- })();
50
+ if (args.analyse) {
51
+ void runCliAnalysis(args);
52
+ }
182
53
  else {
183
- console.log(`Welcome to linguist-js, a JavaScript port of GitHub's language analyzer.`);
54
+ console.log(`Welcome to linguist-js, a JavaScript port of the github-linguist language analyser.`);
184
55
  console.log(`Type 'linguist --help' for a list of commands.`);
185
56
  }
@@ -0,0 +1,2 @@
1
+ import * as T from '../types/types.js';
2
+ export default function analyseFs(inputPaths: string[], inputOptions?: T.Options): Promise<T.Results>;
@@ -0,0 +1,11 @@
1
+ import analyseVirtualFiles from '../analyser/index.js';
2
+ import fromFilesystem from '../input/fromFilesystem.js';
3
+ import normaliseOpts from '../input/normaliseOpts.js';
4
+ import retrieveData from '../program/data/retrieveData.js';
5
+ export default async function analyseFs(inputPaths, inputOptions = {}) {
6
+ const options = normaliseOpts(inputOptions);
7
+ // Load data from github-linguist web repo
8
+ const { langData, heuristicsData, vendorPaths } = await retrieveData(options.offline ?? false);
9
+ const files = await fromFilesystem(inputPaths, options, vendorPaths);
10
+ return analyseVirtualFiles(files, langData, heuristicsData, options);
11
+ }
@@ -0,0 +1,4 @@
1
+ import * as T from '../types/types.js';
2
+ export default function analyseRaw(inputContent: {
3
+ [filename: string]: string;
4
+ }, inputOptions?: T.Options): Promise<T.Results>;
@@ -0,0 +1,11 @@
1
+ import analyseVirtualFiles from '../analyser/index.js';
2
+ import fromRawContent from '../input/fromRawContent.js';
3
+ import normaliseOpts from '../input/normaliseOpts.js';
4
+ import retrieveData from '../program/data/retrieveData.js';
5
+ export default async function analyseRaw(inputContent, inputOptions = {}) {
6
+ const options = normaliseOpts(inputOptions);
7
+ // Load data from github-linguist web repo
8
+ const { langData, heuristicsData, vendorPaths } = await retrieveData(options.offline ?? false);
9
+ const files = fromRawContent(inputContent, vendorPaths);
10
+ return analyseVirtualFiles(files, langData, heuristicsData, options);
11
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,19 @@
1
- import * as T from './types';
2
- declare function analyse(path?: string, opts?: T.Options): Promise<T.Results>;
3
- declare function analyse(paths?: string[], opts?: T.Options): Promise<T.Results>;
4
- export = analyse;
1
+ import analyseFs from './entry/analyseFs.js';
2
+ import analyseRaw from './entry/analyseRaw.js';
3
+ declare const _default: {
4
+ /**
5
+ * Analyse a list of folders and return language statistics
6
+ * @param inputPaths - An array of file paths to analyse
7
+ * @param options - Configuration options for the analysis
8
+ * @returns A promise that resolves to the analysis results
9
+ */
10
+ analyseFolders: typeof analyseFs;
11
+ /**
12
+ * Analyse raw content and return language statistics
13
+ * @param inputContent - An object where keys are filenames and values are file contents
14
+ * @param options - Configuration options for the analysis
15
+ * @returns A promise that resolves to the analysis results
16
+ */
17
+ analyseRawContent: typeof analyseRaw;
18
+ };
19
+ export default _default;