Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

linguist-js

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

linguist-js - npm Package Compare versions

Comparing version 1.8.0 to 1.8.1

dist/helpers/convert-pcre.js

4

dist/cli.js

@@ -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"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc