New:Socket for Asana Is Now Available.Learn more
Sign In

strata-css

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

strata-css - npm Package Compare versions

Comparing version
1.6.13
to
1.6.14
+12
-0
CHANGELOG.md

@@ -5,2 +5,14 @@ # Changelog

## [1.6.14] — 2026-08-05
### Fixed
- **Relative `content` globs resolved against the wrong directory, producing an empty stylesheet.** `scanFiles()` passed patterns to `glob.sync()` without a `cwd`, so a glob like `./src/**/*.jsx` always resolved against `process.cwd()` rather than the Strata project root. Whenever a build ran from a different directory — monorepo package builds, bundlers invoked from a parent directory — **zero files matched and the output contained no utility CSS at all**, with no error. The config itself was located correctly (it is resolved from `opts.cwd`), which made the setup look entirely correct. Globs now resolve against `opts.cwd`, and matched paths are absolute so cache keys, PostCSS dependency messages and watcher paths stay consistent regardless of where the build runs.
- **Files matched by a `content` glob were silently discarded unless their extension was one of eight.** The scanner gated on an allowlist (`.html .jsx .tsx .vue .astro .svelte .js .ts`); anything else matched by the glob was read and thrown away with no warning. This silently broke every non-JS ecosystem — `.php` and `.blade.php` (Laravel, WordPress), `.mdx`/`.md` (Next.js, Astro content), `.erb` (Rails), `.hbs`, `.twig` — and even `.mjs`/`.cjs`. A Laravel project pointing `content` at `./resources/**/*.blade.php` received an empty stylesheet and no diagnostic. The allowlist is replaced by a denylist of binary/media formats: the content glob is the filter, so a file you explicitly asked for is now always scanned. `.svg` is deliberately scanned, as SVG markup can carry class attributes.
### Tests
- 12 new assertions in `test/scanner.js` covering both bugs — `.php`, `.blade.php`, `.mdx`, `.md`, `.erb`, `.hbs`, `.twig`, `.mjs`, `.cjs`, `.svg` are scanned while `.png` is skipped, and a build run from a directory other than the project root resolves its relative globs correctly and emits non-empty CSS. All 12 verified to fail against 1.6.13 and pass with the fix.
- Differential run over 195 repository files confirms zero tokens lost versus the 1.6.13 scanner.
---
## [1.6.13] — 2026-08-04

@@ -7,0 +19,0 @@

+1
-1
{
"name": "strata-css",
"version": "1.6.13",
"version": "1.6.14",
"_versioningNote": "Stable: 1.0.0 / 1.1.0 / 2.0.0 | Beta: 1.1.0-beta.1 / 1.1.0-beta.2",

@@ -5,0 +5,0 @@ "description": "A modern CSS framework combining Bootstrap components with Tailwind JIT processing",

@@ -115,3 +115,3 @@ /**

const classNames = scanFiles(contentGlobs)
const classNames = scanFiles(contentGlobs, cwd)
const { componentCSS, utilityCSS } = generate(classNames, config)

@@ -124,3 +124,3 @@

// when a .tsx file added/changed a utility class.
const watchFiles = getWatchFiles(contentGlobs)
const watchFiles = getWatchFiles(contentGlobs, cwd)
for (let i = 0; i < watchFiles.length; i++) {

@@ -194,3 +194,3 @@ result.messages.push({

const classNames = scanFiles(contentGlobs)
const classNames = scanFiles(contentGlobs, cwd)
const { componentCSS, utilityCSS } = generate(classNames, config)

@@ -197,0 +197,0 @@

@@ -12,4 +12,19 @@ /**

const ALLOWED_EXTENSIONS = new Set([
'.html','.jsx','.tsx','.vue','.astro','.svelte','.js','.ts'
// Previously an allowlist of 8 extensions, which silently discarded any other
// file a content glob matched — .php, .blade.php, .mdx, .erb, .hbs, .twig,
// .mjs and .cjs all produced no classes and no warning. The content glob is
// the user's filter; if they asked for a file, scan it. Only binary/media
// formats that cannot carry class attributes are skipped. .svg is deliberately
// absent from this list — SVG markup can carry class attributes.
const SKIP_EXTENSIONS = new Set([
// images
'.png','.jpg','.jpeg','.gif','.bmp','.ico','.webp','.avif','.tiff','.tif','.psd',
// fonts
'.woff','.woff2','.ttf','.eot','.otf',
// audio / video
'.mp3','.wav','.ogg','.flac','.mp4','.webm','.avi','.mov','.mkv',
// archives
'.zip','.gz','.tgz','.bz2','.7z','.rar','.tar',
// binaries / build artefacts
'.exe','.dll','.so','.dylib','.bin','.wasm','.pdf','.map','.lock',
])

@@ -135,7 +150,13 @@

function getFiles(contentGlobs) {
function getFiles(contentGlobs, cwd) {
// Relative content globs must resolve against the Strata project root, not
// whatever directory the build happens to run from. Without this, a bundler
// invoked from a parent directory (monorepos, some Next/webpack setups)
// matched zero files and emitted a completely empty stylesheet, silently.
const base = cwd || process.cwd()
const allFiles = []
for (let g = 0; g < contentGlobs.length; g++) {
const pattern = contentGlobs[g]
const cached = globCache.get(pattern)
const pattern = contentGlobs[g]
const cacheKey = `${base}::${pattern}`
const cached = globCache.get(cacheKey)

@@ -148,6 +169,8 @@ // Glob results rarely change — cache for 500ms

const files = glob.sync(pattern, { nodir: true })
// absolute:true keeps cache keys, PostCSS dependency messages and watcher
// paths consistent regardless of the caller's working directory.
const files = glob.sync(pattern, { nodir: true, cwd: base, absolute: true })
.filter(f => path.extname(f).toLowerCase() !== '.css')
globCache.set(pattern, { files, time: Date.now() })
globCache.set(cacheKey, { files, time: Date.now() })
files.forEach(f => allFiles.push(f))

@@ -160,3 +183,3 @@ }

const ext = path.extname(filePath).toLowerCase()
if (!ALLOWED_EXTENSIONS.has(ext)) return null
if (SKIP_EXTENSIONS.has(ext)) return null

@@ -215,5 +238,5 @@ let mtime

function scanFiles(contentGlobs) {
function scanFiles(contentGlobs, cwd) {
const allClasses = new Set()
const files = getFiles(contentGlobs)
const files = getFiles(contentGlobs, cwd)

@@ -228,4 +251,4 @@ for (let i = 0; i < files.length; i++) {

function getWatchFiles(contentGlobs) {
return getFiles(contentGlobs)
function getWatchFiles(contentGlobs, cwd) {
return getFiles(contentGlobs, cwd)
}

@@ -235,3 +258,5 @@

if (filePath) {
// Cache keys are absolute; accept either form from callers and watchers.
fileCache.delete(filePath)
fileCache.delete(path.resolve(filePath))
globCache.clear() // a specific file change may mean add/delete — re-glob

@@ -238,0 +263,0 @@ } else {