Skip to main content

CLI and linting

Jess ships one CLI with separate compile and lint workflows:

jess input.less output.css
jess lint "src/**/*.{css,less,scss,jess}"

The default command compiles one input file to CSS. The lint subcommand reports diagnostics without writing CSS. jess --version and jess lint --version print the installed version.

Compile​

Compile a stylesheet by passing the input file first:

jess input.less

Jess compiles one .less, .scss, .jess or .css file per run. It writes input.css next to the source file. Pass an output file, or an existing output directory with -o, when you want to control the destination:

jess input.less dist/input.css
jess input.less -o dist
jess input.less app.css -o dist # writes dist/app.css

To compile several files, run Jess once per file:

for f in src/*.less; do jess "$f" -o dist; done

A .css input goes through the same output options as the other languages, so Jess can flatten its native nesting or minify it. Its default output, input.css, is the input itself, which Jess never overwrites: give an output path or a different -o directory.

jess input.css dist/input.css
jess input.css -o dist

jess a.less b.less does not compile two files: the second argument is the output, and Jess refuses it because it is named like a stylesheet. A third argument is an error. Reading a stylesheet from stdin with - is not supported. Use /dev/stdout as the output to print the CSS.

How the output is written​

  • An existing output file is replaced, not written into: the CSS goes to a new file that is renamed over it. A symlink there is replaced rather than followed, and other names of a hard-linked file keep their contents. A terminal, pipe or device (such as /dev/stdout) is written directly.
  • Jess refuses an output that is the input file under any name (compared on disk, so a hard link or a case variant counts), that is named like a stylesheet (.less, .scss, .sass, .jess), or that is a symlink to one.

Diagnostics go to stderr. Color and terminal hyperlinks are on only when stderr is a terminal and NO_COLOR is unset; --color and --no-color override that.

Exit statusMeaning
0The CSS was written.
1The stylesheet failed to compile, or a file could not be read or written.
2Invalid command line: an unknown option, a missing or extra argument, or a refused output path.

Settings such as output: { collapseNesting: true } come from styles.config.* files. Jess merges every one from the input file's folder up to the package root (the first folder with a package.json), the nearest file winning setting by setting.

To import stylesheets from hosts you trust over https, name them with --allow-remote-imports (comma-separated; the flag may repeat). It needs @jesscss/plugin-remote-import installed next to jess:

jess input.less --allow-remote-imports cdn.example.com

Without it, an @import of a URL stays in the output as a plain CSS @import and nothing is downloaded.

The default command is intentionally short because it mirrors familiar tools: sass input.scss output.css, lessc input.less output.css, and tsc all keep the primary build workflow close to the command name. Linting is explicit because it is a different operation with a different exit policy.

Lint​

Run lint with no arguments to use lint.files from styles.config.js. If no lint file patterns are configured, Jess scans **/*.{css,less,scss,jess}.

jess lint

Pass files or glob patterns to lint a specific set:

jess lint "src/**/*.{css,less,scss,jess}"
jess lint src/app.scss

Text output is compact: one file heading, one line per diagnostic, then a summary.

src/app.css
2:3 warning property-no-unknown Unknown property: 'colr'
3:10 warning length-zero-no-unit The unit "px" is unnecessary for a zero value
Linted 1 file(s): 0 error(s), 2 warning(s)

Lint Options​

OptionWhat it does
--format textPrint compact human-readable output. This is the default.
--format jsonPrint the full structured lint result as JSON, including lint ruleName and shared diagnostic code.
--max-warnings <n>Exit non-zero when warnings exceed n. Use --max-warnings 0 in CI.
--syntax-onlyReport parser diagnostics only.
--quietSuppress warnings in text output.
--config <path>Load a specific styles.config.js file.
--color, --no-colorTurn ANSI color and terminal hyperlinks on or off. By default they are on only when stdout is a terminal and NO_COLOR is unset.

jess lint exits with 0 when it finds no errors and no more warnings than --max-warnings, 1 when it finds an error or too many warnings, and 2 for an invalid command line.

Configure Lint​

Configure linting in styles.config.js:

export default {
lint: {
files: ['src/**/*.{css,less,scss,jess}'],
ignoreFiles: ['dist/**'],
reportSyntax: true,
rules: {
'block-no-empty': ['warn', { include: ['mixins'] }],
'property-no-unknown': 'error',
'declaration-block-no-duplicate-properties': ['warn', { ignore: ['consecutive-duplicates'] }],
'length-zero-no-unit': 'warn',
'jess/no-unused-variable': 'off',
'jess/no-unused-mixin': 'off',
'jess/no-unused-function': 'off',
'jess/no-duplicate-module-load': 'warn',
'jess/no-unbounded-extend': 'warn',
'jess/no-dead-extend': 'warn',
'jess/no-suspicious-map-key-access': 'warn',
'vendor-prefix': 'warn',
'compatible-vendor-prefixes': 'off',
'unknown-vendor-specific-properties': 'off',
'value-no-vendor-prefix': 'off',
'selector-class-pattern': ['off', { pattern: '^[a-z][a-z0-9-]*$' }],
'custom-property-pattern': ['off', { pattern: '^--[a-z][a-z0-9-]*$' }],
'keyframes-name-pattern': ['off', { pattern: '^[a-z][a-z0-9-]*$' }],
'color-function-notation': ['off', { notation: 'modern' }],
'alpha-value-notation': ['off', { notation: 'percentage' }],
'hue-degree-notation': ['off', { notation: 'angle' }],
'float': 'off',
'jess/no-shadowed-token': 'off',
'jess/unsupported-sass-form': 'warn'
}
}
}

Rule severity values are off, warn, and error; null also disables a rule. Rules that support secondary options can use a Stylelint-like tuple: ['warn', { ...options }].

block-no-empty reports empty rulesets by default. Use ['warn', { include: ['mixins'] }] to also report empty Less, SCSS, and Jess mixin bodies.

Naming convention rules such as selector-class-pattern, custom-property-pattern, and keyframes-name-pattern are opt-in and require a secondary pattern option.

Notation convention rules such as color-function-notation, alpha-value-notation, and hue-degree-notation are opt-in and require a secondary notation option. Their lint rule names match Stylelint for migration familiarity; their diagnostic codes remain Jess-owned shared identities.

CSS validity rules use VSCode web custom data where possible, including property names, at-rule descriptors, and simple static descriptor/property values.

What Jess Checks Today​

Jess's stable lint set is deliberately small:

Rule nameJess diagnostic codeWhat it catches
block-no-emptylint/empty-rulesEmpty rulesets; empty mixin bodies with include: ['mixins']
property-no-unknownlint/unknown-propertyUnknown CSS properties
property-no-deprecatedlint/property-no-deprecatedDeprecated or obsolete CSS properties from web custom data
at-rule-no-unknownlint/unknown-at-ruleUnknown CSS at-rules
declaration-block-no-duplicate-propertieslint/duplicate-propertyDuplicate declarations in one block
color-no-invalid-hexlint/hex-color-lengthInvalid hex color lengths
length-zero-no-unitlint/zero-unitsZero length values that do not need a unit
jess/no-unused-variablelint/no-unused-variableOpt-in same-file unused Less, SCSS, and Jess variables
jess/no-unused-mixinlint/no-unused-mixinOpt-in same-file unused Less, SCSS, and Jess mixins
jess/no-unused-functionlint/no-unused-functionOpt-in same-file unused SCSS and Jess functions
jess/no-duplicate-module-loadlint/no-duplicate-module-loadRepeated same-file static SCSS/Jess module-load directives
jess/no-unbounded-extendlint/no-unbounded-extendStatic Less/SCSS/Jess extend targets with no bounded selector anchor
jess/no-dead-extendlint/no-dead-extendExact static extend targets with no same-file selector match
jess/no-suspicious-map-key-accesslint/no-suspicious-map-key-accessNumeric key access against same-file Less maps, SCSS maps, and Jess collections
vendor-prefixlint/vendor-prefixCSS vendor-prefixed declarations/keyframes without the standard form
property-no-vendor-prefixlint/property-no-vendor-prefixOpt-in authored CSS vendor-prefixed property names
at-rule-no-vendor-prefixlint/at-rule-no-vendor-prefixOpt-in authored CSS vendor-prefixed keyframe at-rules
value-no-vendor-prefixlint/value-no-vendor-prefixOpt-in authored CSS vendor-prefixed value keywords and functions
custom-property-patternlint/custom-property-patternOpt-in static custom property naming convention
keyframes-name-patternlint/keyframes-name-patternOpt-in static keyframes naming convention
color-function-notationlint/color-function-notationOpt-in modern CSS color function notation
alpha-value-notationlint/alpha-value-notationOpt-in alpha channel and opacity notation convention
hue-degree-notationlint/hue-degree-notationOpt-in HSL hue unit notation convention
compatible-vendor-prefixeslint/compatible-vendor-prefixesOpt-in incomplete CSS vendor-prefixed declaration/keyframe sets
unknown-vendor-specific-propertieslint/unknown-vendor-specific-propertyOpt-in unknown CSS vendor-prefixed declarations
import-statementlint/import-statementOpt-in CSS @import loading warnings
floatlint/floatOpt-in CSS float layout warnings
jess/no-shadowed-tokenlint/no-shadowed-tokenOpt-in same-file nested variable shadowing
selector-max-idlint/selector-max-idOpt-in CSS ID selector warnings
selector-max-universallint/selector-max-universalOpt-in CSS universal selector warnings
selector-no-vendor-prefixlint/selector-no-vendor-prefixOpt-in authored CSS vendor-prefixed pseudo selectors
selector-class-patternlint/selector-class-patternOpt-in static class selector naming convention
media-feature-name-no-vendor-prefixlint/media-feature-name-no-vendor-prefixOpt-in authored CSS vendor-prefixed media feature names
jess/unsupported-sass-formunsupported/sass-formSCSS forms Jess recognizes but does not support yet

The lint package owns policy and reporting. Detection lives in the shared Jess diagnostics layer so CLI linting and editor diagnostics improve together. Rule names are the user-facing lint configuration and compact-output labels. Diagnostic codes are the shared identities used by diagnostics-core, the language service, JSON output, and compatibility aliases.

Parser syntax failures are diagnostics, not lint rules. jess lint reports them when reportSyntax is enabled and keeps them out of rule configuration.

Jess Lint and Stylelint​

Stylelint is the established CSS linter. It has a much broader rule catalog than Jess lint today, plus plugins, shareable configs, autofix, custom syntaxes, custom formatters, and mature ecosystem presets. Keep using it for broad CSS convention policy while you rely on Jess lint for diagnostics that need Jess's own parser and language facts.

Jess lint is not a Stylelint adapter. It does not flatten Jess, Less, or SCSS into a PostCSS-shaped tree, and it does not lint rendered CSS. It reports diagnostics from Jess's source model so findings can line up with compile behavior and editor diagnostics.

Use this split when migrating:

NeedBest fit today
Large existing Stylelint configKeep Stylelint
Unknown CSS property or at-rule checks in Jess-parsed filesJess lint
Syntax diagnostics shared with editor toolingJess lint
SCSS support-boundary warningsJess lint
Autofix-heavy style policyStylelint
CI budget for Jess diagnosticsjess lint --max-warnings 0

The @jesscss/lint API exports a Stylelint-comparison policy for tool authors who want to measure the overlapping rule subset:

import {
STYLELINT_COMPARISON_LINT_CONFIG,
stylelintComparisonRules
} from '@jesscss/lint'

That comparison set is intentionally narrower than the recommended Jess lint config. It includes only rules with close Stylelint equivalents and leaves out Jess-only parser/support diagnostics.

Diagnostics Story​

Jess lint is a policy layer over shared diagnostics:

  1. Parsers and diagnostics-core detect problems from the authored source.
  2. @jesscss/lint decides whether each diagnostic is off, a warning, or an error.
  3. jess lint renders compact text or JSON and applies the exit policy.
  4. The language service can consume the same lower-level diagnostics for IDE feedback.

That means improvements to shared diagnostics should improve both CLI linting and editor feedback. CLI-only detectors are intentionally not the long-term shape.

The product order is diagnostics first:

  1. Add useful native diagnostics with stable codes and source spans.
  2. Share them between jess lint and the language service.
  3. Make severity and CI policy easy to configure.
  4. Expand Stylelint-comparable coverage where Jess can detect the same issue from its own source model.

Formatting polish, custom formatter compatibility, and autofix are later layers. Jess will not expose jess lint --fix until fixes can be composed safely against authored source.

API​

Tool authors can use @jesscss/lint directly:

import { lintFiles, formatStyledLintResult } from '@jesscss/lint'

const result = await lintFiles(['src/**/*.less'], {
maxWarnings: 0
})

console.log(formatStyledLintResult(result))

For application projects, prefer the jess lint CLI unless you need a custom Node integration.

Coordinates and Performance​

Line and column information is useful for diagnostics, linting, and language services. Jess keeps that as an opt-in tooling concern: compile-facing parser paths do not enable line tracking just because lint exists.