forgecss 0.1.7 → 0.2.1
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.
- package/cli.js +15 -7
- package/index.d.ts +9 -9
- package/index.js +80 -37
- package/lib/generator.js +24 -54
- package/lib/inventory.d.ts +3 -0
- package/lib/inventory.js +6 -3
- package/lib/processor.d.ts +3 -0
- package/lib/processor.js +14 -10
- package/lib/transformers/mediaQuery.js +44 -0
- package/lib/transformers/pseudo.js +57 -0
- package/package.json +3 -2
- package/tsconfig.json +3 -0
package/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ program.option("-v, --verbose", "Enable watch mode", false);
|
|
|
13
13
|
program.parse();
|
|
14
14
|
|
|
15
15
|
const options = program.opts();
|
|
16
|
-
let config = null;
|
|
16
|
+
let config = null, instance = null;
|
|
17
17
|
|
|
18
18
|
if (!fs.existsSync(options.config)) {
|
|
19
19
|
throw new Error(`forgecss: Config file not found at ${options.config}. Check the --config option.`);
|
|
@@ -30,11 +30,15 @@ async function runForgeCSS(lookAtPath = null) {
|
|
|
30
30
|
if (!config) {
|
|
31
31
|
// The very first run
|
|
32
32
|
config = await loadConfig(options.config);
|
|
33
|
+
if (!config.dir) {
|
|
34
|
+
throw new Error('forgecss: missing "dir" in configuration.');
|
|
35
|
+
}
|
|
36
|
+
if (!config.output) {
|
|
37
|
+
throw new Error('forgecss: missing "output" in configuration.');
|
|
38
|
+
}
|
|
39
|
+
instance = ForgeCSS(config);
|
|
33
40
|
if (options.watch) {
|
|
34
|
-
|
|
35
|
-
throw new Error('forgecss: missing "source" in configuration.');
|
|
36
|
-
}
|
|
37
|
-
const watcher = chokidar.watch(config.source, {
|
|
41
|
+
const watcher = chokidar.watch(config.dir, {
|
|
38
42
|
persistent: true,
|
|
39
43
|
ignoreInitial: true,
|
|
40
44
|
ignored: (p, stats) => path.resolve(p) === path.resolve(config.output)
|
|
@@ -50,9 +54,13 @@ async function runForgeCSS(lookAtPath = null) {
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
|
-
|
|
57
|
+
if (lookAtPath) {
|
|
58
|
+
instance.parseFile({ file: lookAtPath, output: config.output });
|
|
59
|
+
} else {
|
|
60
|
+
instance.parseDirectory({ dir: config.dir, output: config.output });
|
|
61
|
+
}
|
|
54
62
|
if (options.verbose) {
|
|
55
|
-
console.log(`forgecss:
|
|
63
|
+
console.log(`forgecss: ${config.output} generated successfully.`);
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
|
package/index.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
export type ForgeCSSOptions = {
|
|
2
|
-
source: string;
|
|
3
2
|
inventoryFiles?: string[];
|
|
4
3
|
usageFiles?: string[];
|
|
5
4
|
usageAttributes?: string[];
|
|
6
|
-
mapping
|
|
7
|
-
queries
|
|
8
|
-
[key: string]:
|
|
9
|
-
query: string;
|
|
10
|
-
};
|
|
5
|
+
mapping?: {
|
|
6
|
+
queries?: {
|
|
7
|
+
[key: string]: string
|
|
11
8
|
};
|
|
12
9
|
};
|
|
13
|
-
output: string;
|
|
14
10
|
};
|
|
15
11
|
|
|
16
12
|
export type ForgeInstance = {
|
|
17
|
-
|
|
13
|
+
parseDirectory: (options: { dir: string; output?: string }) => Promise<string>;
|
|
14
|
+
parseFile: (options: { file: string; output?: string }) => Promise<string>;
|
|
15
|
+
parse: (options: { css: string; html?: string; jsx?: string; output?: string }) => Promise<string>;
|
|
18
16
|
};
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
declare function ForgeCSS(options?: ForgeCSSOptions): ForgeInstance;
|
|
19
|
+
|
|
20
|
+
export default ForgeCSS;
|
package/index.js
CHANGED
|
@@ -1,72 +1,115 @@
|
|
|
1
|
+
import { writeFile } from "fs/promises";
|
|
1
2
|
import getAllFiles from "./lib/getAllFiles.js";
|
|
2
|
-
import { extractStyles } from "./lib/inventory.js";
|
|
3
|
+
import { extractStyles, invalidateInvetory } from "./lib/inventory.js";
|
|
3
4
|
import { invalidateUsageCache, findUsages } from "./lib/processor.js";
|
|
4
5
|
import { generateOutputCSS } from "./lib/generator.js";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_OPTIONS = {
|
|
7
|
-
source: null,
|
|
8
8
|
inventoryFiles: ["css", "less", "scss"],
|
|
9
9
|
usageFiles: ["html", "jsx", "tsx"],
|
|
10
10
|
usageAttributes: ["class", "className"],
|
|
11
11
|
mapping: {
|
|
12
12
|
queries: {}
|
|
13
|
-
}
|
|
14
|
-
output: null
|
|
13
|
+
}
|
|
15
14
|
};
|
|
16
15
|
|
|
17
|
-
export default function ForgeCSS(options
|
|
16
|
+
export default function ForgeCSS(options) {
|
|
18
17
|
const config = { ...DEFAULT_OPTIONS };
|
|
19
18
|
|
|
20
|
-
config.
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
config.mapping = {
|
|
20
|
+
queries: Object.assign({}, DEFAULT_OPTIONS.mapping.queries, options?.mapping?.queries ?? {})
|
|
21
|
+
};
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
async function result(output) {
|
|
24
|
+
try {
|
|
25
|
+
const css = await generateOutputCSS(config);
|
|
26
|
+
if (output) {
|
|
27
|
+
await writeFile(output, `/* ForgeCSS autogenerated file */\n${css}`, "utf-8");
|
|
28
|
+
}
|
|
29
|
+
return css;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error(`forgecss: error generating output CSS: ${err}`);
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
return {
|
|
32
|
-
async
|
|
37
|
+
async parseDirectory({ dir, output = null }) {
|
|
38
|
+
if (!dir) {
|
|
39
|
+
throw new Error('forgecss: parseDirectory requires "dir" as an argument.');
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
// filling the inventory
|
|
43
|
+
let files = await getAllFiles(dir, config.inventoryFiles);
|
|
44
|
+
for (let file of files) {
|
|
45
|
+
await extractStyles(file);
|
|
46
|
+
}
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error(`forgecss: error extracting styles.`, err);
|
|
49
|
+
}
|
|
50
|
+
// finding the usages
|
|
51
|
+
try {
|
|
52
|
+
let files = await getAllFiles(dir, config.usageFiles);
|
|
53
|
+
for (let file of files) {
|
|
54
|
+
await findUsages(file);
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(`forgecss: error extracting usages`, err);
|
|
58
|
+
}
|
|
59
|
+
// generating the output CSS
|
|
60
|
+
return result(output);
|
|
61
|
+
},
|
|
62
|
+
async parseFile({ file, output = null }) {
|
|
63
|
+
if (!file) {
|
|
64
|
+
throw new Error('forgecss: parseFile requires "file" as an argument.');
|
|
65
|
+
}
|
|
66
|
+
const ext = file.split(".").pop().toLowerCase();
|
|
33
67
|
// filling the inventory
|
|
34
68
|
try {
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
await extractStyles(lookAtPath);
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
let files = await getAllFiles(config.source, config.inventoryFiles);
|
|
41
|
-
for (let file of files) {
|
|
42
|
-
await extractStyles(file);
|
|
43
|
-
}
|
|
69
|
+
if (config.inventoryFiles.includes(ext)) {
|
|
70
|
+
await extractStyles(file);
|
|
44
71
|
}
|
|
45
72
|
} catch (err) {
|
|
46
|
-
console.error(`forgecss: error extracting styles
|
|
73
|
+
console.error(`forgecss: error extracting styles.`, err);
|
|
47
74
|
}
|
|
48
75
|
// finding the usages
|
|
49
76
|
try {
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await findUsages(lookAtPath);
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
let files = await getAllFiles(config.source, config.usageFiles);
|
|
57
|
-
for (let file of files) {
|
|
58
|
-
await findUsages(file);
|
|
59
|
-
}
|
|
77
|
+
if (config.usageFiles.includes(ext)) {
|
|
78
|
+
invalidateUsageCache(file);
|
|
79
|
+
await findUsages(file);
|
|
60
80
|
}
|
|
61
81
|
} catch (err) {
|
|
62
|
-
console.error(`forgecss: error extracting
|
|
82
|
+
console.error(`forgecss: error extracting usages.`, err);
|
|
63
83
|
}
|
|
64
84
|
// generating the output CSS
|
|
85
|
+
return result(output);
|
|
86
|
+
},
|
|
87
|
+
async parse({ css, html, jsx, output = null }) {
|
|
88
|
+
if (!css) {
|
|
89
|
+
throw new Error('forgecss: parse requires "css".');
|
|
90
|
+
}
|
|
91
|
+
if (!html && !jsx) {
|
|
92
|
+
throw new Error('forgecss: parse requires "html" or "jsx".');
|
|
93
|
+
}
|
|
94
|
+
invalidateInvetory();
|
|
95
|
+
invalidateUsageCache();
|
|
96
|
+
// filling the inventory
|
|
97
|
+
try {
|
|
98
|
+
await extractStyles("styles.css", css);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(`forgecss: error extracting styles.`, err);
|
|
101
|
+
}
|
|
102
|
+
// finding the usages
|
|
65
103
|
try {
|
|
66
|
-
|
|
104
|
+
if (html) {
|
|
105
|
+
await findUsages("usage.html", html);
|
|
106
|
+
} else if (jsx) {
|
|
107
|
+
await findUsages("usage.jsx", jsx);
|
|
108
|
+
}
|
|
67
109
|
} catch (err) {
|
|
68
|
-
console.error(`forgecss: error
|
|
110
|
+
console.error(`forgecss: error extracting usages.`, err);
|
|
69
111
|
}
|
|
112
|
+
return result(output);
|
|
70
113
|
}
|
|
71
114
|
};
|
|
72
115
|
}
|
package/lib/generator.js
CHANGED
|
@@ -1,67 +1,37 @@
|
|
|
1
|
-
import postcss from "postcss";
|
|
2
|
-
import { writeFile } from "fs/promises";
|
|
3
|
-
|
|
4
1
|
import { getUsages } from "./processor.js";
|
|
5
|
-
import
|
|
2
|
+
import mediaQueryTransformer from "./transformers/mediaQuery.js";
|
|
3
|
+
import pseudoClassTransformer from "./transformers/pseudo.js";
|
|
6
4
|
|
|
7
5
|
export async function generateOutputCSS(config) {
|
|
8
|
-
const
|
|
6
|
+
const bucket = {};
|
|
9
7
|
const usages = getUsages();
|
|
10
8
|
Object.keys(usages).map((file) => {
|
|
11
9
|
Object.keys(usages[file]).forEach(async (label) => {
|
|
12
10
|
try {
|
|
13
|
-
|
|
11
|
+
if (mediaQueryTransformer(config, label, usages[file][label], bucket)) {
|
|
12
|
+
return;
|
|
13
|
+
} else if (pseudoClassTransformer(label, usages[file][label], bucket)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
14
16
|
} catch (err) {
|
|
15
|
-
console.error(
|
|
17
|
+
console.error(
|
|
18
|
+
`forgecss: Error generating media query for label "${label}" (found in file ${file.replace(
|
|
19
|
+
process.cwd(),
|
|
20
|
+
""
|
|
21
|
+
)})`,
|
|
22
|
+
err
|
|
23
|
+
);
|
|
16
24
|
}
|
|
17
25
|
});
|
|
18
26
|
});
|
|
19
|
-
|
|
20
|
-
.map((
|
|
27
|
+
return Object.keys(bucket)
|
|
28
|
+
.map((key) => {
|
|
29
|
+
if (bucket[key].rules) {
|
|
30
|
+
return bucket[key].rules.toString();
|
|
31
|
+
}
|
|
32
|
+
return bucket[key].toString();
|
|
33
|
+
})
|
|
34
|
+
.filter(Boolean)
|
|
21
35
|
.join("\n");
|
|
22
|
-
await writeFile(
|
|
23
|
-
config.output,
|
|
24
|
-
`/* ForgeCSS autogenerated file */\n${result}`,
|
|
25
|
-
"utf-8"
|
|
26
|
-
);
|
|
27
36
|
}
|
|
28
|
-
|
|
29
|
-
if (!config.mapping.queries[label]) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
`Unknown media query label: ${label}. Check app-fe/wwwroot/scripts/lib/generateMediaQueries.js for available mappings.`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
if (!cache[label]) {
|
|
35
|
-
cache[label] = {
|
|
36
|
-
mq: postcss.atRule({
|
|
37
|
-
name: "media",
|
|
38
|
-
params: `all and (${config.mapping.queries[label].query})`
|
|
39
|
-
}),
|
|
40
|
-
classes: {}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
const mq = cache[label].mq;
|
|
44
|
-
selectors.forEach((selector) => {
|
|
45
|
-
const prefixedSelector = `.${label}_${selector}`;
|
|
46
|
-
if (cache[label].classes[prefixedSelector]) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
cache[label].classes[prefixedSelector] = true;
|
|
50
|
-
const rule = postcss.rule({ selector: prefixedSelector });
|
|
51
|
-
const decls = getStylesByClassName(selector);
|
|
52
|
-
if (decls.length === 0) {
|
|
53
|
-
console.warn(`Warning: No styles found for class .${selector} used in media query ${label}`);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
decls.forEach((d) => {
|
|
57
|
-
rule.append(
|
|
58
|
-
postcss.decl({
|
|
59
|
-
prop: d.prop,
|
|
60
|
-
value: d.value,
|
|
61
|
-
important: d.important
|
|
62
|
-
})
|
|
63
|
-
);
|
|
64
|
-
});
|
|
65
|
-
mq.append(rule);
|
|
66
|
-
});
|
|
67
|
-
}
|
|
37
|
+
|
package/lib/inventory.js
CHANGED
|
@@ -2,10 +2,10 @@ import { readFile } from "fs/promises";
|
|
|
2
2
|
import postcss from "postcss";
|
|
3
3
|
import safeParser from "postcss-safe-parser";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
let INVENTORY = {};
|
|
6
6
|
|
|
7
|
-
export async function extractStyles(filePath) {
|
|
8
|
-
const content = await readFile(filePath, 'utf-8');
|
|
7
|
+
export async function extractStyles(filePath, css = null) {
|
|
8
|
+
const content = css !== null ? css : await readFile(filePath, 'utf-8');
|
|
9
9
|
INVENTORY[filePath] = postcss.parse(content, { parser: safeParser });
|
|
10
10
|
}
|
|
11
11
|
export function getStylesByClassName(selector) {
|
|
@@ -20,4 +20,7 @@ export function getStylesByClassName(selector) {
|
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
22
|
return decls;
|
|
23
|
+
}
|
|
24
|
+
export function invalidateInvetory() {
|
|
25
|
+
INVENTORY = {};
|
|
23
26
|
}
|
package/lib/processor.js
CHANGED
|
@@ -4,18 +4,18 @@ import { fromHtml } from "hast-util-from-html";
|
|
|
4
4
|
import { visit } from "unist-util-visit";
|
|
5
5
|
|
|
6
6
|
const FUNC_NAME = 'fx';
|
|
7
|
-
|
|
7
|
+
let USAGES = {};
|
|
8
8
|
|
|
9
9
|
const { parse } = swc;
|
|
10
10
|
|
|
11
|
-
export async function findUsages(filePath) {
|
|
11
|
+
export async function findUsages(filePath, fileContent = null) {
|
|
12
12
|
try {
|
|
13
13
|
if (USAGES[filePath]) {
|
|
14
14
|
// already processed
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
USAGES[filePath] = {};
|
|
18
|
-
const content = await readFile(filePath, "utf-8");
|
|
18
|
+
const content = fileContent ? fileContent : await readFile(filePath, "utf-8");
|
|
19
19
|
const extension = filePath.split('.').pop().toLowerCase();
|
|
20
20
|
|
|
21
21
|
// HTML
|
|
@@ -23,7 +23,7 @@ export async function findUsages(filePath) {
|
|
|
23
23
|
const ast = fromHtml(content);
|
|
24
24
|
visit(ast, "element", (node) => {
|
|
25
25
|
if (node.properties.className) {
|
|
26
|
-
|
|
26
|
+
storeUsage(filePath, node.properties.className.join(' '));
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
return;
|
|
@@ -47,21 +47,28 @@ export async function findUsages(filePath) {
|
|
|
47
47
|
value += elem?.cooked || "";
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
storeUsage(filePath, value);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
} catch (err) {
|
|
56
|
-
console.error(`forgecss: error processing file ${filePath}
|
|
56
|
+
console.error(`forgecss: error processing file ${filePath.replace(process.cwd(), '')}`, err);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
export function invalidateUsageCache(filePath) {
|
|
60
|
+
if (!filePath) {
|
|
61
|
+
USAGES = {};
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
60
64
|
if (USAGES[filePath]) {
|
|
61
65
|
delete USAGES[filePath];
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
|
-
function
|
|
68
|
+
export function getUsages() {
|
|
69
|
+
return USAGES;
|
|
70
|
+
}
|
|
71
|
+
function storeUsage(filePath, classesString = "") {
|
|
65
72
|
if (classesString) {
|
|
66
73
|
classesString.split(" ").forEach((part) => {
|
|
67
74
|
if (part.indexOf(":") > -1) {
|
|
@@ -112,7 +119,4 @@ function traverseASTNode(node, visitors, stack = []) {
|
|
|
112
119
|
traverseASTNode(child, visitors, [node].concat(stack));
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
|
-
}
|
|
116
|
-
export function getUsages() {
|
|
117
|
-
return USAGES;
|
|
118
122
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import postcss from "postcss";
|
|
2
|
+
|
|
3
|
+
import { getStylesByClassName } from "../inventory.js";
|
|
4
|
+
|
|
5
|
+
export default function mediaQueryTransformer(config, label, selectors, bucket) {
|
|
6
|
+
if (!config?.mapping?.queries[label]) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (!bucket[label]) {
|
|
10
|
+
bucket[label] = {
|
|
11
|
+
rules: postcss.atRule({
|
|
12
|
+
name: "media",
|
|
13
|
+
params: `all and (${config.mapping.queries[label]})`
|
|
14
|
+
}),
|
|
15
|
+
classes: {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const rules = bucket[label].rules;
|
|
19
|
+
selectors.forEach((selector) => {
|
|
20
|
+
const prefixedSelector = `.${label}_${selector}`;
|
|
21
|
+
if (bucket[label].classes[prefixedSelector]) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
bucket[label].classes[prefixedSelector] = true; // caching
|
|
25
|
+
const rule = postcss.rule({ selector: prefixedSelector });
|
|
26
|
+
const decls = getStylesByClassName(selector);
|
|
27
|
+
if (decls.length === 0) {
|
|
28
|
+
console.warn(`forgecss: no styles found for class ".${selector}" used in media query "${label}"`);
|
|
29
|
+
delete bucket[label];
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
decls.forEach((d) => {
|
|
33
|
+
rule.append(
|
|
34
|
+
postcss.decl({
|
|
35
|
+
prop: d.prop,
|
|
36
|
+
value: d.value,
|
|
37
|
+
important: d.important
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
rules.append(rule);
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import postcss from "postcss";
|
|
2
|
+
import { getStylesByClassName } from "../inventory.js";
|
|
3
|
+
|
|
4
|
+
const ALLOWED_PSEUDO_CLASSES = [
|
|
5
|
+
"hover",
|
|
6
|
+
"active",
|
|
7
|
+
"focus",
|
|
8
|
+
"focus-visible",
|
|
9
|
+
"focus-within",
|
|
10
|
+
"disabled",
|
|
11
|
+
"enabled",
|
|
12
|
+
"read-only",
|
|
13
|
+
"read-write",
|
|
14
|
+
"checked",
|
|
15
|
+
"indeterminate",
|
|
16
|
+
"valid",
|
|
17
|
+
"invalid",
|
|
18
|
+
"required",
|
|
19
|
+
"optional",
|
|
20
|
+
"in-range",
|
|
21
|
+
"out-of-range",
|
|
22
|
+
"placeholder-shown",
|
|
23
|
+
"autofill",
|
|
24
|
+
"user-invalid"
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export default function pseudoClassTransformer(label, selectors, bucket) {
|
|
28
|
+
if (!ALLOWED_PSEUDO_CLASSES.includes(label)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const root = postcss.root();
|
|
32
|
+
selectors.forEach((selector) => {
|
|
33
|
+
const key = `${label}_${selector}`;
|
|
34
|
+
if (bucket[key]) {
|
|
35
|
+
// already have that
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const rule = postcss.rule({ selector: `.${key}:${label}` });
|
|
39
|
+
const decls = getStylesByClassName(selector);
|
|
40
|
+
if (decls.length === 0) {
|
|
41
|
+
console.warn(`forgecss: no styles found for class ".${selector}" used in pseudo class "${label}"`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
decls.forEach((d) => {
|
|
45
|
+
rule.append(
|
|
46
|
+
postcss.decl({
|
|
47
|
+
prop: d.prop,
|
|
48
|
+
value: d.value,
|
|
49
|
+
important: d.important
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
root.append(rule);
|
|
54
|
+
bucket[key] = root;
|
|
55
|
+
});
|
|
56
|
+
return true;
|
|
57
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgecss",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "ForgeCSS turns strings into fully generated responsive CSS using a custom DSL.",
|
|
6
6
|
"author": "Krasimir Tsonev",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "node ./scripts/build.js"
|
|
9
|
+
"build": "node ./scripts/build.js",
|
|
10
|
+
"test": "node ./tests/run.js"
|
|
10
11
|
},
|
|
11
12
|
"repository": {
|
|
12
13
|
"type": "git",
|
package/tsconfig.json
ADDED