yegor256/tacit

`validate` Grunt task in `Gruntfile.js` returns success without checking any CSS

Open

#417 opened on Jun 9, 2026

View on GitHub
 (1 comment) (1 reaction) (0 assignees)HTML (99 forks)github user discovery
bughelp wanted

Repository metrics

Stars
 (1,804 stars)
PR merge metrics
 (PR metrics pending)

Description

In Gruntfile.js:124-140 the validate task wires css-validator through glob with a node-style callback: glob("*.css", {}, (err, files) => {...}). The glob package pinned to 13.0.6 in package.json:11 dropped the callback signature in v9 — the destructured glob export is now a Promise-returning function that ignores any third callback argument. The arrow function passed to registerTask returns undefined synchronously, so Grunt marks the task done before the never-fired callback would have queued an async handle, and the default chain ['sasslint', 'sass:dist', 'sass:uncompressed', 'css_purge', 'file_append', 'checkYear', 'validate'] reports success regardless of what the W3C Jigsaw service would have said.

Two further faults compound the silent pass. The task is registered with an arrow function, so this.async() inside the forEach reads the module-scope this, not the Grunt task context, and calling it would throw TypeError: this.async is not a function. The glob pattern "*.css" resolves against the process working directory while srcPath = path.join("${__dirname}/dist", file) reads from dist/, so the iteration set and the read set disagree.

A minimal fix is to convert the task to the modern Promise API: register it with a regular function so this.async() resolves to the Grunt task, await glob("dist/*.css"), drive each css-validator invocation through a Promise, and propagate the aggregate validity through done(false) on the first failure.

Contributor guide