mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-02-07 16:11:12 +01:00
Add a new linting task in order to detect unused/unknown css variables in the Firefox build
The goal is to be able to catch the errors before making a release. And fix some css issues (especially the missing css code for the newly added menu.css)
This commit is contained in:
parent
36de2d976d
commit
4bf759404c
3
.github/workflows/lint.yml
vendored
3
.github/workflows/lint.yml
vendored
@ -32,3 +32,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Run lint-chromium
|
- name: Run lint-chromium
|
||||||
run: npx gulp lint-chromium
|
run: npx gulp lint-chromium
|
||||||
|
|
||||||
|
- name: Run lint-mozcentral
|
||||||
|
run: npx gulp lint-mozcentral
|
||||||
|
|||||||
@ -17,9 +17,9 @@
|
|||||||
"float": ["inline-start", "inline-end"]
|
"float": ["inline-start", "inline-end"]
|
||||||
},
|
},
|
||||||
"length-zero-no-unit": [true, {
|
"length-zero-no-unit": [true, {
|
||||||
ignore: ["custom-properties"]
|
"ignore": ["custom-properties"]
|
||||||
}],
|
}],
|
||||||
"selector-pseudo-element-colon-notation": "double",
|
"selector-pseudo-element-colon-notation": "double",
|
||||||
"shorthand-property-no-redundant-values": true,
|
"shorthand-property-no-redundant-values": true
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
external/builder/builder.mjs
vendored
19
external/builder/builder.mjs
vendored
@ -39,15 +39,22 @@ function preprocess(inFilename, outFilename, defines) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function expandCssImports(content, baseUrl) {
|
function expandCssImports(content, baseUrl) {
|
||||||
|
if (defines.GECKOVIEW) {
|
||||||
|
// In Geckoview, we don't need some styles.
|
||||||
|
const startComment = "/* Ignored in GECKOVIEW: begin */";
|
||||||
|
const endComment = "/* Ignored in GECKOVIEW: end */";
|
||||||
|
const beginIndex = content.indexOf(startComment);
|
||||||
|
const endIndex = content.indexOf(endComment);
|
||||||
|
if (beginIndex >= 0 && endIndex > beginIndex) {
|
||||||
|
content =
|
||||||
|
content.substring(0, beginIndex) +
|
||||||
|
content.substring(endIndex + endComment.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return content.replaceAll(
|
return content.replaceAll(
|
||||||
/^\s*@import\s+url\(([^)]+)\);\s*$/gm,
|
/^\s*@import\s+url\(([^)]+)\);\s*$/gm,
|
||||||
function (all, url) {
|
function (all, url) {
|
||||||
if (defines.GECKOVIEW) {
|
|
||||||
switch (url) {
|
|
||||||
case "annotation_editor_layer_builder.css":
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const file = path.join(path.dirname(baseUrl), url);
|
const file = path.join(path.dirname(baseUrl), url);
|
||||||
const imported = fs.readFileSync(file, "utf8").toString();
|
const imported = fs.readFileSync(file, "utf8").toString();
|
||||||
return expandCssImports(imported, file);
|
return expandCssImports(imported, file);
|
||||||
|
|||||||
110
external/stylelint/no-unused-custom-properties.mjs
vendored
Normal file
110
external/stylelint/no-unused-custom-properties.mjs
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* Copyright 2025 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Remove the exception below once someone figures out how to fix it.
|
||||||
|
// eslint-disable-next-line import/no-unresolved
|
||||||
|
import { parse, registerWalkers, Root } from "postcss-values-parser";
|
||||||
|
import { isString } from "stylelint/lib/utils/validateTypes.mjs";
|
||||||
|
import stylelint from "stylelint";
|
||||||
|
|
||||||
|
const {
|
||||||
|
createPlugin,
|
||||||
|
utils: { report, validateOptions },
|
||||||
|
} = stylelint;
|
||||||
|
|
||||||
|
registerWalkers(Root);
|
||||||
|
|
||||||
|
const ruleName = "pdfjs/no-unused-custom-properties";
|
||||||
|
|
||||||
|
// It's a very basic linter: we don't take into account scopes.
|
||||||
|
// But it should be enough for our use case.
|
||||||
|
|
||||||
|
/** @type {import('stylelint').Plugin} */
|
||||||
|
const ruleFunction =
|
||||||
|
(enabled, { ignoreList = [] } = {}, context = {}) =>
|
||||||
|
(root, result) => {
|
||||||
|
const validOptions = validateOptions(
|
||||||
|
result,
|
||||||
|
ruleName,
|
||||||
|
{
|
||||||
|
actual: enabled,
|
||||||
|
possible: [true],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actual: ignoreList,
|
||||||
|
possible: [isString],
|
||||||
|
optional: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!validOptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreList = ignoreList.map(s => (s.startsWith("--") ? s : `--${s}`));
|
||||||
|
|
||||||
|
const usedCustomProperties = new Set(ignoreList);
|
||||||
|
const definedCustomProperties = new Set();
|
||||||
|
const usedBy = new Map();
|
||||||
|
root.walkDecls(decl => {
|
||||||
|
let definingProperty = null;
|
||||||
|
if (decl.prop.startsWith("--")) {
|
||||||
|
// This is a custom property definition.
|
||||||
|
definingProperty = decl.prop;
|
||||||
|
definedCustomProperties.add(definingProperty);
|
||||||
|
}
|
||||||
|
// Parse the declaration value to find var() usages.
|
||||||
|
const parsedValue = parse(decl.value);
|
||||||
|
parsedValue.walkFuncs(node => {
|
||||||
|
if (!node.isVar || node.nodes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This is a var() function; get the custom property name.
|
||||||
|
const property = node.nodes[0].value;
|
||||||
|
if (!definingProperty) {
|
||||||
|
// This is a usage of a custom property but not in a definition.
|
||||||
|
// width: var(--foo);
|
||||||
|
usedCustomProperties.add(property);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let usages = usedBy.get(property);
|
||||||
|
if (!usages) {
|
||||||
|
usages = [];
|
||||||
|
usedBy.set(property, usages);
|
||||||
|
}
|
||||||
|
// Record that this custom property is used by the defining property.
|
||||||
|
// --foo: var(--bar);
|
||||||
|
// bar is really used only if foo is.
|
||||||
|
usages.push(definingProperty);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const isUsed = p =>
|
||||||
|
usedCustomProperties.has(p) || (usedBy.get(p) || []).some(isUsed);
|
||||||
|
for (const customProperty of definedCustomProperties) {
|
||||||
|
if (isUsed(customProperty)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
report({
|
||||||
|
message: `Custom property "${customProperty}" is defined but never used.`,
|
||||||
|
node: root,
|
||||||
|
result,
|
||||||
|
ruleName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ruleFunction.ruleName = ruleName;
|
||||||
|
|
||||||
|
export default createPlugin(ruleName, ruleFunction);
|
||||||
29
gulpfile.mjs
29
gulpfile.mjs
@ -2099,6 +2099,35 @@ gulp.task("lint", function (done) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
"lint-mozcentral",
|
||||||
|
gulp.series("mozcentral", function runLintMozcentral(done) {
|
||||||
|
console.log();
|
||||||
|
console.log("### Checking mozilla-central files");
|
||||||
|
|
||||||
|
const styleLintOptions = [
|
||||||
|
"../../node_modules/stylelint/bin/stylelint.mjs",
|
||||||
|
"**/*.css",
|
||||||
|
"--report-needless-disables",
|
||||||
|
"--config",
|
||||||
|
"../../stylelint-mozcentral.json",
|
||||||
|
];
|
||||||
|
|
||||||
|
const styleLintProcess = startNode(styleLintOptions, {
|
||||||
|
stdio: "inherit",
|
||||||
|
cwd: BUILD_DIR + "mozcentral/",
|
||||||
|
});
|
||||||
|
styleLintProcess.on("close", function (styleLintCode) {
|
||||||
|
if (styleLintCode !== 0) {
|
||||||
|
done(new Error("Stylelint failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("files checked, no errors found");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"lint-chromium",
|
"lint-chromium",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
|
|||||||
1032
package-lock.json
generated
1032
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,7 @@
|
|||||||
"postcss-dir-pseudo-class": "^9.0.1",
|
"postcss-dir-pseudo-class": "^9.0.1",
|
||||||
"postcss-discard-comments": "^7.0.5",
|
"postcss-discard-comments": "^7.0.5",
|
||||||
"postcss-nesting": "^13.0.2",
|
"postcss-nesting": "^13.0.2",
|
||||||
|
"postcss-values-parser": "^7.0.0",
|
||||||
"prettier": "^3.7.2",
|
"prettier": "^3.7.2",
|
||||||
"puppeteer": "^24.31.0",
|
"puppeteer": "^24.31.0",
|
||||||
"stylelint": "^16.26.1",
|
"stylelint": "^16.26.1",
|
||||||
|
|||||||
12
stylelint-mozcentral.json
Normal file
12
stylelint-mozcentral.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["./external/stylelint/no-unused-custom-properties.mjs"],
|
||||||
|
"rules": {
|
||||||
|
"no-unknown-custom-properties": true,
|
||||||
|
"pdfjs/no-unused-custom-properties": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignoreList": ["scale-round-x", "scale-round-y", "input-width"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
web/menu.css
17
web/menu.css
@ -33,6 +33,23 @@
|
|||||||
--menuitem-focus-outline-color: light-dark(#0062fa, #00cadb);
|
--menuitem-focus-outline-color: light-dark(#0062fa, #00cadb);
|
||||||
--menuitem-focus-border-color: light-dark(white, black);
|
--menuitem-focus-border-color: light-dark(white, black);
|
||||||
|
|
||||||
|
--menu-bg: light-dark(white, #23222b);
|
||||||
|
--menu-background-blend-mode: normal;
|
||||||
|
--menu-box-shadow:
|
||||||
|
0 0.375px 1.5px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)),
|
||||||
|
0 3px 12px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
|
||||||
|
--menu-border-color: light-dark(rgb(21 20 26 / 0.1), rgb(251 251 254 / 0.1));
|
||||||
|
--menuitem-border-radius: 8px;
|
||||||
|
--menu-backdrop-filter: none;
|
||||||
|
--menu-text-color: light-dark(#15141a, #fbfbfe);
|
||||||
|
--menuitem-text-hover-fg: var(--menu-text-color);
|
||||||
|
--menuitem-hover-bg: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--menu-text-color),
|
||||||
|
transparent 86%
|
||||||
|
);
|
||||||
|
--menuitem-hover-background-blend-mode: normal;
|
||||||
|
|
||||||
@media screen and (forced-colors: active) {
|
@media screen and (forced-colors: active) {
|
||||||
--menu-bg: Canvas;
|
--menu-bg: Canvas;
|
||||||
--menu-background-blend-mode: normal;
|
--menu-background-blend-mode: normal;
|
||||||
|
|||||||
@ -17,10 +17,11 @@
|
|||||||
@import url(text_layer_builder.css);
|
@import url(text_layer_builder.css);
|
||||||
@import url(annotation_layer_builder.css);
|
@import url(annotation_layer_builder.css);
|
||||||
@import url(xfa_layer_builder.css);
|
@import url(xfa_layer_builder.css);
|
||||||
/* Ignored in GECKOVIEW builds: */
|
/* Ignored in GECKOVIEW: begin */
|
||||||
@import url(annotation_editor_layer_builder.css);
|
@import url(annotation_editor_layer_builder.css);
|
||||||
@import url(sidebar.css);
|
@import url(sidebar.css);
|
||||||
@import url(menu.css);
|
@import url(menu.css);
|
||||||
|
/* Ignored in GECKOVIEW: end */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
--border-color-interactive: light-dark(#8f8f9d, #f9f9fa);
|
--border-color-interactive: light-dark(#8f8f9d, #f9f9fa);
|
||||||
--border-color-interactive-hover: var(--border-color-interactive);
|
--border-color-interactive-hover: var(--border-color-interactive);
|
||||||
--border-color-interactive-active: var(--border-color-interactive);
|
--border-color-interactive-active: var(--border-color-interactive);
|
||||||
|
--focus-outline-offset: 2px;
|
||||||
|
|
||||||
@media (forced-colors: active) {
|
@media (forced-colors: active) {
|
||||||
--color-accent-primary: ButtonText;
|
--color-accent-primary: ButtonText;
|
||||||
|
|||||||
@ -16,12 +16,6 @@
|
|||||||
@import url(pdf_viewer.css);
|
@import url(pdf_viewer.css);
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--dir-factor: 1;
|
|
||||||
--scale-select-width: 140px;
|
|
||||||
|
|
||||||
--toolbar-icon-opacity: 1;
|
|
||||||
--doorhanger-icon-opacity: 0.9;
|
|
||||||
|
|
||||||
--main-color: light-dark(rgb(12 12 13), rgb(249 249 250));
|
--main-color: light-dark(rgb(12 12 13), rgb(249 249 250));
|
||||||
--body-bg-color: light-dark(rgb(212 212 215), rgb(42 42 46));
|
--body-bg-color: light-dark(rgb(212 212 215), rgb(42 42 46));
|
||||||
--scrollbar-color: light-dark(auto, rgb(121 121 123));
|
--scrollbar-color: light-dark(auto, rgb(121 121 123));
|
||||||
@ -46,10 +40,6 @@
|
|||||||
--toolbarButton-download-icon: url(images/gv-toolbarButton-download.svg);
|
--toolbarButton-download-icon: url(images/gv-toolbarButton-download.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root:dir(rtl) {
|
|
||||||
--dir-factor: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (forced-colors: active) {
|
@media screen and (forced-colors: active) {
|
||||||
:root {
|
:root {
|
||||||
--dialog-button-border: 1px solid Highlight;
|
--dialog-button-border: 1px solid Highlight;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user