pretty-parallel
Version:
Concurrent prettier runner
175 lines • 6.4 kB
JavaScript
;
/**
* This file has been copied from https://github.com/prettier/prettier/blob/2bbbe1a8d17961101d076ac530309fd2c6b06cbe/src/cli/expand-patterns.js
* and has been adapted to typescript
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.fixWindowsSlashes = exports.expandPatterns = void 0;
const tslib_1 = require("tslib");
const promises_1 = tslib_1.__importDefault(require("node:fs/promises"));
const node_path_1 = tslib_1.__importDefault(require("node:path"));
const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
async function statSafe(filePath) {
try {
return await promises_1.default.stat(filePath);
}
catch (error) {
/* istanbul ignore next */
if (error.code !== 'ENOENT') {
throw error;
}
return null;
}
}
async function* expandPatterns(context) {
const cwd = process.cwd();
const seen = new Set();
for await (const pathOrError of expandPatternsInternal(context)) {
if (typeof pathOrError !== 'string') {
yield pathOrError;
continue;
}
const relativePath = node_path_1.default.relative(cwd, pathOrError);
// filter out duplicates
if (seen.has(relativePath)) {
continue;
}
seen.add(relativePath);
yield relativePath;
}
}
exports.expandPatterns = expandPatterns;
async function* expandPatternsInternal(context) {
// Ignores files in version control systems directories and `node_modules`
const silentlyIgnoredDirs = ['.git', '.svn', '.hg', 'node_modules'];
const globOptions = {
dot: true,
ignore: silentlyIgnoredDirs.map((dir) => '**/' + dir),
};
let supportedFilesGlob;
const cwd = process.cwd();
const entries = [];
for (const pattern of context.filePatterns) {
const stringPattern = pattern.toString();
const absolutePath = node_path_1.default.resolve(cwd, stringPattern);
if (containsIgnoredPathSegment(absolutePath, cwd, silentlyIgnoredDirs)) {
continue;
}
const stat = await statSafe(absolutePath);
if (stat) {
if (stat.isFile()) {
entries.push({
type: 'file',
glob: escapePathForGlob(fixWindowsSlashes(stringPattern)),
input: stringPattern,
});
}
else if (stat.isDirectory()) {
/*
1. Remove trailing `/`, `fast-glob` can't find files for `src//*.js` pattern
2. Cleanup dirname, when glob `src/../*.js` pattern with `fast-glob`,
it returns files like 'src/../index.js'
*/
const relativePath = node_path_1.default.relative(cwd, absolutePath) || '.';
entries.push({
type: 'dir',
glob: escapePathForGlob(fixWindowsSlashes(relativePath)) + '/' + getSupportedFilesGlob(),
input: stringPattern,
});
}
}
else if (stringPattern[0] === '!') {
// convert negative patterns to `ignore` entries
globOptions.ignore.push(fixWindowsSlashes(stringPattern.slice(1)));
}
else {
entries.push({
type: 'glob',
glob: fixWindowsSlashes(stringPattern),
input: stringPattern,
});
}
}
for (const { type, glob, input } of entries) {
let result;
try {
result = await (0, fast_glob_1.default)(glob, globOptions);
}
catch (err) {
/* istanbul ignore next */
yield {
error: `${errorMessages.globError[type]}: ${input}\n${err.message}`,
};
/* istanbul ignore next */
continue;
}
if (result.length > 0) {
yield* sortPaths(result);
}
}
function getSupportedFilesGlob() {
if (!supportedFilesGlob) {
const extensions = context.languages.flatMap((lang) => lang.extensions || []);
const filenames = context.languages.flatMap((lang) => lang.filenames || []);
supportedFilesGlob = `**/{${[
...extensions.map((ext) => '*' + (ext[0] === '.' ? ext : '.' + ext)),
...filenames,
]}}`;
}
return supportedFilesGlob;
}
}
const errorMessages = {
globError: {
file: 'Unable to resolve file',
dir: 'Unable to expand directory',
glob: 'Unable to expand glob pattern',
},
emptyResults: {
file: 'Explicitly specified file was ignored due to negative glob patterns',
dir: 'No supported files were found in the directory',
glob: 'No files matching the pattern were found',
},
};
/**
* @param {string} absolutePath
* @param {string} cwd
* @param {string[]} ignoredDirectories
*/
function containsIgnoredPathSegment(absolutePath, cwd, ignoredDirectories) {
return node_path_1.default
.relative(cwd, absolutePath)
.split(node_path_1.default.sep)
.some((dir) => ignoredDirectories.includes(dir));
}
/**
* @param {string[]} paths
*/
function sortPaths(paths) {
return paths.sort((a, b) => a.localeCompare(b));
}
/**
* This function should be replaced with `fastGlob.escapePath` when these issues are fixed:
* - https://github.com/mrmlnc/fast-glob/issues/261
* - https://github.com/mrmlnc/fast-glob/issues/262
* @param {string} path
*/
function escapePathForGlob(path) {
return fast_glob_1.default
.escapePath(path.replace(/\\/g, '\0'))
.replace(/\\!/g, '@(!)') // Workaround for fast-glob#261
.replace(/\0/g, '@(\\\\)'); // Workaround for fast-glob#262 (part 2)
}
const isWindows = node_path_1.default.sep === '\\';
/**
* Using backslashes in globs is probably not okay, but not accepting
* backslashes as path separators on Windows is even more not okay.
* https://github.com/prettier/prettier/pull/6776#discussion_r380723717
* https://github.com/mrmlnc/fast-glob#how-to-write-patterns-on-windows
* @param {string} pattern
*/
function fixWindowsSlashes(pattern) {
return isWindows ? pattern.replace(/\\/g, '/') : pattern;
}
exports.fixWindowsSlashes = fixWindowsSlashes;
//# sourceMappingURL=expand-patterns.js.map