Skip to content

Commit

Permalink
feat: add --ext CLI flag and extensions Node.js API option
Browse files Browse the repository at this point in the history
  • Loading branch information
Mouvedia committed Mar 4, 2023
1 parent 2b33910 commit 38b0b57
Show file tree
Hide file tree
Showing 20 changed files with 189 additions and 154 deletions.
2 changes: 1 addition & 1 deletion .changeset/old-otters-care.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"stylelint": minor
---

Added: ext flag and extensions property
Added: `--ext` CLI flag and `extensions` Node.js API option
11 changes: 9 additions & 2 deletions docs/user-guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ Disable the default ignores. Stylelint will not automatically ignore the content

### `--ext`

Allows you to specify which file extensions Stylelint uses when searching for target files in the directories set in the [input](#usage-examples).
Specify file extensions used when searching for target files in the directories set in the [input](#usage-examples). [More info](node-api.md#extensions).

Note that [extensions](./configure.md#extensions) will take precedence if both are provided.
Note it also accepts dot-less elements in its list.
e.g. `--ext css,less` is treated the same as the more conventional `--ext .css,.less`

### `--fix`

Expand Down Expand Up @@ -140,6 +141,12 @@ _You should include quotation marks around file globs._

Recursively linting all `.css` files in the `foo` directory:

```shell
stylelint foo
```

or

```shell
stylelint "foo/**/*.css"
```
Expand Down
10 changes: 0 additions & 10 deletions docs/user-guide/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,6 @@ The value of `"extends"` is a "locater" (or an array of "locaters") that is ulti

You'll find more configs in [Awesome Stylelint](https://github.com/stylelint/awesome-stylelint#configs).

## `extensions`

Allows you to specify which file extensions Stylelint uses when searching for target files in the directories set in the [input](./cli.md#usage-examples).

```json
{
"extensions": ["css", "scss", "less"]
}
```

## `plugins`

Plugins are custom rules or sets of custom rules built to support methodologies, toolsets, _non-standard_ CSS features, or very specific use cases.
Expand Down
6 changes: 6 additions & 0 deletions docs/user-guide/node-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ A string to lint.

The directory from which Stylelint will look for files. Defaults to the current working directory returned by `process.cwd()`.

### `extensions`

Specify supported file extensions. Stylelint defaults to `['css']`.

Note that it only applies to directories; i.e., files and glob patterns will be ignored.

### `files`

A file glob, or array of [file globs](https://github.com/sindresorhus/globby).
Expand Down
6 changes: 0 additions & 6 deletions docs/user-guide/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,6 @@ CLI flags: `--disable-default-ignores, --di`

Disable the default ignores. Stylelint will not automatically ignore the contents of `node_modules`.

## `extensions`

CLI flags: `--ext`

Specify supported file extensions. By default, Stylelint sets it to `['css']`.

## `globbyOptions`

CLI flags: `--globby-options, --go`
Expand Down
4 changes: 1 addition & 3 deletions lib/__tests__/__snapshots__/cli.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ exports[`CLI --help 1`] = `
--ext [default: ".css"]
Specify supported file extensions.
Only applies to directories.
i.e. glob patterns and/or file names are ignored
Only applies to directories; i.e., files and glob patterns will be ignored.
--formatter, -f [default: "string"]
Expand Down
40 changes: 7 additions & 33 deletions lib/__tests__/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const stripAnsi = require('strip-ansi');
const cli = require('../cli');
const pkg = require('../../package.json');
const replaceBackslashes = require('../testUtils/replaceBackslashes');
const safeChdir = require('../testUtils/safeChdir');

const fixturesPath = (...elems) => replaceBackslashes(path.join(__dirname, 'fixtures', ...elems));
const { buildCLI } = cli;
Expand Down Expand Up @@ -88,6 +87,10 @@ describe('buildCLI', () => {
expect(buildCLI(['--di']).flags.disableDefaultIgnores).toBe(true);
});

it('flags.ext', () => {
expect(buildCLI(['--ext=.css,.scss']).flags.ext).toBe('.css,.scss');
});

it('flags.fix', () => {
expect(buildCLI(['--fix']).flags.fix).toBe(true);
});
Expand Down Expand Up @@ -430,47 +433,18 @@ describe('CLI', () => {
);
});

describe('--ext | fixtures/extensions', () => {
const cwd = path.join(__dirname, 'fixtures', 'extensions');

safeChdir(cwd);

it('cwd', async () => {
await cli([
'.',
'--custom-syntax=postcss-scss',
'--config',
fixturesPath('config-color-named.json'),
'--ext=.css,.scss',
]);

const str = process.stdout.write.mock.calls[0][0];

expect(process.stderr.write).toHaveBeenCalledTimes(0);
expect(process.stdout.write).toHaveBeenCalledTimes(1);
expect(str).not.toContain('foo.json');
expect(str).toContain('bar.scss');
expect(str).toContain('folder/qux.css');
});
});

it('--ext | fixtures/', async () => {
it('--ext | dot less extensions', async () => {
await cli([
fixturesPath('no-empty-source.html'),
fixturesPath('extensions'),
'--custom-syntax=postcss-scss',
fixturesPath('extensions', 'folder', 'qux.css'),
'--config',
fixturesPath('config-color-named.json'),
'--ext=.css,.scss',
'--ext=css,scss',
]);

const str = process.stdout.write.mock.calls[0][0];

expect(process.stderr.write).toHaveBeenCalledTimes(0);
expect(process.stdout.write).toHaveBeenCalledTimes(1);
expect(str).not.toContain('lib/__tests__/fixtures/extensions/foo.json');
expect(str).toContain('lib/__tests__/fixtures/no-empty-source.html');
expect(str).toContain('lib/__tests__/fixtures/extensions/bar.scss');
expect(str).toContain('lib/__tests__/fixtures/extensions/folder/qux.css');
});
});
13 changes: 0 additions & 13 deletions lib/__tests__/extends.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const safeChdir = require('../testUtils/safeChdir');
const configExtendingAnotherExtend = require('./fixtures/config-extending-another-extend.json');
const configExtendingOne = require('./fixtures/config-extending-one.json');
const configExtendingThreeWithOverride = require('./fixtures/config-extending-three-with-override.json');
const configExtendingExtensions = require('./fixtures/config-extending-extensions.json');
const standalone = require('../standalone');

const fixturesPath = path.join(__dirname, 'fixtures');
Expand Down Expand Up @@ -47,18 +46,6 @@ it('extending with overrides', async () => {
expect(linted.results[0].warnings).toHaveLength(0);
});

it('extending with extensions', async () => {
const linted = await standalone({
files: [path.join(fixturesPath, 'extensions')],
config: configExtendingExtensions,
configBasedir: path.join(__dirname, 'fixtures'),
});

expect(linted.results).toHaveLength(2);
expect(linted.results[0].source.endsWith('.scss')).toBe(true);
expect(linted.results[1].source.endsWith('.css')).toBe(true);
});

it('extending configuration and no configBasedir', () => {
return expect(
standalone({
Expand Down
5 changes: 0 additions & 5 deletions lib/__tests__/fixtures/config-extending-extensions.json

This file was deleted.

6 changes: 0 additions & 6 deletions lib/__tests__/fixtures/extensions/config.json

This file was deleted.

Empty file.
Empty file.
5 changes: 2 additions & 3 deletions lib/__tests__/integration.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
'use strict';

const lessSyntax = require('postcss-less');
const path = require('path');
const postcss = require('postcss');
const sassSyntax = require('postcss-sass');
const scssSyntax = require('postcss-scss');
const { stripIndent } = require('common-tags');

const stylelint = require('..');

const fixtures = (...elem) => path.join(__dirname, 'fixtures', ...elem);
const fixturePath = require('../testUtils/fixturePath');
const fixtures = fixturePath.bind(null, __dirname);

const config = {
rules: {
Expand Down
6 changes: 2 additions & 4 deletions lib/__tests__/normalizeRuleSettings-integration.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
'use strict';

const path = require('path');

const standalone = require('../standalone');

const fixture = (...elem) => path.join(__dirname, 'fixtures', ...elem);
const fixturePath = require('../testUtils/fixturePath');
const fixture = fixturePath.bind(null, __dirname);

it('[normalized rule settings] primary option array', async () => {
const { results } = await standalone({
Expand Down
150 changes: 124 additions & 26 deletions lib/__tests__/standalone-ext.test.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,133 @@
'use strict';

const path = require('path');
const { existsSync } = require('fs');
const standalone = require('../standalone');
const fixturesPath = path.join(__dirname, 'fixtures');

it('extensions array', async () => {
const inputFiles = [
path.join(fixturesPath, 'no-empty-source.html'),
path.join(fixturesPath, 'extensions'),
];
const { results } = await standalone({
files: inputFiles,
customSyntax: 'postcss-scss',
extensions: ['css', 'scss'],
config: {
rules: { 'color-named': 'never' },
},
});

expect(results).toHaveLength(3);
expect(results[0].source.endsWith('no-empty-source.html')).toBe(true);
expect(results[1].source.endsWith(path.join('extensions', 'bar.scss'))).toBe(true);
expect(results[2].source.endsWith(path.join('extensions', 'folder', 'qux.css'))).toBe(true);
const safeChdir = require('../testUtils/safeChdir');
const fixturePath = require('../testUtils/fixturePath');
const configColorNamed = require('./fixtures/config-color-named.json');

const fixture = fixturePath.bind(null, __dirname);
const cwd = fixture('extensions');

describe('extensions', () => {
test('array', async () => {
const inputFiles = [fixture('no-empty-source.html'), cwd];
const { results } = await standalone({
files: inputFiles,
customSyntax: 'postcss-scss',
extensions: ['css', 'scss'],
config: {
rules: { 'color-named': 'never' },
},
});

expect(results).toHaveLength(3);
expect(existsSync(fixture('extensions', 'foo.json'))).toBe(true);
expect(results[0].source).toBe(fixture('no-empty-source.html'));
expect(results[1].source).toBe(fixture('extensions', 'bar.scss'));
expect(results[2].source).toBe(fixture('extensions', 'folder', 'qux.css'));
});

test('default', async () => {
const { results } = await standalone({
files: [cwd],
config: { rules: { 'color-named': 'never' } },
});

expect(results).toHaveLength(1);
expect(results[0].source).toBe(fixture('extensions', 'folder', 'qux.css'));
});

test('dot prefix', async () => {
const { results } = await standalone({
files: [cwd],
config: { rules: { 'color-named': 'never' } },
extensions: ['.scss'],
customSyntax: 'postcss-scss',
});

expect(results).toHaveLength(1);
expect(results[0].source).toContain('bar.scss');
});

test('no match', () => {
return expect(
standalone({
files: [cwd],
config: configColorNamed,
extensions: ['js'],
cwd,
}),
).rejects.toThrow('All input files were ignored');
});
});

it('extensions default', async () => {
const { results } = await standalone({
files: [path.join(fixturesPath, 'extensions')],
config: { rules: { 'color-named': 'never' } },
describe('inputs', () => {
safeChdir(cwd);

test('.', async () => {
const { results } = await standalone({
files: ['.'],
config: configColorNamed,
extensions: ['css', 'scss'],
customSyntax: 'postcss-scss',
cwd,
});

expect(results).toHaveLength(2);
expect(existsSync('foo.json')).toBe(true);
expect(existsSync('folder/baz.json')).toBe(true);
expect(results[0].source).toContain('bar.scss');
expect(results[1].source).toContain(path.normalize('folder/qux.css'));
});

test('false positive', async () => {
const inputFiles = [cwd, fixture('config-color-named.json')];
const { results } = await standalone({
files: inputFiles,
config: configColorNamed,
extensions: ['css', 'scss'],
customSyntax: 'postcss-scss',
cwd,
});

expect(results).toHaveLength(3);
expect(results[0].source).toContain('bar.scss');
expect(results[1].source).toContain(path.normalize('folder/qux.css'));
expect(results[2].source).toContain(path.normalize('fixtures/config-color-named.json'));
});

expect(results).toHaveLength(1);
expect(results[0].source.endsWith(path.join('extensions', 'folder', 'qux.css'))).toBe(true);
test('common prefix', async () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
const inputFiles = [path.join(cwd, 'folder'), path.join(cwd, 'folder-slash', 'file.json')];
const { results } = await standalone({
files: inputFiles,
config: configColorNamed,
extensions: ['css'],
cwd,
});

expect(results).toHaveLength(2);
expect(results[0].source).toContain(path.normalize('folder/qux.css'));
expect(results[1].source).toContain(path.normalize('folder-slash/file.json'));
warn.mockRestore();
});

test('**', async () => {
const { results } = await standalone({
files: ['**'],
config: configColorNamed,
extensions: ['css', 'scss'],
customSyntax: 'postcss-scss',
cwd,
});

expect(results).toHaveLength(5);
expect(results[0].source).toContain('bar.scss');
expect(results[1].source).toContain('foo.json');
expect(results[2].source).toContain(path.normalize('folder/baz.json'));
expect(results[3].source).toContain(path.normalize('folder/qux.css'));
expect(results[4].source).toContain(path.normalize('folder-slash/file.json'));
});
});

0 comments on commit 38b0b57

Please sign in to comment.