strata-css 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +730 -730
  2. package/bin/strata.js +332 -177
  3. package/package.json +68 -68
  4. package/src/index.js +171 -171
package/package.json CHANGED
@@ -1,68 +1,68 @@
1
- {
2
- "name": "strata-css",
3
- "version": "1.0.2",
4
- "_versioningNote": "Stable: 1.0.0 / 1.1.0 / 2.0.0 | Beta: 1.1.0-beta.1 / 1.1.0-beta.2",
5
- "description": "A modern CSS framework combining Bootstrap components with Tailwind JIT processing",
6
- "main": "src/index.js",
7
- "types": "index.d.ts",
8
- "exports": {
9
- ".": "./src/index.js",
10
- "./package.json": "./package.json"
11
- },
12
- "bin": {
13
- "strata-css": "bin/strata.js"
14
- },
15
- "files": [
16
- "src/",
17
- "bin/",
18
- "strata.css",
19
- "index.d.ts",
20
- "README.md",
21
- "LICENSE",
22
- "CHANGELOG.md"
23
- ],
24
- "scripts": {
25
- "dev": "node bin/strata.js --watch",
26
- "build": "node bin/strata.js --build",
27
- "minify": "node bin/strata.js --minify",
28
- "benchmark": "node --expose-gc benchmark/run.js",
29
- "publish:stable": "npm publish --tag latest",
30
- "publish:beta": "npm publish --tag beta"
31
- },
32
- "keywords": [
33
- "css",
34
- "framework",
35
- "postcss",
36
- "postcss-plugin",
37
- "jit",
38
- "tailwind",
39
- "tailwindcss",
40
- "bootstrap",
41
- "component-library",
42
- "utility-first",
43
- "theming",
44
- "dark-mode",
45
- "css-framework"
46
- ],
47
- "author": "Aftab Ibrahim Kazi",
48
- "license": "MIT",
49
- "homepage": "https://aftabibrahimkazi.github.io/strata",
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/AftabIbrahimKazi/strata.git"
53
- },
54
- "bugs": {
55
- "url": "https://github.com/AftabIbrahimKazi/strata/issues"
56
- },
57
- "type": "commonjs",
58
- "engines": {
59
- "node": ">=18.0.0"
60
- },
61
- "dependencies": {
62
- "autoprefixer": "^10.5.0",
63
- "chokidar": "^5.0.0",
64
- "cssnano": "^8.0.1",
65
- "glob": "^13.0.6",
66
- "postcss": "^8.5.14"
67
- }
68
- }
1
+ {
2
+ "name": "strata-css",
3
+ "version": "1.0.4",
4
+ "_versioningNote": "Stable: 1.0.0 / 1.1.0 / 2.0.0 | Beta: 1.1.0-beta.1 / 1.1.0-beta.2",
5
+ "description": "A modern CSS framework combining Bootstrap components with Tailwind JIT processing",
6
+ "main": "src/index.js",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": "./src/index.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "bin": {
13
+ "strata-css": "bin/strata.js"
14
+ },
15
+ "files": [
16
+ "src/",
17
+ "bin/",
18
+ "strata.css",
19
+ "index.d.ts",
20
+ "README.md",
21
+ "LICENSE",
22
+ "CHANGELOG.md"
23
+ ],
24
+ "scripts": {
25
+ "dev": "node bin/strata.js --watch",
26
+ "build": "node bin/strata.js --build",
27
+ "minify": "node bin/strata.js --minify",
28
+ "benchmark": "node --expose-gc benchmark/run.js",
29
+ "publish:stable": "npm publish --tag latest",
30
+ "publish:beta": "npm publish --tag beta"
31
+ },
32
+ "keywords": [
33
+ "css",
34
+ "framework",
35
+ "postcss",
36
+ "postcss-plugin",
37
+ "jit",
38
+ "tailwind",
39
+ "tailwindcss",
40
+ "bootstrap",
41
+ "component-library",
42
+ "utility-first",
43
+ "theming",
44
+ "dark-mode",
45
+ "css-framework"
46
+ ],
47
+ "author": "Aftab Ibrahim Kazi",
48
+ "license": "MIT",
49
+ "homepage": "https://aftabibrahimkazi.github.io/strata",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/AftabIbrahimKazi/strata.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/AftabIbrahimKazi/strata/issues"
56
+ },
57
+ "type": "commonjs",
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "dependencies": {
62
+ "autoprefixer": "^10.5.0",
63
+ "chokidar": "^5.0.0",
64
+ "cssnano": "^8.0.1",
65
+ "glob": "^13.0.6",
66
+ "postcss": "^8.5.14"
67
+ }
68
+ }
package/src/index.js CHANGED
@@ -1,171 +1,171 @@
1
- /**
2
- * Strata CSS — PostCSS Plugin — Optimised v6
3
- *
4
- * Warm builds bypass PostCSS entirely — no node creation, no GC pressure
5
- * Cold builds run full PostCSS pipeline (including autoprefixer etc.)
6
- * Warm builds return cached string directly — zero object allocation
7
- */
8
-
9
- 'use strict'
10
-
11
- const path = require('path')
12
- const fs = require('fs')
13
- let postcss
14
-
15
- // ─── State ────────────────────────────────────────────────────────────
16
- let dirty = true
17
- let cachedCSS = null // final output CSS string from last cold build
18
-
19
- // ─── Config cache ─────────────────────────────────────────────────────
20
- let cachedConfig = null
21
- let cachedConfigPath = null
22
- let cachedConfigMtime = 0
23
-
24
- function loadConfig(cwd) {
25
- const configPath = path.resolve(cwd, 'strata.config.js')
26
- const configPathCjs = path.resolve(cwd, 'strata.config.cjs')
27
-
28
- if (fs.existsSync(configPathCjs)) {
29
- try { return require(configPathCjs) } catch {}
30
- }
31
-
32
- if (fs.existsSync(configPath)) {
33
- try { return require(configPath) } catch {}
34
- }
35
-
36
- return {}
37
- }
38
-
39
- // ─── Base CSS ─────────────────────────────────────────────────────────
40
- const BASE_CSS = require('./layers/base').trim()
41
- let BASE_AST = null
42
-
43
- function getBaseAST() {
44
- if (!postcss) postcss = require('postcss')
45
- if (!BASE_AST) BASE_AST = postcss.parse(BASE_CSS)
46
- return BASE_AST
47
- }
48
-
49
- // ─── Input CSS cache ───────────────────────────────────────────────────
50
- // strata.css rarely changes — cache it with mtime check
51
- let cachedInputCSS = null
52
- let cachedInputPath = null
53
- let cachedInputMtime = 0
54
-
55
- function readInputCSS(inputCSSPath) {
56
- let mtime = 0
57
- try { mtime = fs.statSync(inputCSSPath).mtimeMs } catch {}
58
- if (cachedInputCSS && cachedInputPath === inputCSSPath && cachedInputMtime === mtime) {
59
- return cachedInputCSS
60
- }
61
- cachedInputCSS = fs.readFileSync(inputCSSPath, 'utf8')
62
- cachedInputPath = inputCSSPath
63
- cachedInputMtime = mtime
64
- return cachedInputCSS
65
- }
66
-
67
- // ─── PostCSS Plugin ───────────────────────────────────────────────────
68
- // Only runs on cold builds — warm builds bypass via strata.build()
69
-
70
- const plugin = (opts = {}) => ({
71
- postcssPlugin: 'strata-css',
72
-
73
- async Once(root) {
74
- if (!postcss) postcss = require('postcss')
75
-
76
- const cwd = opts.cwd || process.cwd()
77
- const config = loadConfig(cwd)
78
-
79
- const { scanFiles } = require('./scanner/scanner')
80
- const { generate } = require('./generator/generator')
81
-
82
- const contentGlobs = config.content || [
83
- './src/**/*.{html,jsx,tsx,vue,astro,svelte,js,ts}'
84
- ]
85
-
86
- const classNames = scanFiles(contentGlobs)
87
- const { componentCSS, utilityCSS } = generate(classNames, config)
88
-
89
- // Replace @strata directives
90
- let baseInserted = false
91
- root.walkAtRules('strata', rule => {
92
- const d = rule.params.trim()
93
- if (d === 'base' && !baseInserted) {
94
- rule.replaceWith(getBaseAST().clone())
95
- baseInserted = true
96
- } else if (d === 'components') {
97
- // componentCSS now contains multiple @layer sub-layer blocks
98
- componentCSS ? rule.replaceWith(postcss.parse(componentCSS)) : rule.remove()
99
- } else if (d === 'utilities') {
100
- // utilityCSS now contains multiple @layer sub-layer blocks
101
- utilityCSS ? rule.replaceWith(postcss.parse(utilityCSS)) : rule.remove()
102
- } else {
103
- rule.remove()
104
- }
105
- })
106
- }
107
- })
108
-
109
- plugin.postcss = true
110
- module.exports = plugin
111
-
112
- // ─── Build API — used by CLI ──────────────────────────────────────────
113
- // Warm builds bypass PostCSS entirely — zero allocation, zero GC pressure
114
-
115
- module.exports.build = async (inputCSSPath, outputCSSPath, opts = {}) => {
116
- // ── Warm path: return cached CSS, no work at all ──────────────────
117
- if (!dirty && cachedCSS) {
118
- if (outputCSSPath) fs.writeFileSync(outputCSSPath, cachedCSS)
119
- return cachedCSS
120
- }
121
-
122
- // ── Cold path: string assembly — no PostCSS parse/stringify ───────
123
- // PostCSS parse → AST clone → replaceWith → stringify is a costly
124
- // round-trip that adds no transformation. We replace @strata directives
125
- // via regex on the raw string, which is O(n) on the input file only.
126
- const cwd = opts.cwd || process.cwd()
127
- const config = loadConfig(cwd)
128
-
129
- const { scanFiles } = require('./scanner/scanner')
130
- const { generate } = require('./generator/generator')
131
-
132
- const contentGlobs = config.content || [
133
- './src/**/*.{html,jsx,tsx,vue,astro,svelte,js,ts}'
134
- ]
135
-
136
- const classNames = scanFiles(contentGlobs)
137
- const { componentCSS, utilityCSS } = generate(classNames, config)
138
-
139
- // Read input CSS (cached by mtime — strata.css rarely changes)
140
- const inputCSS = readInputCSS(inputCSSPath)
141
-
142
- // Replace @strata directives with pre-built CSS strings.
143
- // Use function replacements (not string literals) so any `$` sequences
144
- // in the CSS (e.g. inside comments) are never treated as regex back-references.
145
- const css = inputCSS
146
- .replace(/^\s*@strata\s+base\s*;/m, () => BASE_CSS)
147
- .replace(/^\s*@strata\s+components\s*;/m, () => componentCSS || '')
148
- .replace(/^\s*@strata\s+utilities\s*;/m, () => utilityCSS || '')
149
-
150
- cachedCSS = css
151
- dirty = false
152
-
153
- if (outputCSSPath) {
154
- fs.mkdirSync(path.dirname(outputCSSPath), { recursive: true })
155
- fs.writeFileSync(outputCSSPath, css)
156
- }
157
-
158
- return css
159
- }
160
-
161
- // ─── Cache invalidation ───────────────────────────────────────────────
162
- module.exports.invalidate = (changedFile) => {
163
- dirty = true
164
- cachedCSS = null
165
- const { clearFileCache } = require('./scanner/scanner')
166
- clearFileCache(changedFile)
167
- }
168
-
169
- // ─── Direct PostCSS usage (for users using postcss.config.js) ────────
170
- // Warm path still applies — cached CSS is injected as a raw parse
171
- module.exports.postcss = true
1
+ /**
2
+ * Strata CSS — PostCSS Plugin — Optimised v6
3
+ *
4
+ * Warm builds bypass PostCSS entirely — no node creation, no GC pressure
5
+ * Cold builds run full PostCSS pipeline (including autoprefixer etc.)
6
+ * Warm builds return cached string directly — zero object allocation
7
+ */
8
+
9
+ 'use strict'
10
+
11
+ const path = require('path')
12
+ const fs = require('fs')
13
+ let postcss
14
+
15
+ // ─── State ────────────────────────────────────────────────────────────
16
+ let dirty = true
17
+ let cachedCSS = null // final output CSS string from last cold build
18
+
19
+ // ─── Config cache ─────────────────────────────────────────────────────
20
+ let cachedConfig = null
21
+ let cachedConfigPath = null
22
+ let cachedConfigMtime = 0
23
+
24
+ function loadConfig(cwd) {
25
+ const configPath = path.resolve(cwd, 'strata.config.js')
26
+ const configPathCjs = path.resolve(cwd, 'strata.config.cjs')
27
+
28
+ if (fs.existsSync(configPathCjs)) {
29
+ try { return require(configPathCjs) } catch {}
30
+ }
31
+
32
+ if (fs.existsSync(configPath)) {
33
+ try { return require(configPath) } catch {}
34
+ }
35
+
36
+ return {}
37
+ }
38
+
39
+ // ─── Base CSS ─────────────────────────────────────────────────────────
40
+ const BASE_CSS = require('./layers/base').trim()
41
+ let BASE_AST = null
42
+
43
+ function getBaseAST() {
44
+ if (!postcss) postcss = require('postcss')
45
+ if (!BASE_AST) BASE_AST = postcss.parse(BASE_CSS)
46
+ return BASE_AST
47
+ }
48
+
49
+ // ─── Input CSS cache ───────────────────────────────────────────────────
50
+ // strata.css rarely changes — cache it with mtime check
51
+ let cachedInputCSS = null
52
+ let cachedInputPath = null
53
+ let cachedInputMtime = 0
54
+
55
+ function readInputCSS(inputCSSPath) {
56
+ let mtime = 0
57
+ try { mtime = fs.statSync(inputCSSPath).mtimeMs } catch {}
58
+ if (cachedInputCSS && cachedInputPath === inputCSSPath && cachedInputMtime === mtime) {
59
+ return cachedInputCSS
60
+ }
61
+ cachedInputCSS = fs.readFileSync(inputCSSPath, 'utf8')
62
+ cachedInputPath = inputCSSPath
63
+ cachedInputMtime = mtime
64
+ return cachedInputCSS
65
+ }
66
+
67
+ // ─── PostCSS Plugin ───────────────────────────────────────────────────
68
+ // Only runs on cold builds — warm builds bypass via strata.build()
69
+
70
+ const plugin = (opts = {}) => ({
71
+ postcssPlugin: 'strata-css',
72
+
73
+ async Once(root) {
74
+ if (!postcss) postcss = require('postcss')
75
+
76
+ const cwd = opts.cwd || process.cwd()
77
+ const config = loadConfig(cwd)
78
+
79
+ const { scanFiles } = require('./scanner/scanner')
80
+ const { generate } = require('./generator/generator')
81
+
82
+ const contentGlobs = config.content || [
83
+ './src/**/*.{html,jsx,tsx,vue,astro,svelte,js,ts}'
84
+ ]
85
+
86
+ const classNames = scanFiles(contentGlobs)
87
+ const { componentCSS, utilityCSS } = generate(classNames, config)
88
+
89
+ // Replace @strata directives
90
+ let baseInserted = false
91
+ root.walkAtRules('strata', rule => {
92
+ const d = rule.params.trim()
93
+ if (d === 'base' && !baseInserted) {
94
+ rule.replaceWith(getBaseAST().clone())
95
+ baseInserted = true
96
+ } else if (d === 'components') {
97
+ // componentCSS now contains multiple @layer sub-layer blocks
98
+ componentCSS ? rule.replaceWith(postcss.parse(componentCSS)) : rule.remove()
99
+ } else if (d === 'utilities') {
100
+ // utilityCSS now contains multiple @layer sub-layer blocks
101
+ utilityCSS ? rule.replaceWith(postcss.parse(utilityCSS)) : rule.remove()
102
+ } else {
103
+ rule.remove()
104
+ }
105
+ })
106
+ }
107
+ })
108
+
109
+ plugin.postcss = true
110
+ module.exports = plugin
111
+
112
+ // ─── Build API — used by CLI ──────────────────────────────────────────
113
+ // Warm builds bypass PostCSS entirely — zero allocation, zero GC pressure
114
+
115
+ module.exports.build = async (inputCSSPath, outputCSSPath, opts = {}) => {
116
+ // ── Warm path: return cached CSS, no work at all ──────────────────
117
+ if (!dirty && cachedCSS) {
118
+ if (outputCSSPath) fs.writeFileSync(outputCSSPath, cachedCSS)
119
+ return cachedCSS
120
+ }
121
+
122
+ // ── Cold path: string assembly — no PostCSS parse/stringify ───────
123
+ // PostCSS parse → AST clone → replaceWith → stringify is a costly
124
+ // round-trip that adds no transformation. We replace @strata directives
125
+ // via regex on the raw string, which is O(n) on the input file only.
126
+ const cwd = opts.cwd || process.cwd()
127
+ const config = loadConfig(cwd)
128
+
129
+ const { scanFiles } = require('./scanner/scanner')
130
+ const { generate } = require('./generator/generator')
131
+
132
+ const contentGlobs = config.content || [
133
+ './src/**/*.{html,jsx,tsx,vue,astro,svelte,js,ts}'
134
+ ]
135
+
136
+ const classNames = scanFiles(contentGlobs)
137
+ const { componentCSS, utilityCSS } = generate(classNames, config)
138
+
139
+ // Read input CSS (cached by mtime — strata.css rarely changes)
140
+ const inputCSS = readInputCSS(inputCSSPath)
141
+
142
+ // Replace @strata directives with pre-built CSS strings.
143
+ // Use function replacements (not string literals) so any `$` sequences
144
+ // in the CSS (e.g. inside comments) are never treated as regex back-references.
145
+ const css = inputCSS
146
+ .replace(/^\s*@strata\s+base\s*;/m, () => BASE_CSS)
147
+ .replace(/^\s*@strata\s+components\s*;/m, () => componentCSS || '')
148
+ .replace(/^\s*@strata\s+utilities\s*;/m, () => utilityCSS || '')
149
+
150
+ cachedCSS = css
151
+ dirty = false
152
+
153
+ if (outputCSSPath) {
154
+ fs.mkdirSync(path.dirname(outputCSSPath), { recursive: true })
155
+ fs.writeFileSync(outputCSSPath, css)
156
+ }
157
+
158
+ return css
159
+ }
160
+
161
+ // ─── Cache invalidation ───────────────────────────────────────────────
162
+ module.exports.invalidate = (changedFile) => {
163
+ dirty = true
164
+ cachedCSS = null
165
+ const { clearFileCache } = require('./scanner/scanner')
166
+ clearFileCache(changedFile)
167
+ }
168
+
169
+ // ─── Direct PostCSS usage (for users using postcss.config.js) ────────
170
+ // Warm path still applies — cached CSS is injected as a raw parse
171
+ module.exports.postcss = true