Skip to content

Commit 1f6f5c2

Browse files
committed
rebuild
1 parent f862a39 commit 1f6f5c2

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

packages/css-color-parser/docs/css-color-parser.syntaxflag.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,22 @@ ColorMix
5959
Is a mixed color, e.g. `color-mix(in oklch, red, blue)`
6060

6161

62+
</td></tr>
63+
<tr><td>
64+
65+
ColorMixVariadic
66+
67+
68+
</td><td>
69+
70+
`"color-mix-variadic"`
71+
72+
73+
</td><td>
74+
75+
Is a variadic mixed color, e.g. `color-mix(in oklch, red)` `color-mix(in oklch, red, blue, green)`
76+
77+
6278
</td></tr>
6379
<tr><td>
6480

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* A test suite for PostCSS plugins.
3+
*
4+
* @example
5+
* ```sh
6+
* node --test
7+
* ```
8+
*
9+
* ```js
10+
* // test/_tape.mjs
11+
* import { postcssTape } from '@csstools/postcss-tape';
12+
* import plugin from '<your plugin package name>';
13+
*
14+
* postcssTape(plugin)({
15+
* basic: {
16+
* message: "supports basic usage",
17+
* },
18+
* 'basic:color': {
19+
* message: "supports { color: '<a color>' }",
20+
* options: {
21+
* color: 'purple'
22+
* }
23+
* },
24+
* });
25+
* ```
26+
*
27+
* @packageDocumentation
28+
*/
29+
30+
import type { Declaration } from 'postcss';
31+
import type { Plugin } from 'postcss';
32+
import type { PluginCreator } from 'postcss';
33+
34+
/**
35+
* A dummy PostCSS plugin that clones any at rule with params `to-clone` to a new at rule with params `cloned`.
36+
*/
37+
export declare const atRuleClonerPlugin: {
38+
postcssPlugin: string;
39+
prepare(): Plugin;
40+
};
41+
42+
/**
43+
* A dummy PostCSS plugin that clones any declaration with the property `to-clone` to a new declaration with the property `cloned`.
44+
*/
45+
export declare const declarationClonerPlugin: {
46+
postcssPlugin: string;
47+
Declaration(decl: Declaration): void;
48+
};
49+
50+
/**
51+
* General options for `@csstools/postcss-tape`.
52+
* These affect the entire test run, not individual test cases.
53+
*
54+
* @example
55+
* ```js
56+
* import { postcssTape } from '@csstools/postcss-tape';
57+
* import plugin from 'your-postcss-plugin';
58+
*
59+
* postcssTape(plugin, {
60+
* skipPackageNameCheck: true,
61+
* })(...);
62+
* ```
63+
*/
64+
export declare type Options = {
65+
/**
66+
* PostCSS plugins should start their name with `postcss-`.
67+
* If this is something you do not want to do, you can set this to `true` to skip this check.
68+
*/
69+
skipPackageNameCheck?: boolean;
70+
};
71+
72+
/**
73+
* Create a test suite for a PostCSS plugin.
74+
*/
75+
export declare function postcssTape(pluginCreator: PluginCreator<unknown>, runOptions?: Options): (options: Record<string, TestCaseOptions>) => Promise<void>;
76+
77+
/**
78+
* A dummy PostCSS plugin that clones any rule with the selector `to-clone` to a new rule with the selector `cloned`.
79+
*/
80+
export declare const ruleClonerPlugin: {
81+
postcssPlugin: string;
82+
prepare(): Plugin;
83+
};
84+
85+
/**
86+
* Options for a test case.
87+
*/
88+
export declare interface TestCaseOptions {
89+
/** Debug message */
90+
message?: string;
91+
/** Plugin options. Only used if `plugins` is not specified. */
92+
options?: unknown;
93+
/** Plugins to use. When specified the original plugin is not used. */
94+
plugins?: Array<Plugin>;
95+
/** The expected number of warnings. */
96+
warnings?: number;
97+
/** Expected exception */
98+
exception?: RegExp;
99+
/** Override the file name of the "source" file. */
100+
source?: string;
101+
/** Override the file name of the "expect" file. */
102+
expect?: string;
103+
/** Override the file name of the "result" file. */
104+
result?: string;
105+
/** Do something before the test is run. */
106+
before?: () => void | Promise<void>;
107+
/** Do something after the test is run. */
108+
after?: () => void | Promise<void>;
109+
}
110+
111+
export { }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/* node:coverage disable */
2+
import e from"node:assert/strict";import s from"node:fs/promises";import t from"node:fs";import o from"node:path";import n from"postcss";import r from"postcss-8.4";import i from"node:test";import a from"node:url";const noopPlugin=()=>({postcssPlugin:"noop-plugin",Once(){}});async function fileContentsOrEmptyString(e){try{return await s.readFile(e,"utf8")}catch{return""}}function reduceInformationInCssSyntaxError(e){process.env.DEBUG||(delete e.source,e.input&&delete e.input.source,delete e.postcssNode)}function postcssTape(a,c){return async p=>{c=c??{},await i("`postcss` flag is set on exported plugin creator",(()=>{e.equal(a.postcss,!0)})),await i("exported plugin creator is a function",(()=>{e.equal(typeof a,"function")})),await i("`postcssPlugin` is set on a plugin instance",(()=>{const s=a();e.ok(s.postcssPlugin),e.equal(typeof s.postcssPlugin,"string")})),await i("package.json",(async t=>{const o=await s.readFile("./package.json","utf-8"),n=JSON.parse(o);await t.test('includes "postcss-plugin" keyword',(()=>{e.ok(Array.isArray(n.keywords)&&n.keywords?.includes("postcss-plugin"),new PackageDescriptionError('Missing "postcss-plugin" keyword in package.json',"keywords"))})),await t.test('name starts with "postcss-"',{skip:c?.skipPackageNameCheck},(()=>{let s="string"==typeof n.name?n.name:"";if(s.startsWith("@")){const e=s.split("/");s=e.slice(1).join("/")}e.ok(s.startsWith("postcss-"),new PackageDescriptionError(`package name "${s}" does not start with "postcss-"`,"name"))})),await t.test("`postcss` is a peer dependency and not a direct dependency",{skip:"postcssTapeSelfTest"in a},(()=>{e.ok(Object.keys(Object(n.peerDependencies)).includes("postcss"),new PackageDescriptionError('"postcss" must be listed in "peerDependencies"',"peerDependencies")),e.ok(!Object.keys(Object(n.dependencies)).includes("postcss"),new PackageDescriptionError('"postcss" must not be listed in "dependencies"',"dependencies"))}))}));const l=a().postcssPlugin;await i(l,(async i=>{for(const c in p)await i.test(c,(async i=>{const l=p[c];l.before&&await l.before();const u=o.join(".","test",...c.split(":")[0].split(o.posix.sep)),d=o.join(".","test",...c.replace(/:/g,".").split(o.posix.sep)),m="css";let g=`${u}.${m}`,w=`${d}.expect.${m}`,f=`${d}.result.${m}`;l.source&&(g=o.join(".","test",l.source)),l.expect&&(w=o.join(".","test",l.expect)),l.result&&(f=o.join(".","test",l.result));const k=l.plugins??[a(l.options)],h=await fileContentsOrEmptyString(g),y=await fileContentsOrEmptyString(w);let E;try{E=await n(k).process(h,{from:g,to:f,map:{inline:!1,annotation:!1}})}catch(e){if(!(e instanceof Error))throw e;if(reduceInformationInCssSyntaxError(e),l.exception&&l.exception.test(e.message))return;throw e}e.ok(!l.exception,new OutcomeError(`expected an exception matching "${l.exception}"`,g));const x=E.css.toString();{const e=[s.writeFile(f,x,"utf8")];process.env.REWRITE_EXPECTS&&e.push(s.writeFile(w,x,"utf8")),await Promise.all(e)}y||e.ok(t.existsSync(w),new OutcomeError(`Missing expect file: "${w}"`,g)),await i.test("has expected output",(()=>{e.deepEqual(x,y),e.deepEqual(E.warnings().length,l.warnings??0,`Unexpected number warnings:\n${E.warnings().toString()}`)})),await i.test("sourcemaps",(()=>{e.ok(!E.map.toJSON().sources.includes("<no source>"),'Sourcemap is broken. This is most likely a newly created PostCSS AST Node without a value for "source". See: https://github.com/postcss/postcss/blob/main/docs/guidelines/plugin.md#24-set-nodesource-for-new-nodes')})),l.after&&await l.after(),await i.test("output is parsable with PostCSS",(async()=>{const s=await fileContentsOrEmptyString(f),t=await n([noopPlugin()]).process(s,{from:f,to:f,map:{inline:!1,annotation:!1}});e.deepEqual(t.warnings(),[],"Unexpected warnings on second pass")})),await i.test("The oldest and current PostCSS version produce the same result",{skip:n([noopPlugin()]).version===r([noopPlugin()]).version},(async()=>{const s=await r(k).process(h,{from:g,to:f,map:{inline:!1,annotation:!1}});e.deepEqual(s.css.toString(),x)}))}))}))}}noopPlugin.postcss=!0;const c={postcssPlugin:"declaration-cloner",Declaration(e){"to-clone"===e.prop&&e.cloneBefore({prop:"cloned"})}},p={postcssPlugin:"rule-cloner",prepare(){const e=new WeakSet;return{postcssPlugin:"rule-cloner",RuleExit(s){e.has(s)||"to-clone"===s.selector&&(e.add(s),s.cloneBefore({selector:"cloned"}))}}}},l={postcssPlugin:"at-rule-cloner",prepare(){const e=new WeakSet;return{postcssPlugin:"at-rule-cloner",AtRuleExit(s){if(!e.has(s))return"to-clone"===s.params?(e.add(s),void s.cloneBefore({params:"cloned"})):"to-clone"===s.name?(e.add(s),void s.cloneBefore({name:"cloned"})):void 0}}}};class PackageDescriptionError extends Error{constructor(e,s){super(e),this.name="PackageDescriptionError",this.stack=`${this.name}: ${this.message}\n at "${s}" (${a.pathToFileURL(o.resolve("package.json")).href}:1:1)`}}class OutcomeError extends Error{constructor(e,s){super(e),this.name="OutcomeError",this.stack=`${this.name}: ${this.message}\n at ${a.pathToFileURL(o.resolve(s)).href}:1:1`}}export{l as atRuleClonerPlugin,c as declarationClonerPlugin,postcssTape,p as ruleClonerPlugin};
3+
/* node:coverage enable */

0 commit comments

Comments
 (0)