Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

checkcss

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

checkcss - npm Package Compare versions

Comparing version 1.3.1 to 2.0.0

dist/CheckCSS.d.ts

5

dist/index.d.ts

@@ -1,5 +0,4 @@

export declare const CLASS_IDENT_REGEX: RegExp;
export * from './CheckCSS.js';
export declare function ignoreCSS(re: RegExp | undefined): void;
export declare function extractClasses(sel: string): string[];
export default function checkCSS(): void;
export declare function monitorCSS(): void;
export default function checkCSS(): void;

117

dist/index.js

@@ -1,105 +0,30 @@

// Regex for identifying class names in CSS selectors
// REF: https://www.w3.org/TR/selectors-3/#lex
export const CLASS_IDENT_REGEX = /\.-?(?:[_a-z]|[^\0-\x7f]|\\[0-9a-f]{1,6}\s?|\\[^\s0-9a-f])(?:[_a-z0-9-]|[^\0-\x7f]|\\[0-9a-f]{1,6}\s?|\\[^\s0-9a-f])*/gi;
const seen = new Set();
let defined;
import { CheckCSS } from './CheckCSS.js';
export * from './CheckCSS.js';
let ignoreRE;
let checkcss;
const warned = new Set();
function warn(msg) {
if (warned.has(msg))
return;
warned.add(msg);
console.warn(msg);
}
// Legacy API support
export function ignoreCSS(re) {
ignoreRE = re;
}
function checkClassNames(node, includeChildren = false) {
if (node?.classList) {
for (const cl of node.classList) {
// Ignore defined and already-seen classes
if (defined.has(cl) || seen.has(cl))
continue;
// Mark as seen
seen.add(cl);
// Ignore classes that mathc the ignore regex
if (ignoreRE?.test(cl))
continue;
console.warn(`Undefined CSS class: ${cl}`, node);
}
export default function checkCSS() {
warn('checkCSS() is deprecated. Use CheckCSS#scan() instead');
if (!checkcss) {
checkcss = new CheckCSS(document);
checkcss.onClassnameDetected = (classname, el) => {
return ignoreRE?.test(classname) ?? true;
};
}
if (includeChildren) {
for (const el of node.querySelectorAll('*')) {
checkClassNames(el);
}
}
checkcss.scan();
}
function isGroupingRule(rule) {
return 'cssRules' in rule;
}
function isCSSStyleRule(rule) {
return 'selectorText' in rule;
}
export function extractClasses(sel) {
const classnames = sel.match(CLASS_IDENT_REGEX) ?? [];
return classnames.map(c => {
// Strip '.'
c = c.substring(1);
// Unescape numeric escape sequences (\###)
c = c.replaceAll(/\\[0-9a-f]{1,6}\s?/gi, escape => {
return String.fromCodePoint(parseInt(escape.substring(1), 16));
});
// Unescape character escape sequences (\[some char])
c = c.replaceAll(/\\[^\s0-9a-f]/g, c => c.substring(1));
return c;
});
}
function ingestRules(rules) {
for (const rule of rules) {
if (isGroupingRule(rule)) {
// Some rules are groups of rules (e.g. CSSMediaRule), so we need to
// recurse into them
ingestRules(rule.cssRules);
}
else if (isCSSStyleRule(rule)) {
// Add each classname to the defined set
for (const classname of extractClasses(rule.selectorText)) {
defined.add(classname);
}
}
}
}
export function monitorCSS() {
const observer = new MutationObserver(mutationsList => {
for (const mut of mutationsList) {
if (mut.type === 'childList' && mut?.addedNodes) {
for (const el of mut.addedNodes) {
// Ignore text nodes
if (el.nodeType == 3)
continue;
if (!(el instanceof HTMLElement))
return;
// Sweep DOM fragment
checkClassNames(el);
for (const cel of el.querySelectorAll('*')) {
checkClassNames(cel);
}
}
}
else if (mut?.attributeName == 'class') {
// ... if the element 'class' changed
checkClassNames(mut.target);
}
}
});
observer.observe(document, {
attributes: true,
childList: true,
subtree: true,
});
warn('monitorCSS() is deprecated. Use CheckCSS#watch() instead');
checkcss.watch();
}
export default function checkCSS() {
if (defined)
return;
defined = new Set();
// Ingest rules from all stylesheets
for (const sheet of document.styleSheets) {
ingestRules(sheet.cssRules);
}
// Do a sweep of the existing DOM
checkClassNames(document.documentElement, true);
}
//# sourceMappingURL=index.js.map
{
"name": "checkcss",
"version": "1.3.1",
"version": "2.0.0",
"type": "module",
"description": "Utility method for warning when elements have a `class` attribute that refers to an undefined CSS class",
"description": "Detect references to undefined CSS classes",
"main": "dist/index.js",
"types": "dist/index.d.js",
"exports": {
".": "./dist/index.js"
},
"scripts": {
"test": "node test/test.js",
"test:browser": "npx http-server -o /test/browser-test.htm",
"prepare": "rm -fr dist && yarn build",

@@ -31,3 +34,6 @@ "build": "tsc",

"typescript": "^4.7.3"
},
"dependencies": {
"uuid": "^9.0.0"
}
}

@@ -1,19 +0,13 @@

# checkcss
Utility method for warning any time the `class` attribute of an element references an undefined CSS class.
Logic for detecting when DOM elements reference undefined CSS classes.
This module provides two methods:
Note: The `scan()` method uses the [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) API to monitor DOM changes. While this should be pretty efficient, it's probably not something you want to be running in production.
* `checkCSS()` performs a one-time sweep of the DOM.
* `monitorCSS()` Sets up a
[MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to continuously monitor DOM changes, looking for elements that reference undefined CSS classes.
(Note: `monitorCSS()` is fairly efficient but is probably not something you want to be
running in production.)
## Installation
```
npm i checkcss
npm install checkcss
# or
yarn add checkcss
```

@@ -24,12 +18,23 @@

```javascript
import checkCSS, { ignoreCSS, monitorCSS } from 'checkcss';
import { CheckCSS } from 'checkcss';
// (optional) Set a regex for classnames to ignore
ignoreCSS(/^license-|^maintainer-/);
// Create CheckCSS instance
const checkcss = new CheckCSS();
// Check current DOM
checkCSS();
// OPTIONAL: Set hook to filter classnames.
// Return false for classnames that should be ignored.
checkcss.onClassnameDetected = function (classname, element) {
return /^license-|^maintainer-/.test();
};
// ... and setup monitor to check DOM as it changes
monitorCSS();
// OPTIONAL: Set hook for custom logging (replaces default log method)
checkcss.onUndefinedClassname = function (classname) {
// Custom logging goes here
};
// Scan current DOM for undefined classes
checkcss.scan();
// Monitor DOM as it changes
checkcss.watch();
```

@@ -1,117 +0,37 @@

// Regex for identifying class names in CSS selectors
// REF: https://www.w3.org/TR/selectors-3/#lex
export const CLASS_IDENT_REGEX =
/\.-?(?:[_a-z]|[^\0-\x7f]|\\[0-9a-f]{1,6}\s?|\\[^\s0-9a-f])(?:[_a-z0-9-]|[^\0-\x7f]|\\[0-9a-f]{1,6}\s?|\\[^\s0-9a-f])*/gi;
import { CheckCSS } from './CheckCSS.js';
export * from './CheckCSS.js';
const seen = new Set();
let defined: Set<any>;
let ignoreRE: RegExp | undefined;
export function ignoreCSS(re: RegExp | undefined) {
ignoreRE = re;
}
function checkClassNames(node: Element, includeChildren = false) {
if (node?.classList) {
for (const cl of node.classList) {
// Ignore defined and already-seen classes
if (defined.has(cl) || seen.has(cl)) continue;
let checkcss: CheckCSS;
// Mark as seen
seen.add(cl);
// Ignore classes that mathc the ignore regex
if (ignoreRE?.test(cl)) continue;
console.warn(`Undefined CSS class: ${cl}`, node);
}
}
if (includeChildren) {
for (const el of node.querySelectorAll('*')) {
checkClassNames(el);
}
}
const warned = new Set();
function warn(msg: string) {
if (warned.has(msg)) return;
warned.add(msg);
console.warn(msg);
}
function isGroupingRule(rule: CSSRule): rule is CSSGroupingRule {
return 'cssRules' in rule;
// Legacy API support
export function ignoreCSS(re: RegExp | undefined) {
ignoreRE = re;
}
function isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule {
return 'selectorText' in rule;
}
export default function checkCSS() {
warn('checkCSS() is deprecated. Use CheckCSS#scan() instead');
export function extractClasses(sel: string) {
const classnames = sel.match(CLASS_IDENT_REGEX) ?? [];
return classnames.map(c => {
// Strip '.'
c = c.substring(1);
if (!checkcss) {
checkcss = new CheckCSS(document);
// Unescape numeric escape sequences (\###)
c = c.replaceAll(/\\[0-9a-f]{1,6}\s?/gi, escape => {
return String.fromCodePoint(parseInt(escape.substring(1), 16));
});
checkcss.onClassnameDetected = (classname, el) => {
return ignoreRE?.test(classname) ?? true;
};
}
// Unescape character escape sequences (\[some char])
c = c.replaceAll(/\\[^\s0-9a-f]/g, c => c.substring(1));
return c;
});
checkcss.scan();
}
function ingestRules(rules: CSSRuleList) {
for (const rule of rules) {
if (isGroupingRule(rule)) {
// Some rules are groups of rules (e.g. CSSMediaRule), so we need to
// recurse into them
ingestRules(rule.cssRules);
} else if (isCSSStyleRule(rule)) {
// Add each classname to the defined set
for (const classname of extractClasses(rule.selectorText)) {
defined.add(classname);
}
}
}
}
export function monitorCSS() {
const observer = new MutationObserver(mutationsList => {
for (const mut of mutationsList) {
if (mut.type === 'childList' && mut?.addedNodes) {
for (const el of mut.addedNodes) {
// Ignore text nodes
if (el.nodeType == 3) continue;
if (!(el instanceof HTMLElement)) return;
// Sweep DOM fragment
checkClassNames(el);
for (const cel of el.querySelectorAll('*')) {
checkClassNames(cel);
}
}
} else if (mut?.attributeName == 'class') {
// ... if the element 'class' changed
checkClassNames(mut.target as Element);
}
}
});
observer.observe(document, {
attributes: true,
childList: true,
subtree: true,
});
warn('monitorCSS() is deprecated. Use CheckCSS#watch() instead');
checkcss.watch();
}
export default function checkCSS() {
if (defined) return;
defined = new Set();
// Ingest rules from all stylesheets
for (const sheet of document.styleSheets) {
ingestRules(sheet.cssRules);
}
// Do a sweep of the existing DOM
checkClassNames(document.documentElement, true);
}

@@ -8,6 +8,10 @@ import assert from 'assert';

// Sampling of selector patterns that show up in the `tailwind` framework. "X" =
// text of some sort, "0" = numeric digits of some sort.
// Sampling of selector patterns that show up in the Tailwind framework
// "X" = text of some sort, "0" = numeric digits of some sort.
const TAILWIND_SELECTORS = {
'.w-[32px]': ['w-[32px]'],
'.left-1/2': ['left-1/2'],
'.-X\\.X': ['-X.X'],
'.-X\\.X > :X([X]) ~ :X([X])': ['-X.X'],

@@ -14,0 +18,0 @@ '.X, .X, .X': ['X', 'X', 'X'],

{
"compilerOptions": {
"declaration": true,
"moduleResolution": "node",
"outDir": "./dist",

@@ -5,0 +6,0 @@ "sourceMap": true,

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc