linguist-js
Advanced tools
Comparing version 1.8.0 to 1.8.1
@@ -10,2 +10,4 @@ "use strict"; | ||
const index_1 = __importDefault(require("./index")); | ||
if (typeof commander_1.program === 'undefined') | ||
throw `Dependency 'commander' is not installed.`; | ||
commander_1.program | ||
@@ -56,3 +58,3 @@ .name('linguist --analyze') | ||
const root = args.analyze === true ? '.' : args.analyze; | ||
const { count, languages, results } = await index_1.default(root, args); | ||
const { count, languages, results } = await (0, index_1.default)(root, args); | ||
// Make file paths relative | ||
@@ -59,0 +61,0 @@ for (const [file, lang] of Object.entries(results)) { |
@@ -6,17 +6,20 @@ "use strict"; | ||
const fs_1 = __importDefault(require("fs")); | ||
const path_1 = require("path"); | ||
const path_1 = __importDefault(require("path")); | ||
const js_yaml_1 = __importDefault(require("js-yaml")); | ||
const tiny_glob_1 = __importDefault(require("tiny-glob")); | ||
const glob_to_regexp_1 = __importDefault(require("glob-to-regexp")); | ||
const binary_extensions_1 = __importDefault(require("binary-extensions")); | ||
const isbinaryfile_1 = require("isbinaryfile"); | ||
const helpers_1 = require("./helpers"); | ||
const walk_tree_1 = __importDefault(require("./helpers/walk-tree")); | ||
const load_data_1 = __importDefault(require("./helpers/load-data")); | ||
const read_file_1 = __importDefault(require("./helpers/read-file")); | ||
const convert_pcre_1 = __importDefault(require("./helpers/convert-pcre")); | ||
const convertToRegex = (path) => (0, glob_to_regexp_1.default)('**/' + path, { globstar: true, extended: true }); | ||
const last = (arr) => arr[arr.length - 1]; | ||
async function analyse(input, opts = {}) { | ||
var _a, _b, _c, _d, _e, _f, _g, _h; | ||
var _j, _k, _l; | ||
const root = Array.isArray(input) && input.length > 1 ? `{${input.join(',')}}` : input !== null && input !== void 0 ? input : '.'; | ||
const langData = await helpers_1.loadFile('languages.yml').then(js_yaml_1.default.load); | ||
const vendorData = await helpers_1.loadFile('vendor.yml').then(js_yaml_1.default.load); | ||
const heuristicsData = await helpers_1.loadFile('heuristics.yml').then(js_yaml_1.default.load); | ||
const generatedData = await helpers_1.loadFile('generated.rb').then(text => { var _a; return (_a = text.match(/(?<=name\.match\(\/).+?(?=(?<!\\)\/\))/gm)) !== null && _a !== void 0 ? _a : []; }); | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
var _l, _m, _o; | ||
const langData = await (0, load_data_1.default)('languages.yml').then(js_yaml_1.default.load); | ||
const vendorData = await (0, load_data_1.default)('vendor.yml').then(js_yaml_1.default.load); | ||
const heuristicsData = await (0, load_data_1.default)('heuristics.yml').then(js_yaml_1.default.load); | ||
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 : []; }); | ||
vendorData.push(...generatedData); | ||
@@ -33,35 +36,33 @@ const results = {}; | ||
}; | ||
let files = await tiny_glob_1.default(root + '/**/*', { absolute: true, filesOnly: true, dot: true }); | ||
files = files.map(path => path.replace(/\\/g, '/')).filter(file => !file.includes('/.git/')); | ||
const folders = new Set(files.map(file => path_1.posix.dirname(file))); | ||
const ignoredFiles = [ | ||
'.git', | ||
opts.keepVendored ? vendorData.map(path => (0, convert_pcre_1.default)(path).source) : [], | ||
(_b = (_a = opts.ignore) === null || _a === void 0 ? void 0 : _a.map(path => (0, glob_to_regexp_1.default)('*' + path + '*', { extended: true }).source)) !== null && _b !== void 0 ? _b : [], | ||
].flat(); | ||
let { files, folders } = (0, walk_tree_1.default)(input !== null && input !== void 0 ? input : '.', ignoredFiles); | ||
// Apply aliases | ||
opts = { checkIgnored: !opts.quick, checkAttributes: !opts.quick, checkHeuristics: !opts.quick, checkShebang: !opts.quick, ...opts }; | ||
// Apply explicit ignores | ||
if (opts.ignore) { | ||
const ignoredPaths = opts.ignore.map(path => glob_to_regexp_1.default('*' + path + '*', { extended: true }).source); | ||
files = files.filter(file => !ignoredPaths.some(ignore => RegExp(ignore).test(file))); | ||
} | ||
// Load gitattributes | ||
const customIgnored = []; | ||
if (!opts.quick) { | ||
for (const folder of folders) { | ||
// Skip checks if folder is already ignored | ||
if (!opts.keepVendored && vendorData.some(path => helpers_1.pcre(path).test(folder))) { | ||
// Skip if folder is marked in gitattributes | ||
if (customIgnored.some(path => (0, convert_pcre_1.default)(path).test(folder))) | ||
continue; | ||
} | ||
const attributesFile = path_1.posix.join(folder, '.gitattributes'); | ||
const ignoresFile = path_1.posix.join(folder, '.gitignore'); | ||
// Parse gitignores | ||
const ignoresFile = path_1.default.join(folder, '.gitignore'); | ||
if (opts.checkIgnored && fs_1.default.existsSync(ignoresFile)) { | ||
const ignoresData = await helpers_1.readFile(ignoresFile); | ||
const ignoresData = await (0, read_file_1.default)(ignoresFile); | ||
const ignoresList = ignoresData.split(/\r?\n/).filter(line => line.trim() && !line.startsWith('#')); | ||
const ignoredPaths = ignoresList.map(path => glob_to_regexp_1.default('*' + path + '*', { extended: true }).source); | ||
vendorData.push(...ignoredPaths); | ||
const ignoredPaths = ignoresList.map(path => convertToRegex(path).source); | ||
customIgnored.push(...ignoredPaths.map(file => file.replace(folder, ''))); | ||
} | ||
// Parse gitattributes | ||
const attributesFile = path_1.default.join(folder, '.gitattributes'); | ||
if (opts.checkAttributes && fs_1.default.existsSync(attributesFile)) { | ||
const attributesData = await helpers_1.readFile(attributesFile); | ||
const attributesData = await (0, read_file_1.default)(attributesFile); | ||
// Custom vendor options | ||
const vendorMatches = attributesData.matchAll(/^(\S+).*[^-]linguist-(vendored|generated|documentation)(?!=false)/gm); | ||
for (const [_line, path] of vendorMatches) { | ||
vendorData.push(folder + helpers_1.convertToRegex(path).source.substr(1)); | ||
customIgnored.push(convertToRegex(path).source.substr(1).replace(folder, '')); | ||
} | ||
@@ -77,3 +78,3 @@ // Custom file associations | ||
} | ||
const fullPath = folder + helpers_1.convertToRegex(path).source.substr(1); | ||
const fullPath = folder + convertToRegex(path).source.substr(1); | ||
overrides[fullPath] = forcedLang; | ||
@@ -87,4 +88,4 @@ } | ||
// Filter out any files that match a vendor file path | ||
const matcher = (match) => helpers_1.pcre(match.replace(/\/$/, '/.+$').replace(/^\.\//, '')); | ||
files = files.filter(file => !vendorData.some(match => matcher(match).test(file))); | ||
const matcher = (match) => (0, convert_pcre_1.default)(match.replace(/\/$/, '/.+$').replace(/^\.\//, '')); | ||
files = files.filter(file => !customIgnored.some(pattern => matcher(pattern).test(file))); | ||
} | ||
@@ -98,3 +99,3 @@ // Load all files and parse languages | ||
results[file].push(data); | ||
extensions[file] = path_1.posix.extname(file); | ||
extensions[file] = path_1.default.extname(file); | ||
}; | ||
@@ -107,3 +108,3 @@ const overridesArray = Object.entries(overrides); | ||
if (!opts.quick && opts.checkShebang) { | ||
const firstLine = await helpers_1.readFile(file, true); | ||
const firstLine = await (0, read_file_1.default)(file, true); | ||
if (firstLine.startsWith('#!')) { | ||
@@ -130,3 +131,3 @@ 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')); }); | ||
// Check if filename is a match | ||
const matchesName = (_a = langData[lang].filenames) === null || _a === void 0 ? void 0 : _a.some(name => path_1.posix.basename(file.toLowerCase()) === name.toLowerCase()); | ||
const matchesName = (_c = langData[lang].filenames) === null || _c === void 0 ? void 0 : _c.some(name => path_1.default.basename(file.toLowerCase()) === name.toLowerCase()); | ||
if (matchesName) | ||
@@ -137,3 +138,3 @@ addResult(file, lang); | ||
// Check if extension is a match | ||
const matchesExt = (_b = langData[lang].extensions) === null || _b === void 0 ? void 0 : _b.some(ext => file.toLowerCase().endsWith(ext.toLowerCase())); | ||
const matchesExt = (_d = langData[lang].extensions) === null || _d === void 0 ? void 0 : _d.some(ext => file.toLowerCase().endsWith(ext.toLowerCase())); | ||
if (matchesExt) | ||
@@ -148,3 +149,3 @@ addResult(file, lang); | ||
// Skip binary files | ||
if (!opts.keepBinary && (binary_extensions_1.default.some(ext => file.endsWith('.' + ext)) || await isbinaryfile_1.isBinaryFile(file))) { | ||
if (!opts.keepBinary && (binary_extensions_1.default.some(ext => file.endsWith('.' + ext)) || await (0, isbinaryfile_1.isBinaryFile)(file))) { | ||
continue; | ||
@@ -178,4 +179,4 @@ } | ||
// Check file contents and apply heuristic patterns | ||
const fileContent = await helpers_1.readFile(file); | ||
if (patterns.some(pattern => helpers_1.pcre(pattern).test(fileContent))) { | ||
const fileContent = await (0, read_file_1.default)(file); | ||
if (patterns.some(pattern => (0, convert_pcre_1.default)(pattern).test(fileContent))) { | ||
finalResults[file] = heuristic.language; | ||
@@ -186,11 +187,11 @@ break; | ||
// Default to final language | ||
const lastLanguage = helpers_1.last(heuristics.rules).language; | ||
(_c = finalResults[file]) !== null && _c !== void 0 ? _c : (finalResults[file] = Array.isArray(lastLanguage) ? lastLanguage[0] : lastLanguage); | ||
const lastLanguage = last(heuristics.rules).language; | ||
(_e = finalResults[file]) !== null && _e !== void 0 ? _e : (finalResults[file] = Array.isArray(lastLanguage) ? lastLanguage[0] : lastLanguage); | ||
} | ||
} | ||
// If no heuristics, load the only language | ||
(_d = finalResults[file]) !== null && _d !== void 0 ? _d : (finalResults[file] = results[file][0]); | ||
(_f = finalResults[file]) !== null && _f !== void 0 ? _f : (finalResults[file] = results[file][0]); | ||
} | ||
// Skip specified categories | ||
if ((_e = opts.categories) === null || _e === void 0 ? void 0 : _e.length) { | ||
if ((_g = opts.categories) === null || _g === void 0 ? void 0 : _g.length) { | ||
const categories = ['data', 'markup', 'programming', 'prose']; | ||
@@ -216,4 +217,4 @@ const hiddenCategories = categories.filter(cat => !opts.categories.includes(cat)); | ||
if (!lang) { | ||
const ext = path_1.posix.extname(file); | ||
(_f = (_j = languages.unknown)[ext]) !== null && _f !== void 0 ? _f : (_j[ext] = 0); | ||
const ext = path_1.default.extname(file); | ||
(_h = (_l = languages.unknown)[ext]) !== null && _h !== void 0 ? _h : (_l[ext] = 0); | ||
languages.unknown[ext] += fileSize; | ||
@@ -225,5 +226,5 @@ languages.total.unknownBytes += fileSize; | ||
const { type } = langData[lang]; | ||
(_g = (_k = languages.all)[lang]) !== null && _g !== void 0 ? _g : (_k[lang] = { type, bytes: 0, color: langData[lang].color }); | ||
(_j = (_m = languages.all)[lang]) !== null && _j !== void 0 ? _j : (_m[lang] = { type, bytes: 0, color: langData[lang].color }); | ||
languages.all[lang].bytes += fileSize; | ||
(_h = (_l = languages[type])[lang]) !== null && _h !== void 0 ? _h : (_l[lang] = 0); | ||
(_k = (_o = languages[type])[lang]) !== null && _k !== void 0 ? _k : (_o[lang] = 0); | ||
languages[type][lang] += fileSize; | ||
@@ -230,0 +231,0 @@ languages.total.bytes += fileSize; |
{ | ||
"name": "linguist-js", | ||
"version": "1.8.0", | ||
"version": "1.8.1", | ||
"description": "Analyse languages used in a folder. Powered by GitHub Linguist, although it doesn't need to be installed.", | ||
@@ -16,3 +16,4 @@ "main": "dist/index.js", | ||
"bin/", | ||
"dist/" | ||
"dist/**/*.js", | ||
"dist/*.d.ts" | ||
], | ||
@@ -37,3 +38,2 @@ "repository": { | ||
"binary-extensions": "^2.2.0", | ||
"commander": "^8.1.0", | ||
"cross-fetch": "^3.1.4", | ||
@@ -43,5 +43,7 @@ "glob-to-regexp": "^0.4.1", | ||
"js-yaml": "^4.1.0", | ||
"node-cache": "^5.1.2", | ||
"tiny-glob": "^0.2.9" | ||
"node-cache": "^5.1.2" | ||
}, | ||
"optionalDependencies": { | ||
"commander": "^8.1.0" | ||
}, | ||
"devDependencies": { | ||
@@ -51,5 +53,5 @@ "@types/glob-to-regexp": "ts4.4", | ||
"@types/node": "ts4.4", | ||
"fast-deep-equal": "^3.1.3", | ||
"typescript": "~4.4.1-rc" | ||
"deep-object-diff": "^1.1.0", | ||
"typescript": "~4.4.2" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30699
7
16
491
3
- Removedcommander@^8.1.0
- Removedtiny-glob@^0.2.9
- Removedglobalyzer@0.1.0(transitive)
- Removedglobrex@0.1.2(transitive)
- Removedtiny-glob@0.2.9(transitive)