diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..0a353ed --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +**/*.md \ No newline at end of file diff --git a/package.json b/package.json index 58b5f52..030700c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-contains", - "version": "0.0.1", + "version": "0.1.0", "description": "A PostCSS plugin to styles selectors based on specific declaration or property.", "keywords": [ "postcss", @@ -27,7 +27,7 @@ "test": "vitest run", "ci": "npm run build && npm run check-format && npm run test" }, - "dependencies": { + "peerDependencies": { "postcss": "^8.4.47" }, "devDependencies": { diff --git a/readme.md b/readme.md index ef0b500..ba5cf08 100644 --- a/readme.md +++ b/readme.md @@ -7,21 +7,23 @@ The `@contains` at-rule targets elements and selectors when they _contain_: - A specific property (e.g. `position` or `margin`) - A specific declaration (property-value pair, e.g. `display: grid`) + ## Installation ```sh npm install postcss-contains --save-dev ``` + ## Usage ```js // postcss.config.js -import postcssContains from "postcss-contains"; +import postcssContains from "postcss-contains" export default { plugins: [postcssContains], -}; +} ``` ```css @@ -86,6 +88,7 @@ div { } ``` + ### Duplications When two `@contains` rules target the same property or declaration, their styles will merge by default. @@ -134,6 +137,7 @@ div { See [options](#options) for more. + ### Specificity "Property-value" matches considered with a specificity so they take precedence over "property-only" matches. @@ -169,6 +173,7 @@ span { } ``` + ## Options #### `duplication` @@ -236,16 +241,13 @@ div { ```css /* a */ -@contains (color) { -} +@contains (color) {} /* b */ -@contains (color: red) { -} +@contains (color: red) {} /* c */ -@contains (color: red) { -} +@contains (color: red) {} ``` More examples are provided [here](./test/exmaples.md). diff --git a/src/contains.ts b/src/contains.ts index 12fec7a..bdbc79c 100644 --- a/src/contains.ts +++ b/src/contains.ts @@ -179,87 +179,85 @@ export default class Contains { } // 1) collecting all @contains: conditions and their declarations - collect(root: Root, result: Result) { - root.walkAtRules("contains", (atRule: AtRule) => { - const params = getParams(atRule.params); - const overrides = atRule.params.startsWith("overrides"); - - if (/\n/.test(atRule.params)) { - atRule.warn( - result, - "It's better to not use new lines inside @contains params.", - ); - } + collect(atRule: AtRule, result: Result) { + const params = getParams(atRule.params); + const overrides = atRule.params.startsWith("overrides"); + + if (/\n/.test(atRule.params)) { + atRule.warn( + result, + "It's better to not use new lines inside @contains params.", + ); + } - if (!atRule.nodes) { - throw new Error( - `@contains has no styles (provided no curly brackets).\n ${atRule.toString()}`, - ); - } + if (!atRule.nodes) { + throw atRule.error( + `@contains has no styles (provided no curly brackets).\n ${atRule.toString()}`, + ); + } - if (atRule.nodes.length === 0) { - atRule.warn(result, `The @contains was empty; it provides no styles.`); - } + if (atRule.nodes.length === 0) { + atRule.warn(result, `The @contains was empty; it provides no styles.`); + } - const isInvalidType = atRule.nodes.some( - (child) => child.type === "rule" || child.type === "atrule", + const isInvalidType = atRule.nodes.some( + (child) => child.type === "rule" || child.type === "atrule", + ); + + if (isInvalidType) { + throw atRule.error( + `rules and at-rules can not be nested inside @contains.\n ${atRule.toString()}`, ); + } - if (isInvalidType) { - throw new Error( - `rules and at-rules can not be nested inside @contains.\n ${atRule.toString()}`, + if (params.includes(":")) { + const { property, value } = extract(params, "pair"); + + if (!property || !value) { + throw atRule.error( + `Something went wrong on \t ${atRule.toString()} \n\t >>> property: ${property} - value: ${value}`, ); } - if (params.includes(":")) { - const { property, value } = extract(params, "pair"); - - if (!property || !value) { - throw new Error( - `Something went wrong on \t ${atRule.toString()} \n\t >>> property: ${property} - value: ${value}`, - ); - } - - const variant: "pair" | "single" = "pair"; - const declarations = new Map(); + const variant: "pair" | "single" = "pair"; + const declarations = new Map(); - for (const node of atRule.nodes) { - if (node.type === "decl") { - const { prop, value, important } = node; - // const declaration = new Declaration({ prop, value, important }); - declarations.set(prop, value); - } + for (const node of atRule.nodes) { + if (node.type === "decl") { + const { prop, value, important } = node; + // const declaration = new Declaration({ prop, value, important }); + declarations.set(prop, value); } + } - const bucket = { value, variant, overrides, declarations }; - this.add(property, bucket); - atRule.remove(); - return; - } else { - const { property } = extract(params, "single"); + const bucket = { value, variant, overrides, declarations }; + this.add(property, bucket); + atRule.remove(); + return; + } else { + const { property } = extract(params, "single"); - if (!property) { - throw new Error( - `Something went wrong on \t ${atRule.toString()} \n\t >>> property: ${property}`, - ); - } + if (!property) { + throw atRule.error( + `Something went wrong on \t ${atRule.toString()} \n\t >>> property: ${property}`, + ); + } - const variant: "pair" | "single" = "single"; - const declarations = new Map(); + const variant: "pair" | "single" = "single"; + const declarations = new Map(); - for (const node of atRule.nodes) { - if (node.type === "decl") { - const { prop, value, important } = node; - declarations.set(prop, value); - } + for (const node of atRule.nodes) { + if (node.type === "decl") { + const { prop, value, important } = node; + declarations.set(prop, value); } - - const bucket = { value: null, variant, overrides, declarations }; - this.add(property, bucket); - atRule.remove(); - return; } - }); + + const bucket = { value: null, variant, overrides, declarations }; + this.add(property, bucket); + atRule.remove(); + return; + } } add(property: string, bucket: Bucket) { diff --git a/src/index.ts b/src/index.ts index e2263d6..1d25fea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,8 +14,10 @@ const plugin: PluginCreator = (opts?: PluginOptions) => { return { postcssPlugin: "postcss-contains", - Once(root, { result }) { - contains.collect(root, result); + AtRule: { + contains(atRule, { result }) { + contains.collect(atRule, result); + }, }, Rule(rule) { diff --git a/test/exmaples.md b/test/exmaples.md index 1d136e2..3893f8f 100644 --- a/test/exmaples.md +++ b/test/exmaples.md @@ -42,7 +42,7 @@ - No property or declaration passed to @contains ```css -@Contains() { +@Contains () { /* styles */ } ``` diff --git a/tsconfig.json b/tsconfig.json index aa2e23e..e96d34f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,5 @@ "outDir": "dist", "sourceMap": true }, - "exclude": ["dist", "test"] + "include": ["src"] }