Skip to content

Commit

Permalink
Fix some path / glob problems (#4867)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-allanson committed Aug 31, 2020
1 parent 3cfc658 commit 181f3d9
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/[digit]/not-digits/styles.css
@@ -0,0 +1 @@
a {}
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/extglob!(s)/styles.css
@@ -0,0 +1 @@
a {}
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/glob+chars/glob-plus.css
@@ -0,0 +1 @@
a {}
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/glob-contains-plus/styles.css
@@ -0,0 +1 @@
a {}
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/got!negate/negate/styles.css
@@ -0,0 +1 @@
a {}
@@ -0,0 +1 @@
a {}
@@ -0,0 +1 @@
a {}
@@ -0,0 +1 @@
a {}
1 change: 1 addition & 0 deletions lib/__tests__/fixtures/globs/with spaces/styles.css
@@ -0,0 +1 @@
a {}
193 changes: 193 additions & 0 deletions lib/__tests__/standalone-globs.test.js
@@ -0,0 +1,193 @@
'use strict';

/* eslint-disable node/no-extraneous-require */

const describe = require('@jest/globals').describe;
const expect = require('@jest/globals').expect;
const it = require('@jest/globals').it;

/* eslint-enable */

const path = require('path');
const replaceBackslashes = require('../testUtils/replaceBackslashes');
const standalone = require('../standalone');

const fixturesPath = replaceBackslashes(path.join(__dirname, 'fixtures', 'globs'));

// Tests for https://github.com/stylelint/stylelint/issues/4521

describe('standalone globbing', () => {
describe('paths with special characters', () => {
// ref https://github.com/micromatch/micromatch#matching-features
const fixtureDirs = [
`[digit]/not-digits`,
`with spaces`,
`extglob!(s)`,
`got!negate/negate`,
// `extglob+(s)`, // Note: +'s cause errors. Ignoring until it becomes a problem
];

// https://github.com/stylelint/stylelint/issues/4193
it.each(fixtureDirs)(`static path contains "%s"`, async (fixtureDir) => {
const cssPath = `${fixturesPath}/${fixtureDir}/styles.css`;

const { results } = await standalone({
files: cssPath,
config: { rules: { 'block-no-empty': true } },
});

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});
});

// https://github.com/stylelint/stylelint/issues/4211
it('glob has no + character, matched path does', async () => {
const files = `${fixturesPath}/**/glob-plus.css`; // file is in dir 'glob+chars'

const { results } = await standalone({
files,
config: { rules: { 'block-no-empty': true } },
});

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});

// https://github.com/stylelint/stylelint/issues/4211
it('glob contains + character, matched path does not', async () => {
const files = `${fixturesPath}/+(g)lob-contains-plus/*.css`;

const { results } = await standalone({
files,
config: { rules: { 'block-no-empty': true } },
});

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});

// https://github.com/stylelint/stylelint/issues/3272
// should ignore 'negated-globs/ignore/styles.css'
it('negated glob patterns', async () => {
const files = [
`${fixturesPath}/negated-globs/**/*.css`,
`!${fixturesPath}/negated-globs/ignore/**/*.css`,
];

const { results } = await standalone({
files,
config: { rules: { 'block-no-empty': true } },
});

// ensure that the only result is from the unignored file
expect(results[0].source).toEqual(expect.stringContaining('lint-this-file.css'));

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});

describe('mixed globs and paths with special chars', () => {
it('manual escaping', async () => {
const cssGlob = `${fixturesPath}/got\\[braces\\] and \\(spaces\\)/*.+(s|c)ss`;

const { results } = await standalone({
files: cssGlob,
config: {
rules: {
'block-no-empty': true,
},
},
});

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});

it('setting "cwd" in globbyOptions', async () => {
const cssGlob = `*.+(s|c)ss`;

const { results } = await standalone({
files: cssGlob,
config: {
rules: {
'block-no-empty': true,
},
},
globbyOptions: {
cwd: `${fixturesPath}/got[braces] and (spaces)/`,
},
});

expect(results).toHaveLength(1);
expect(results[0].errored).toEqual(true);
expect(results[0].warnings[0]).toEqual(
expect.objectContaining({
rule: 'block-no-empty',
severity: 'error',
}),
);
});

/* eslint-disable jest/no-commented-out-tests -- Failing case for reference. Documents behaviour that doesn't work. */

// Note: This fails because there's no way to tell which parts of the glob are literal characters, and which are special globbing characters.
//
// 'got[braces] and (spaces)' is a literal directory path. `*.+(s|c)ss` is a glob.

// https://github.com/stylelint/stylelint/issues/4855
// it('glob and matched path contain different special chars, complex example', async () => {
// const cssGlob = `${fixturesPath}/got[braces] and (spaces)/*.+(s|c)ss`;

// const { results } = await standalone({
// files: cssGlob,
// config: {
// rules: {
// 'block-no-empty': true,
// },
// },
// });

// expect(results).toHaveLength(1);
// expect(results[0].errored).toEqual(true);
// expect(results[0].warnings[0]).toEqual(
// expect.objectContaining({
// rule: 'block-no-empty',
// severity: 'error',
// }),
// );
// });

/* eslint-enable */
});
});
15 changes: 15 additions & 0 deletions lib/standalone.js
Expand Up @@ -4,6 +4,7 @@ const _ = require('lodash');
const createStylelint = require('./createStylelint');
const createStylelintResult = require('./createStylelintResult');
const debug = require('debug')('stylelint:standalone');
const fastGlob = require('fast-glob');
const FileCache = require('./utils/FileCache');
const filterFilePaths = require('./utils/filterFilePaths');
const formatters = require('./formatters');
Expand Down Expand Up @@ -170,6 +171,20 @@ module.exports = function (options) {
fileList = [fileList];
}

fileList = fileList.map((entry) => {
if (globby.hasMagic(entry)) {
const cwd = _.get(globbyOptions, 'cwd', process.cwd());
const absolutePath = !path.isAbsolute(entry) ? path.join(cwd, entry) : path.normalize(entry);

if (fs.existsSync(absolutePath)) {
// This glob-like path points to a file. Return an escaped path to avoid globbing
return fastGlob.escapePath(entry);
}
}

return entry;
});

if (!options.disableDefaultIgnores) {
fileList = fileList.concat(ALWAYS_IGNORED_GLOBS.map((glob) => `!${glob}`));
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -118,6 +118,7 @@
"cosmiconfig": "^7.0.0",
"debug": "^4.1.1",
"execall": "^2.0.0",
"fast-glob": "^3.2.4",
"fastest-levenshtein": "^1.0.9",
"file-entry-cache": "^5.0.1",
"get-stdin": "^8.0.0",
Expand Down

0 comments on commit 181f3d9

Please sign in to comment.