mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-28 17:57:48 +02:00
feat(stylelint-copyright): autofix, stricter config (#6374)
* feat(stylelint-copyright): autofix, stricter config * revert TS * oops
This commit is contained in:
parent
284c6166e7
commit
14bec7cf11
12 changed files with 202 additions and 176 deletions
|
@ -12,6 +12,7 @@ packages/lqip-loader/lib/
|
|||
packages/docusaurus/lib/
|
||||
packages/docusaurus-*/lib/*
|
||||
packages/docusaurus-*/lib-next/
|
||||
packages/stylelint-copyright/lib/
|
||||
copyUntypedFiles.mjs
|
||||
|
||||
packages/create-docusaurus/lib/*
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -23,6 +23,7 @@ packages/create-docusaurus/lib/
|
|||
packages/lqip-loader/lib/
|
||||
packages/docusaurus/lib/
|
||||
packages/docusaurus-*/lib/*
|
||||
packages/stylelint-copyright/lib/
|
||||
packages/docusaurus-*/lib-next/
|
||||
|
||||
website/netlifyDeployPreview/*
|
||||
|
|
|
@ -10,6 +10,7 @@ packages/docusaurus-*/lib/*
|
|||
packages/docusaurus-*/lib-next/
|
||||
packages/create-docusaurus/lib/*
|
||||
packages/create-docusaurus/templates/*/docusaurus.config.js
|
||||
packages/stylelint-copyright/lib/
|
||||
__fixtures__
|
||||
|
||||
website/i18n
|
||||
|
|
|
@ -9,7 +9,16 @@ module.exports = {
|
|||
extends: ['stylelint-config-recommended', 'stylelint-config-prettier'],
|
||||
plugins: ['stylelint-copyright'],
|
||||
rules: {
|
||||
'docusaurus/copyright-header': true,
|
||||
'docusaurus/copyright-header': [
|
||||
true,
|
||||
{
|
||||
header: `*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.`,
|
||||
},
|
||||
],
|
||||
'selector-pseudo-class-no-unknown': [
|
||||
true,
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ export default {
|
|||
transform: {
|
||||
'^.+\\.[jt]sx?$': 'babel-jest',
|
||||
},
|
||||
setupFiles: ['./jest/stylelint-rule-test.js'],
|
||||
moduleNameMapper: {
|
||||
// Jest can't resolve CSS or asset imports
|
||||
'^.+\\.(css|jpg|jpeg|png|svg)$': '<rootDir>/jest/emptyModule.js',
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const stylelint = require('stylelint');
|
||||
|
||||
function getOutputCss(output) {
|
||||
const result = output.results[0]._postcssResult;
|
||||
return result.root.toString(result.opts.syntax);
|
||||
}
|
||||
|
||||
global.testStylelintRule = (config, tests) => {
|
||||
describe(tests.ruleName, () => {
|
||||
const checkTestCaseContent = (testCase) =>
|
||||
testCase.description || testCase.code || 'no description';
|
||||
|
||||
if (tests.accept && tests.accept.length) {
|
||||
describe('accept cases', () => {
|
||||
tests.accept.forEach((testCase) => {
|
||||
const spec = testCase.only ? it.only : it;
|
||||
|
||||
spec(checkTestCaseContent(testCase), () => {
|
||||
const options = {
|
||||
code: testCase.code,
|
||||
config,
|
||||
syntax: tests.syntax,
|
||||
};
|
||||
|
||||
return stylelint.lint(options).then((output) => {
|
||||
expect(output.results[0].warnings).toEqual([]);
|
||||
|
||||
if (!tests.fix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the fix.
|
||||
return stylelint
|
||||
.lint({...options, fix: true})
|
||||
.then((fixedOutput) => getOutputCss(fixedOutput))
|
||||
.then((fixedCode) => expect(fixedCode).toBe(testCase.fixed));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (tests.reject && tests.reject.length) {
|
||||
describe('reject cases', () => {
|
||||
tests.reject.forEach((testCase) => {
|
||||
const skip = testCase.skip ? it.skip : it;
|
||||
const spec = testCase.only ? it.only : skip;
|
||||
|
||||
spec(checkTestCaseContent(testCase), () => {
|
||||
const options = {
|
||||
code: testCase.code,
|
||||
config,
|
||||
syntax: tests.syntax,
|
||||
};
|
||||
|
||||
return stylelint.lint(options).then((output) => {
|
||||
const {warnings} = output.results[0];
|
||||
const warning = warnings[0];
|
||||
|
||||
expect(warnings.length).toBeGreaterThanOrEqual(1);
|
||||
expect(testCase).toHaveMessage();
|
||||
|
||||
if (testCase.message != null) {
|
||||
expect(warning.text).toBe(testCase.message);
|
||||
}
|
||||
|
||||
if (testCase.line != null) {
|
||||
expect(warning.line).toBe(testCase.line);
|
||||
}
|
||||
|
||||
if (testCase.column != null) {
|
||||
expect(warning.column).toBe(testCase.column);
|
||||
}
|
||||
|
||||
if (!tests.fix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!testCase.fixed) {
|
||||
throw new Error(
|
||||
'If using { fix: true } in test tests, all reject cases must have { fixed: .. }',
|
||||
);
|
||||
}
|
||||
|
||||
// Check the fix.
|
||||
return stylelint
|
||||
.lint({...options, fix: true})
|
||||
.then((fixedOutput) => getOutputCss(fixedOutput))
|
||||
.then((fixedCode) => expect(fixedCode).toBe(testCase.fixed));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
expect.extend({
|
||||
toHaveMessage(testCase) {
|
||||
if (testCase.message == null) {
|
||||
return {
|
||||
message: () =>
|
||||
'Expected "reject" test case to have a "message" property',
|
||||
pass: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pass: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
|
@ -79,6 +79,7 @@
|
|||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@types/semver": "^7.1.0",
|
||||
"@types/shelljs": "^0.8.6",
|
||||
"@types/stylelint": "^13.13.3",
|
||||
"@types/wait-on": "^5.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||
"@typescript-eslint/parser": "^5.8.1",
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.skipToContent {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
|
|
|
@ -16,7 +16,7 @@ Stylelint plugin to check CSS files for a copyright header.
|
|||
{
|
||||
"plugins": ["stylelint-copyright"],
|
||||
"rules": {
|
||||
"docusaurus/copyright-header": true
|
||||
"docusaurus/copyright-header": [true, {"header": "\n * Copyright"}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -5,17 +5,128 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const stylelint = require('stylelint');
|
||||
const path = require('path');
|
||||
const rule = require('..');
|
||||
|
||||
const {ruleName, messages} = rule;
|
||||
|
||||
function getOutputCss(output) {
|
||||
const result = output.results[0]._postcssResult;
|
||||
return result.root.toString(result.opts.syntax);
|
||||
}
|
||||
|
||||
function testStylelintRule(config, tests) {
|
||||
describe(tests.ruleName, () => {
|
||||
const checkTestCaseContent = (testCase) =>
|
||||
testCase.description || testCase.code || 'no description';
|
||||
|
||||
if (tests.accept && tests.accept.length) {
|
||||
describe('accept cases', () => {
|
||||
tests.accept.forEach((testCase) => {
|
||||
const spec = testCase.only ? it.only : it;
|
||||
|
||||
spec(checkTestCaseContent(testCase), () => {
|
||||
const options = {
|
||||
code: testCase.code,
|
||||
config,
|
||||
syntax: tests.syntax,
|
||||
};
|
||||
|
||||
return stylelint.lint(options).then((output) => {
|
||||
expect(output.results[0].warnings).toEqual([]);
|
||||
|
||||
if (!tests.fix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the fix.
|
||||
return stylelint
|
||||
.lint({...options, fix: true})
|
||||
.then((fixedOutput) => getOutputCss(fixedOutput))
|
||||
.then((fixedCode) => expect(fixedCode).toBe(testCase.fixed));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (tests.reject && tests.reject.length) {
|
||||
describe('reject cases', () => {
|
||||
tests.reject.forEach((testCase) => {
|
||||
const skip = testCase.skip ? it.skip : it;
|
||||
const spec = testCase.only ? it.only : skip;
|
||||
|
||||
spec(checkTestCaseContent(testCase), () => {
|
||||
const options = {
|
||||
code: testCase.code,
|
||||
config,
|
||||
syntax: tests.syntax,
|
||||
};
|
||||
|
||||
return stylelint.lint(options).then((output) => {
|
||||
const {warnings} = output.results[0];
|
||||
const warning = warnings[0];
|
||||
|
||||
expect(warnings.length).toBeGreaterThanOrEqual(1);
|
||||
expect(testCase).toHaveMessage();
|
||||
|
||||
if (testCase.message != null) {
|
||||
expect(warning.text).toBe(testCase.message);
|
||||
}
|
||||
|
||||
if (testCase.line != null) {
|
||||
expect(warning.line).toBe(testCase.line);
|
||||
}
|
||||
|
||||
if (testCase.column != null) {
|
||||
expect(warning.column).toBe(testCase.column);
|
||||
}
|
||||
|
||||
if (!tests.fix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!testCase.fixed) {
|
||||
throw new Error(
|
||||
'If using { fix: true } in test tests, all reject cases must have { fixed: .. }',
|
||||
);
|
||||
}
|
||||
|
||||
// Check the fix.
|
||||
return stylelint
|
||||
.lint({...options, fix: true})
|
||||
.then((fixedOutput) => getOutputCss(fixedOutput))
|
||||
.then((fixedCode) => expect(fixedCode).toBe(testCase.fixed));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
expect.extend({
|
||||
toHaveMessage(testCase) {
|
||||
if (testCase.message == null) {
|
||||
return {
|
||||
message: () =>
|
||||
'Expected "reject" test case to have a "message" property',
|
||||
pass: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pass: true,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testStylelintRule(
|
||||
{
|
||||
// Relative to repo root.
|
||||
plugins: [path.join(process.cwd(), 'packages', 'stylelint-copyright')],
|
||||
plugins: [path.join(__dirname, '..')],
|
||||
rules: {
|
||||
[ruleName]: true,
|
||||
[ruleName]: [true, {header: '*\n * Copyright'}],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -28,27 +139,30 @@ testStylelintRule(
|
|||
* Copyright
|
||||
*/
|
||||
|
||||
.foo {}`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
/**
|
||||
* copyright
|
||||
*/
|
||||
|
||||
.foo {}`,
|
||||
},
|
||||
],
|
||||
reject: [
|
||||
{
|
||||
code: `
|
||||
/**
|
||||
* copyright
|
||||
*/
|
||||
|
||||
.foo {}`,
|
||||
message: messages.rejected,
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
/**
|
||||
* Copyleft
|
||||
*/
|
||||
|
||||
.foo {}`,
|
||||
message: messages.rejected,
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
{
|
||||
|
@ -62,7 +176,7 @@ testStylelintRule(
|
|||
*/
|
||||
.foo {}`,
|
||||
message: messages.rejected,
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -12,45 +12,50 @@ const messages = stylelint.utils.ruleMessages(ruleName, {
|
|||
rejected: 'Missing copyright in the header comment',
|
||||
});
|
||||
|
||||
module.exports = stylelint.createPlugin(
|
||||
const plugin = stylelint.createPlugin(
|
||||
ruleName,
|
||||
(actual) => (root, result) => {
|
||||
const validOptions = stylelint.utils.validateOptions(result, ruleName, {
|
||||
actual,
|
||||
});
|
||||
(primaryOption, secondaryOption, context) => (root, result) => {
|
||||
const validOptions = stylelint.utils.validateOptions(
|
||||
result,
|
||||
ruleName,
|
||||
{
|
||||
actual: primaryOption,
|
||||
possible: [true, false],
|
||||
},
|
||||
{
|
||||
actual: secondaryOption,
|
||||
possible: (v) => typeof v.header === 'string',
|
||||
},
|
||||
);
|
||||
|
||||
if (!validOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
root.walkComments((comment) => {
|
||||
// Ignore root comments with copyright text.
|
||||
if (
|
||||
comment === comment.parent.first &&
|
||||
/[Cc]opyright/.test(comment.text)
|
||||
) {
|
||||
if (
|
||||
root.first &&
|
||||
root.first.type === 'comment' &&
|
||||
root.first.source.start.column === 1
|
||||
) {
|
||||
const {text} = root.first;
|
||||
if (text === secondaryOption.header) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (context.fix) {
|
||||
root.first?.before(`/*${secondaryOption.header}\n */`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore non-root comments.
|
||||
if (comment.type !== 'root' && comment !== comment.parent.first) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore indented comments.
|
||||
if (comment.source.start.column > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
stylelint.utils.report({
|
||||
message: messages.rejected,
|
||||
node: comment,
|
||||
result,
|
||||
ruleName,
|
||||
});
|
||||
stylelint.utils.report({
|
||||
message: messages.rejected,
|
||||
node: root,
|
||||
result,
|
||||
ruleName,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
module.exports = plugin;
|
||||
module.exports.ruleName = ruleName;
|
||||
module.exports.messages = messages;
|
||||
|
|
34
yarn.lock
34
yarn.lock
|
@ -4048,6 +4048,14 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/stringify-object/-/stringify-object-3.3.1.tgz#9ee394931e63468de0412a8e19c9f021a7d1d24d"
|
||||
integrity sha512-bpCBW0O+QrMLNFBY/+rkZtGzcYRmc2aTD8qYHOMNUmednqETfEZtFcGEA11l9xqbIeiT1PgXG0eq3zqayVzZSQ==
|
||||
|
||||
"@types/stylelint@^13.13.3":
|
||||
version "13.13.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/stylelint/-/stylelint-13.13.3.tgz#29ba9b7179e5632b12853252da191443607d32fc"
|
||||
integrity sha512-xvYwobi9L69FXbJTimKYRNHyMwtmcJxMd1woI3U822rkW/f7wcZ6fsV1DqYPT+sNaO0qUtngiBhTQfMeItUvUA==
|
||||
dependencies:
|
||||
globby "11.x.x"
|
||||
postcss "7.x.x"
|
||||
|
||||
"@types/supports-color@^8.1.1":
|
||||
version "8.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/supports-color/-/supports-color-8.1.1.tgz#1b44b1b096479273adf7f93c75fc4ecc40a61ee4"
|
||||
|
@ -9392,6 +9400,18 @@ globals@^13.6.0, globals@^13.9.0:
|
|||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globby@11.x.x, globby@^11.0.0, globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
dependencies:
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.2.9"
|
||||
ignore "^5.2.0"
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^10.0.1:
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
|
||||
|
@ -9406,18 +9426,6 @@ globby@^10.0.1:
|
|||
merge2 "^1.2.3"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^11.0.0, globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
dependencies:
|
||||
array-union "^2.1.0"
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.2.9"
|
||||
ignore "^5.2.0"
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^12.0.2:
|
||||
version "12.0.2"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-12.0.2.tgz#53788b2adf235602ed4cabfea5c70a1139e1ab11"
|
||||
|
@ -14832,7 +14840,7 @@ postcss-zindex@^5.0.1:
|
|||
resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.0.1.tgz#c585724beb69d356af8c7e68847b28d6298ece03"
|
||||
integrity sha512-nwgtJJys+XmmSGoYCcgkf/VczP8Mp/0OfSv3v0+fw0uABY4yxw+eFs0Xp9nAZHIKnS5j+e9ywQ+RD+ONyvl5pA==
|
||||
|
||||
"postcss@5 - 7", postcss@^7.0.14, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.39, postcss@^7.0.6:
|
||||
"postcss@5 - 7", postcss@7.x.x, postcss@^7.0.14, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.39, postcss@^7.0.6:
|
||||
version "7.0.39"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309"
|
||||
integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==
|
||||
|
|
Loading…
Add table
Reference in a new issue