csstree-validator
Advanced tools
Comparing version 2.0.1 to 3.0.0
@@ -1,5 +0,19 @@ | ||
const cli = require('clap'); | ||
const reporters = require('./reporter'); | ||
const { validatePath, validateString } = require('./helpers'); | ||
import path from 'path'; | ||
import fs from 'fs'; | ||
import resolve from 'resolve'; | ||
import { command as createCommand, Error as CliError } from 'clap'; | ||
import * as reporters from './reporter/index.js'; | ||
import { validatePath, validateString } from './helpers.js'; | ||
import { version } from './version.js'; | ||
async function readStdin() { | ||
const buffer = []; | ||
for await (const chunk of process.stdin) { | ||
buffer.push(chunk); | ||
} | ||
return buffer.join(''); | ||
} | ||
function printResult(result, reporter) { | ||
@@ -18,17 +32,35 @@ const output = reporter(result); | ||
const command = cli.create('csstree-validate', '[fileOrDir]') | ||
.version(require('../package.json').version) | ||
.option('-r, --reporter <name>', 'Format of output: console (default), checkstyle, json, gnu', function(name) { | ||
if (!reporters.hasOwnProperty(name)) { | ||
throw new cli.Error('Wrong value for reporter: ' + name); | ||
} | ||
return name; | ||
}) | ||
.action(function(args) { | ||
const options = this.values; | ||
const command = createCommand('csstree-validate [fileOrDir]') | ||
.version(version) | ||
.option( | ||
'-r, --reporter <nameOrFile>', | ||
'Output formatter: console (default), checkstyle, json, gnu or <path to a module>', | ||
(nameOrFile) => { | ||
const modulePath = path.resolve(process.cwd(), nameOrFile); | ||
if (fs.existsSync(modulePath)) { | ||
return import(modulePath); | ||
} | ||
if (!hasOwnProperty.call(reporters, nameOrFile)) { | ||
try { | ||
const resolvedPath = resolve.sync(nameOrFile, { basedir: process.cwd() }); | ||
return import(resolvedPath); | ||
} catch (e) {} | ||
throw new CliError('Wrong value for reporter: ' + nameOrFile); | ||
} | ||
return nameOrFile; | ||
}, | ||
'console' | ||
) | ||
.action(async ({ options, args }) => { | ||
const inputPath = args[0]; | ||
const reporter = reporters[options.reporter] || reporters.console; | ||
const reporter = typeof options.reporter === 'string' | ||
? reporters[options.reporter] | ||
: (await options.reporter).default; | ||
if (process.stdin.isTTY && !inputPath) { | ||
this.showHelp(); | ||
command.run(['--help']); | ||
return; | ||
@@ -38,7 +70,10 @@ } | ||
if (!inputPath) { | ||
const buffer = []; | ||
process.stdin | ||
.on('data', chunk => buffer.push(chunk)) | ||
.on('end', () => printResult(validateString(buffer.join(''), '<stdin>'), reporter)); | ||
readStdin().then(input => | ||
printResult(validateString(input, '<stdin>'), reporter) | ||
); | ||
} else { | ||
if (!fs.existsSync(inputPath)) { | ||
throw new CliError(`ERROR! No such file or directory: ${inputPath}`); | ||
} | ||
printResult(validatePath(args[0]), reporter); | ||
@@ -48,7 +83,5 @@ } | ||
module.exports = { | ||
run: command.run.bind(command), | ||
isCliError(err) { | ||
return err instanceof cli.Error; | ||
} | ||
}; | ||
export const run = command.run.bind(command); | ||
export function isCliError(err) { | ||
return err instanceof CliError; | ||
} |
@@ -1,7 +0,19 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { validate } = require('./validate'); | ||
import { statSync, readdirSync, readFileSync } from 'fs'; | ||
import { extname, join } from 'path'; | ||
import { validate } from './validate.js'; | ||
function createResult() { | ||
const result = Object.create(null); | ||
result[Symbol.iterator] = function*() { | ||
for (const [filename, errors] of Object.entries(this)) { | ||
yield [filename, errors]; | ||
} | ||
}; | ||
return result; | ||
} | ||
function defaultShouldBeValidated(filename) { | ||
return path.extname(filename) === '.css'; | ||
return extname(filename) === '.css'; | ||
} | ||
@@ -11,8 +23,6 @@ | ||
try { | ||
if (fs.statSync(testPath).isDirectory()) { | ||
return fs.readdirSync(testPath).reduce( | ||
(result, dirFilename) => | ||
result.concat(collectFiles(path.join(testPath, dirFilename), shouldBeValidated)), | ||
[] | ||
); | ||
if (statSync(testPath).isDirectory()) { | ||
return [].concat(...readdirSync(testPath).map(dirFilename => | ||
collectFiles(join(testPath, dirFilename), shouldBeValidated) | ||
)).sort(); | ||
} else { | ||
@@ -26,9 +36,7 @@ return shouldBeValidated(testPath) ? [testPath] : []; | ||
function validateDictionary(dictionary) { | ||
const result = {}; | ||
export function validateDictionary(dictionary) { | ||
const result = createResult(); | ||
for (const filename in dictionary) { | ||
if (Object.prototype.hasOwnProperty.call(dictionary, filename)) { | ||
result[filename] = validate(dictionary[filename], filename); | ||
} | ||
for (const filename of Object.keys(dictionary).sort()) { | ||
result[filename] = validate(dictionary[filename], filename); | ||
} | ||
@@ -39,4 +47,4 @@ | ||
function validateString(css, filename) { | ||
const result = {}; | ||
export function validateString(css, filename) { | ||
const result = createResult(); | ||
@@ -52,8 +60,8 @@ if (!filename) { | ||
function validateFile(filename) { | ||
const result = {}; | ||
export function validateFile(filename) { | ||
const result = createResult(); | ||
let css; | ||
try { | ||
css = fs.readFileSync(filename, 'utf-8'); | ||
css = readFileSync(filename, 'utf-8'); | ||
result[filename] = validate(css, filename); | ||
@@ -68,3 +76,5 @@ } catch (e) { | ||
function validateFileList(list) { | ||
return list.reduce(function(result, filename) { | ||
const result = createResult(); | ||
for (const filename of list) { | ||
const res = validateFile(filename)[filename]; | ||
@@ -75,8 +85,8 @@ | ||
} | ||
} | ||
return result; | ||
}, {}); | ||
return result; | ||
} | ||
function validatePath(searchPath, filter) { | ||
export function validatePathList(pathList, filter) { | ||
if (typeof filter !== 'function') { | ||
@@ -86,6 +96,10 @@ filter = defaultShouldBeValidated; | ||
return validateFileList(collectFiles(searchPath, filter)); | ||
const fileList = new Set([].concat(...pathList.map(path => | ||
collectFiles(path, filter) | ||
))); | ||
return validateFileList([...fileList].sort()); | ||
} | ||
function validatePathList(pathList, filter) { | ||
export function validatePath(searchPath, filter) { | ||
if (typeof filter !== 'function') { | ||
@@ -95,20 +109,3 @@ filter = defaultShouldBeValidated; | ||
const fileList = Object.keys( | ||
pathList.reduce(function(result, searchPath) { | ||
collectFiles(searchPath, filter).forEach(function(filename) { | ||
result[filename] = true; | ||
}); | ||
return result; | ||
}, {}) | ||
); | ||
return validateFileList(fileList); | ||
}; | ||
module.exports = { | ||
validatePathList, | ||
validatePath, | ||
validateFile, | ||
validateDictionary, | ||
validateString | ||
}; | ||
return validateFileList(collectFiles(searchPath, filter)); | ||
} |
@@ -1,5 +0,6 @@ | ||
module.exports = { | ||
...require('./helpers.js'), | ||
...require('./validate'), | ||
reporters: require('./reporter') | ||
}; | ||
import * as reporters from './reporter/index.js'; | ||
export * from './version.js'; | ||
export * from './helpers.js'; | ||
export * from './validate.js'; | ||
export { reporters }; |
@@ -7,3 +7,3 @@ // <?xml version="1.0" encoding="utf-8"?> | ||
// </checkstyle> | ||
module.exports = function(data) { | ||
export default function(result) { | ||
const output = [ | ||
@@ -14,17 +14,15 @@ '<?xml version="1.0" encoding="utf-8"?>', | ||
Object.keys(data).sort().forEach(function(name) { | ||
const errors = data[name]; | ||
for (const [filename, errors] of result) { | ||
output.push( | ||
'\t<file name="' + name + '">', | ||
errors.map(function(entry) { | ||
return '\t\t<error ' + | ||
'line="' + (entry.line || 1) + '" ' + | ||
'column="' + (entry.column || 1) + '" ' + | ||
'severity="error" ' + | ||
'message="' + String(entry.message || entry.error).replace(/&/g, '&').replace(/"/g, '"') + '" source="csstree-validator"/>'; | ||
}).join('\n'), | ||
'\t<file name="' + filename + '">', | ||
errors.map(entry => | ||
'\t\t<error ' + | ||
'line="' + (entry.line || 1) + '" ' + | ||
'column="' + (entry.column || 1) + '" ' + | ||
'severity="error" ' + | ||
'message="' + String(entry.message || entry.error).replace(/&/g, '&').replace(/"/g, '"') + '" source="csstree-validator"/>' | ||
).join('\n'), | ||
'\t</file>' | ||
); | ||
}); | ||
} | ||
@@ -34,2 +32,2 @@ output.push('</checkstyle>'); | ||
return output.join('\n'); | ||
}; | ||
} |
@@ -1,9 +0,7 @@ | ||
module.exports = function(data) { | ||
export default function(result) { | ||
const output = []; | ||
Object.keys(data).sort().forEach(function(filename) { | ||
const errors = data[filename]; | ||
for (const [filename, errors] of result) { | ||
output.push('# ' + filename); | ||
output.push.apply(output, errors.map(function(error) { | ||
output.push(...errors.map(function(error) { | ||
if (error.name === 'SyntaxError') { | ||
@@ -19,5 +17,5 @@ return ' [ERROR] ' + error.message; | ||
output.push(''); | ||
}); | ||
} | ||
return output.join('\n'); | ||
}; | ||
} |
// "FILENAME":LINE.COLUMN: error: MESSAGE | ||
// "FILENAME":START_LINE.COLUMN-END_LINE.COLUMN: error: MESSAGE | ||
module.exports = function(data) { | ||
export default function(result) { | ||
const output = []; | ||
Object.keys(data).sort().forEach(function(filename) { | ||
const errors = data[filename]; | ||
output.push(errors.map(function(error) { | ||
for (const [filename, errors] of result) { | ||
output.push(errors.map((error) => { | ||
const line = error.line || -1; | ||
@@ -31,5 +29,5 @@ const column = error.column || -1; | ||
}).join('\n')); | ||
}); | ||
} | ||
return output.join('\n'); | ||
}; | ||
} |
@@ -1,6 +0,4 @@ | ||
module.exports = { | ||
json: require('./json.js'), | ||
console: require('./console.js'), | ||
checkstyle: require('./checkstyle.js'), | ||
gnu: require('./gnu.js') | ||
}; | ||
export { default as json } from './json.js'; | ||
export { default as console } from './console.js'; | ||
export { default as checkstyle } from './checkstyle.js'; | ||
export { default as gnu } from './gnu.js'; |
// [{ "name": {file}, "line": {line},"column": {column},"message": {error} }] | ||
module.exports = function(data) { | ||
const output = Object.keys(data).sort().reduce(function(res, name) { | ||
const errors = data[name]; | ||
export default function(result) { | ||
const output = []; | ||
return res.concat(errors.map(function(entry) { | ||
for (const [filename, errors] of result) { | ||
output.push(...errors.map((entry) => { | ||
const error = entry.error || entry; | ||
return { | ||
name: name, | ||
name: filename, | ||
line: entry.line || 1, | ||
@@ -18,5 +18,5 @@ column: entry.column || 1, | ||
})); | ||
}, []); | ||
} | ||
return JSON.stringify(output, null, 4); | ||
}; | ||
} |
@@ -1,4 +0,5 @@ | ||
const csstree = require('css-tree'); | ||
const syntax = csstree.lexer; | ||
import { lexer, parse, walk, property as propertyName } from 'css-tree'; | ||
const syntax = lexer; | ||
function isTargetError(error) { | ||
@@ -18,3 +19,3 @@ if (!error) { | ||
function validateAtrule(node) { | ||
export function validateAtrule(node) { | ||
const atrule = node.name; | ||
@@ -26,4 +27,6 @@ const errors = []; | ||
errors.push(Object.assign(error, { | ||
atrule, | ||
...node.loc && node.loc.start | ||
})); | ||
return errors; | ||
@@ -54,3 +57,3 @@ } | ||
function validateAtrulePrelude(atrule, prelude, preludeLoc) { | ||
export function validateAtrulePrelude(atrule, prelude, preludeLoc) { | ||
const errors = []; | ||
@@ -61,6 +64,8 @@ let error; | ||
errors.push(Object.assign(error, { | ||
...preludeLoc || (prelude && prelude.loc && prelude.loc.start) | ||
atrule, | ||
...preludeLoc | ||
})); | ||
} else if (error = isTargetError(syntax.matchAtrulePrelude(atrule, prelude).error)) { | ||
errors.push(Object.assign(error, { | ||
atrule, | ||
...error.rawMessage === 'Mismatch' && | ||
@@ -74,3 +79,3 @@ { details: error.message, message: 'Invalid value for `@' + atrule + '` prelude' } | ||
function validateAtruleDescriptor(atrule, descriptor, value, descriptorLoc) { | ||
export function validateAtruleDescriptor(atrule, descriptor, value, descriptorLoc) { | ||
const errors = []; | ||
@@ -83,3 +88,3 @@ let error; | ||
descriptor, | ||
...descriptorLoc || (value && value.loc && value.loc.start) | ||
...descriptorLoc | ||
})); | ||
@@ -100,10 +105,14 @@ } else { | ||
function validateDeclaration(property, value, valueLoc) { | ||
export function validateDeclaration(property, value, valueLoc) { | ||
const errors = []; | ||
let error; | ||
if (propertyName(property).custom) { | ||
return errors; | ||
} | ||
if (error = isTargetError(syntax.checkPropertyName(property))) { | ||
errors.push(Object.assign(error, { | ||
property, | ||
...valueLoc || (value && value.loc && value.loc.start) | ||
...valueLoc | ||
})); | ||
@@ -121,3 +130,3 @@ } else if (error = isTargetError(syntax.matchProperty(property, value).error)) { | ||
function validateRule(node) { | ||
export function validateRule(node) { | ||
const errors = []; | ||
@@ -140,7 +149,7 @@ | ||
function validate(css, filename) { | ||
export function validate(css, filename) { | ||
const errors = []; | ||
const ast = typeof css !== 'string' | ||
? css | ||
: csstree.parse(css, { | ||
: parse(css, { | ||
filename, | ||
@@ -157,3 +166,3 @@ positions: true, | ||
csstree.walk(ast, { | ||
walk(ast, { | ||
visit: 'Atrule', | ||
@@ -165,3 +174,3 @@ enter(node) { | ||
csstree.walk(ast, { | ||
walk(ast, { | ||
visit: 'Rule', | ||
@@ -175,10 +184,1 @@ enter(node) { | ||
}; | ||
module.exports = { | ||
validateAtrule, | ||
validateAtrulePrelude, | ||
validateAtruleDescriptor, | ||
validateRule, | ||
validateDeclaration, | ||
validate | ||
}; |
{ | ||
"name": "csstree-validator", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "CSS validator built on csstree", | ||
@@ -15,34 +15,53 @@ "author": "Roman Dvornov <rdvornov@gmail.com>", | ||
"bin": { | ||
"csstree-validator": "./bin/validate" | ||
"csstree-validator": "./bin/validate.js" | ||
}, | ||
"main": "./lib/index", | ||
"type": "module", | ||
"main": "./cjs/index.cjs", | ||
"exports": { | ||
".": { | ||
"import": "./lib/index.js", | ||
"require": "./cjs/index.cjs" | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"unpkg": "dist/csstree-validator.esm.js", | ||
"jsdelivr": "dist/csstree-validator.esm.js", | ||
"browser": { | ||
"./cjs/version.cjs": "./dist/version.cjs", | ||
"./lib/version.js": "./dist/version.js" | ||
}, | ||
"scripts": { | ||
"lint-and-test": "npm run lint && npm test", | ||
"lint": "eslint lib test", | ||
"test": "mocha --reporter dot", | ||
"build": "rollup --config", | ||
"travis": "npm run lint-and-test", | ||
"prepublishOnly": "npm run build" | ||
"test": "mocha test --reporter ${REPORTER:-progress}", | ||
"test:cjs": "mocha cjs-test --reporter ${REPORTER:-progress}", | ||
"test:dist": "mocha dist/test --reporter ${REPORTER:-progress}", | ||
"build": "npm run bundle && npm run esm-to-cjs", | ||
"build-and-test": "npm run build && npm run test:dist && npm run test:cjs", | ||
"bundle": "node scripts/bundle", | ||
"bundle-and-test": "npm run bundle && npm run test:dist", | ||
"esm-to-cjs": "node scripts/esm-to-cjs", | ||
"esm-to-cjs-and-test": "npm run esm-to-cjs && npm run test:cjs", | ||
"coverage": "c8 --reporter=lcovonly npm test", | ||
"prepublishOnly": "npm run lint-and-test && npm run build-and-test" | ||
}, | ||
"browser": { | ||
"css-tree": "css-tree/dist/csstree.min.js" | ||
}, | ||
"dependencies": { | ||
"clap": "^1.1.1", | ||
"css-tree": "^1.1.3" | ||
"clap": "^3.0.0", | ||
"css-tree": "^2.0.2", | ||
"resolve": "^1.20.0" | ||
}, | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
"@rollup/plugin-json": "^4.0.2", | ||
"@rollup/plugin-node-resolve": "^7.1.1", | ||
"eslint": "^6.3.0", | ||
"mocha": "^6.2.3", | ||
"rollup": "^1.32.1", | ||
"rollup-plugin-terser": "^5.3.0" | ||
"c8": "^7.10.0", | ||
"esbuild": "^0.14.2", | ||
"eslint": "^8.4.1", | ||
"mocha": "^9.1.3", | ||
"rollup": "^2.60.2" | ||
}, | ||
"engines": { | ||
"node": ">=8.0.0" | ||
"node": "^12.20.0 || ^14.13.0 || >=15.0.0", | ||
"npm": ">=7.0.0" | ||
}, | ||
"files": [ | ||
"bin", | ||
"cjs", | ||
"dist", | ||
@@ -49,0 +68,0 @@ "lib" |
166
README.md
[](https://www.npmjs.com/package/csstree-validator) | ||
[](https://travis-ci.org/csstree/validator) | ||
[](https://github.com/csstree/validator/actions/workflows/build.yml) | ||
[](https://coveralls.io/github/csstree/validator?branch=master) | ||
# CSS Tree Validator | ||
# CSSTree Validator | ||
CSS validator built on [CSSTree](https://github.com/csstree/csstree) | ||
## How to use: | ||
## Usage | ||
### NPM package | ||
```bash | ||
@@ -16,8 +15,13 @@ > npm install csstree-validator | ||
Manualy validate CSS string or [CSSTree's AST](https://github.com/csstree/csstree/blob/master/docs/ast.md): | ||
Validate CSS string or [CSSTree's AST](https://github.com/csstree/csstree/blob/master/docs/ast.md): | ||
```js | ||
const { validate } = require('./lib'); | ||
import { validate } from 'csstree-validator'; | ||
// Commonjs: | ||
// const { validate } = require('csstree-validator'); | ||
console.log(validate('.class { pading: 10px; border: 1px super red }', 'demo/example.css')); | ||
const filename = 'demo/example.css'; | ||
const css = '.class { pading: 10px; border: 1px super red }'; | ||
console.log(validate(css, filename)); | ||
// [ | ||
@@ -31,35 +35,33 @@ // SyntaxError [SyntaxReferenceError]: Unknown property `pading` { | ||
// }, | ||
// SyntaxError [SyntaxMatchError]: Mismatch { | ||
// message: 'Invalid value for `border` property', | ||
// rawMessage: 'Mismatch', | ||
// syntax: '<line-width> || <line-style> || <color>', | ||
// css: '1px super red', | ||
// mismatchOffset: 4, | ||
// mismatchLength: 5, | ||
// offset: 35, | ||
// line: 1, | ||
// column: 36, | ||
// loc: { source: 'demo/example.css', start: [Object], end: [Object] }, | ||
// property: 'border', | ||
// details: 'Mismatch\n' + | ||
// ' syntax: <line-width> || <line-style> || <color>\n' + | ||
// ' value: 1px super red\n' + | ||
// ' ------------^' | ||
// } | ||
// SyntaxError [SyntaxMatchError]: Mismatch { | ||
// message: 'Invalid value for `border` property', | ||
// rawMessage: 'Mismatch', | ||
// syntax: '<line-width> || <line-style> || <color>', | ||
// css: '1px super red', | ||
// mismatchOffset: 4, | ||
// mismatchLength: 5, | ||
// offset: 35, | ||
// line: 1, | ||
// column: 36, | ||
// loc: { source: 'demo/example.css', start: [Object], end: [Object] }, | ||
// property: 'border', | ||
// details: 'Mismatch\n' + | ||
// ' syntax: <line-width> || <line-style> || <color>\n' + | ||
// ' value: 1px super red\n' + | ||
// ' ------------^' | ||
// } | ||
// ] | ||
``` | ||
Another option is to use helpers to validate a file or directory and buildin reporters: | ||
Another option is to use helpers to validate a file or a directory and one of buildin reporters: | ||
```js | ||
const { validateFile } = require('csstree-validator'); | ||
const reporter = require('csstree-validator').reporters.checkstyle; | ||
import { validateFile, reporters } from 'csstree-validator'; | ||
console.log(reporter(validateFile('/path/to/style.css'))); | ||
console.log(reporters.checkstyle(validateFile('./path/to/style.css'))); | ||
``` | ||
#### API | ||
### Validate methods | ||
Validate methods: | ||
* validate(css, filename) | ||
* validateAtrule(node) | ||
@@ -70,10 +72,18 @@ * validateAtrulePrelude(atrule, prelude, preludeLoc) | ||
* validateRule(node) | ||
* validate(css, filename) | ||
Helpers: | ||
## Helpers | ||
All helper function return an object where key is a path to a file and value is an array of errors. The result object is iterable (has `Symbol.iterator`) and can be used with `for ... of` or `...` operator. | ||
```js | ||
const result = validateFile('path/to/file.css'); | ||
for (const [filename, errors] of result) { | ||
// ... | ||
} | ||
``` | ||
* validateString(css, filename) | ||
* validateDictionary(dictionary) | ||
* validateString(css, filename) | ||
* validateFile(filename) | ||
* validateFileList(list) | ||
* validatePath(searchPath, filter) | ||
@@ -84,20 +94,46 @@ * validatePathList(pathList, filter) | ||
* json | ||
* console | ||
* checkstyle | ||
* gnu | ||
* `json` | ||
* `console` | ||
* `checkstyle` | ||
* `gnu` | ||
### Library in a browser | ||
## Using in a browser | ||
Available bundles to use in a browser: | ||
- `dist/csstree-validator.js` – minified IIFE with `csstreeValidator` as a global | ||
```html | ||
<script src="csstree-validator/dist/csstree-validator.js"></script> | ||
<script src="node_modules/csstree-validator/dist/csstree-validator.js"></script> | ||
<script> | ||
const errors = csstreeValidator.validate('.some { css: source }'); | ||
const errors = csstreeValidator.validate('.some { css: source }'); | ||
</script> | ||
``` | ||
NOTE: Helpers and reporters are not available for browser version at the moment. | ||
- `dist/csstree-validator.esm.js` – minified ES module | ||
```html | ||
<script type="module"> | ||
import { validate } from "csstree-validator/dist/csstree-validator.esm.js"; | ||
### CLI (terminal command) | ||
const errors = validate('.some { css: source }'); | ||
</script> | ||
``` | ||
One of CDN services like `unpkg` or `jsDelivr` can be used. By default (for short path) a ESM version is exposing. For IIFE version a full path to a bundle should be specified: | ||
```html | ||
<!-- ESM --> | ||
<script type="module"> | ||
import * as csstreeValidator from 'https://cdn.jsdelivr.net/npm/csstree-validator'; | ||
import * as csstreeValidator from 'https://unpkg.com/csstree-validator'; | ||
</script> | ||
<!-- IIFE with csstreeValidator as a global --> | ||
<script src="https://cdn.jsdelivr.net/npm/csstree-validator/dist/csstree-validator.js"></script> | ||
<script src="https://unpkg.com/csstree-validator/dist/csstree-validator.js"></script> | ||
``` | ||
NOTE: Helpers and reporters are not available for browser's version. | ||
## CLI (terminal command) | ||
```bash | ||
@@ -112,11 +148,43 @@ > npm install -g csstree-validator | ||
csstree-validate [fileOrDir] [options] | ||
csstree-validate [fileOrDir] [options] | ||
Options: | ||
-h, --help Output usage information | ||
-r, --reporter <name> Format of output: console (default), checkstyle, json, gnu | ||
-v, --version Output version | ||
-h, --help Output usage information | ||
-r, --reporter <nameOrFile> Output formatter: console (default), checkstyle, json, gnu | ||
or <path to a module> | ||
-v, --version Output version | ||
``` | ||
### Custom reporters | ||
In addition to predefined (buildin) reporters, you can specify the path to a module or a package with a custom reporter. Such module should export a single function which takes the validation result object and returns a string: | ||
```js | ||
export default function(result) { | ||
const output = ''; | ||
for (const [filename, errors] of result) { | ||
// ... | ||
} | ||
return output; | ||
} | ||
// For CommonJS: | ||
// module.exports = function(result) { ... } | ||
``` | ||
The specifier for a custom reporter might be: | ||
- ESM module – a full path to a file with `.js` extension | ||
- CommonJS module – a full path to a file with `.cjs` extension | ||
- ESM package – a package name or a full path to package's module (i.e. `package/lib/index.js`) | ||
- CommonJS package – a package name or a path to package's module (i.e. `package/lib/index.js`, `package/lib/index` or `package/lib`) | ||
- Dual package – a package name or a full path to package's module | ||
The resolution algorithm is testing `reporter` option value in the following order: | ||
- If a value is a path to a file (a base dir for relative paths is `process.cwd()`), then use it a module | ||
- If a value is a path to a package module (a base dir for `node_modules` is `process.cwd()`), then use package's module | ||
- Otherwise the value should be a name of one of predifined reporter, or an error will be raised | ||
## Ready to use | ||
@@ -123,0 +191,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
369273
5
30
2141
198
Yes
3
8
+ Addedresolve@^1.20.0
+ Addedansi-colors@4.1.3(transitive)
+ Addedclap@3.1.1(transitive)
+ Addedcss-tree@2.3.1(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedis-core-module@2.16.1(transitive)
+ Addedmdn-data@2.0.30(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedresolve@1.22.10(transitive)
+ Addedsource-map-js@1.2.1(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
- Removedansi-regex@2.1.1(transitive)
- Removedansi-styles@2.2.1(transitive)
- Removedchalk@1.1.3(transitive)
- Removedclap@1.2.3(transitive)
- Removedcss-tree@1.1.3(transitive)
- Removedescape-string-regexp@1.0.5(transitive)
- Removedhas-ansi@2.0.0(transitive)
- Removedmdn-data@2.0.14(transitive)
- Removedsource-map@0.6.1(transitive)
- Removedstrip-ansi@3.0.1(transitive)
- Removedsupports-color@2.0.0(transitive)
Updatedclap@^3.0.0
Updatedcss-tree@^2.0.2