Skip to content

Commit 49faed1

Browse files
copy mjs files and comments
We must keep the *.mjs files as *.mjs because jest needs them as is...
1 parent ee9ad33 commit 49faed1

18 files changed

+141
-143
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"scripts": {
4747
"lint": "eslint .",
4848
"lint:fix": "eslint . --fix",
49-
"build": "unbuild --config unbuild.config.ts",
49+
"build": "unbuild --config unbuild.config.ts && rsync src/utils/tailwindcss-api/worker/*.mjs lib/worker",
5050
"xdocs:init": "pnpm build && eslint-doc-generator --init-rule-docs",
5151
"docs:init": "eslint-doc-generator --init-rule-docs",
5252
"xdocs:update": "pnpm build && eslint-doc-generator",

src/_sandbox/notes.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
# Notes
2-
3-
Failing tests => use multiple build configs

src/rules/no-custom-classname.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ export const createRule = RuleCreator(urlCreator);
4545
const detectCustomClassnames = (
4646
context: RuleContext,
4747
settings: PluginSettings,
48-
literals: Array<AtomicNode>
48+
literals: Array<AtomicNode>,
4949
) => {
5050
for (const node of literals) {
5151
const { originalClassNamesValue } = dissectAtomicNode(
5252
node,
53-
context as unknown as GenericRuleContext
53+
context as unknown as GenericRuleContext,
5454
);
5555
// Process the extracted classnames and report
5656
const { classNames } = getClassnamesFromValue(originalClassNamesValue);
@@ -78,7 +78,7 @@ export const noCustomClassname = createRule<Options, MessageIds>({
7878
docs: {
7979
description: "Detects classnames which do not belong to Tailwind CSS.",
8080
},
81-
hasSuggestions: true,
81+
hasSuggestions: false,
8282
messages: {
8383
"issue:unknown-classname": `Classname '{{classname}}' is not a Tailwind CSS class!`,
8484
},
@@ -88,6 +88,8 @@ export const noCustomClassname = createRule<Options, MessageIds>({
8888
type: "object",
8989
properties: {
9090
whitelist: {
91+
description:
92+
"List of classnames to ignore (whitelist). Exact match or regular expression.",
9193
type: "array",
9294
items: { type: "string", minLength: 0 },
9395
uniqueItems: true,
@@ -96,6 +98,7 @@ export const noCustomClassname = createRule<Options, MessageIds>({
9698
additionalProperties: false,
9799
},
98100
],
101+
defaultOptions: [{}],
99102
type: "suggestion",
100103
},
101104
/**
@@ -119,10 +122,10 @@ export const noCustomClassname = createRule<Options, MessageIds>({
119122
context,
120123
settings,
121124
options,
122-
detectCustomClassnames
125+
detectCustomClassnames,
123126
),
124127
// Script visitor is used within both JSX and Vue SFC files (inside <script> section).
125-
createScriptVisitors(context, settings, options, detectCustomClassnames)
128+
createScriptVisitors(context, settings, options, detectCustomClassnames),
126129
);
127130
},
128131
});

src/utils/parser/node.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ test("getClassnamesFromValue", () => {
3939

4040
test("getTemplateElementAffixes", () => {
4141
expect(
42-
getTemplateElementAffixes("`relative grid`", "relative grid")
42+
getTemplateElementAffixes("`relative grid`", "relative grid"),
4343
).toStrictEqual(["`", "`"]);
4444
expect(getTemplateElementAffixes("`absolute ${", "absolute ")).toStrictEqual([
4545
"`",
@@ -56,11 +56,11 @@ test("getTagNameFromTaggedTemplateExpression", () => {
5656
TSESTree.AST_NODE_TYPES.TaggedTemplateExpression
5757
) {
5858
expect(
59-
getTagNameFromTaggedTemplateExpression(attribute.value.expression)
59+
getTagNameFromTaggedTemplateExpression(attribute.value.expression),
6060
).toStrictEqual("tw");
6161
} else {
6262
throw new Error(
63-
"Invalid attribute value for `getTagNameFromTaggedTemplateExpression`"
63+
"Invalid attribute value for `getTagNameFromTaggedTemplateExpression`",
6464
);
6565
}
6666
});

src/utils/parser/node.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export const getTemplateElementAffixes = (haystack: string, needle: string) => {
105105
* getTagNameFromTaggedTemplateExpression(node); // 'tw'
106106
*/
107107
export const getTagNameFromTaggedTemplateExpression = (
108-
node: TSESTree.TaggedTemplateExpression
108+
node: TSESTree.TaggedTemplateExpression,
109109
) => {
110110
switch (node.tag.type) {
111111
case "CallExpression": {
@@ -178,7 +178,7 @@ export const getVAttributeName = (node: VueAST.VAttribute): string => {
178178
*/
179179
export const dissectAtomicNode = (
180180
node: AtomicNode,
181-
context: GenericRuleContext
181+
context: GenericRuleContext,
182182
) => {
183183
let originalClassNamesValue = "";
184184
let start = 0;
@@ -204,11 +204,11 @@ export const dissectAtomicNode = (
204204
// but `value.raw` does not include them, so there is a mismatch.
205205
// start/end does not include the backticks, therefore it matches value.raw.
206206
const rawCode = context.sourceCode.getText(
207-
node as unknown as TSESTree.Node
207+
node as unknown as TSESTree.Node,
208208
);
209209
[prefix, suffix] = getTemplateElementAffixes(
210210
rawCode,
211-
originalClassNamesValue
211+
originalClassNamesValue,
212212
);
213213
break;
214214
}

src/utils/parser/visitors-validation.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { getJSXAttributeName, getVAttributeName } from "./node";
1212
*/
1313
export const isValidJSXAttribute = (
1414
node: TSESTree.JSXAttribute,
15-
settings: PluginSettings
15+
settings: PluginSettings,
1616
): boolean => {
1717
const attributes = (settings && settings.attributes) || [];
1818
// Ignored JSXAttribute
@@ -40,7 +40,7 @@ export const isValidJSXAttribute = (
4040
*/
4141
export const isValidTextAttribute = (
4242
node: TextAttribute,
43-
settings: PluginSettings
43+
settings: PluginSettings,
4444
): boolean => {
4545
const attributes = (settings && settings.attributes) || [];
4646
// Ignored TextAttribute
@@ -58,7 +58,7 @@ export const isValidTextAttribute = (
5858
*/
5959
export const isValidVAttribute = (
6060
node: VueAST.VAttribute,
61-
settings: PluginSettings
61+
settings: PluginSettings,
6262
): boolean => {
6363
const attributes = (settings && settings.attributes) || [];
6464
// Ignored VAttribute
@@ -80,7 +80,7 @@ export const isValidVAttribute = (
8080
*/
8181
export const isValidCallExpression = (
8282
node: TSESTree.CallExpression,
83-
settings: PluginSettings
83+
settings: PluginSettings,
8484
): boolean => {
8585
if (!settings.functions || settings.functions.length === 0) {
8686
return false;
@@ -123,7 +123,7 @@ export const isLiteralAttributeValue = (node: SupportedAttribute) => {
123123
* Validates a `Expression` contained within a `JSXAttribute` for `eslint-plugin-tailwindcss`
124124
* @returns `false` if the `Expression` can be skipped. */
125125
export const isValidExpressionAttributeValue = (
126-
node: TSESTree.JSXAttribute
126+
node: TSESTree.JSXAttribute,
127127
) => {
128128
// No value
129129
if (!node.value) return false;

src/utils/parser/visitors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const getParserServices = (context: Readonly<GenericRuleContext>) => {
2727
export const defineVisitors = (
2828
context: Readonly<GenericRuleContext>,
2929
templateBodyVisitor: RuleListener,
30-
scriptVisitor: RuleListener
30+
scriptVisitor: RuleListener,
3131
) => {
3232
const parserServices = getParserServices(context);
3333
if (
@@ -43,6 +43,6 @@ export const defineVisitors = (
4343
// @ts-expect-error Using "vue-eslint-parser" requires this setup
4444
return parserServices.defineTemplateBodyVisitor(
4545
templateBodyVisitor,
46-
scriptVisitor
46+
scriptVisitor,
4747
);
4848
};

src/utils/tailwindcss-api/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ import { type Theme } from "./types";
77
const require = createRequire(import.meta.url);
88

99
export const loadThemeWorker: (cssConfigPath: string) => Theme = createSyncFn(
10-
require.resolve("./utils/tailwindcss-api/worker/load-theme.mjs"),
10+
require.resolve("./worker/load-theme.mjs"),
1111
);
1212

1313
export const getSortedClassNamesWorker: (
1414
cssConfigPath: string,
1515
unorderedClassNames: Array<string>,
1616
) => Array<string> = createSyncFn(
17-
require.resolve("./utils/tailwindcss-api/worker/get-sorted-class-names.mjs"),
17+
require.resolve("./worker/get-sorted-class-names.mjs"),
1818
);
1919

2020
export const isValidClassNameWorker: (
2121
cssConfigPath: string,
2222
className: string,
2323
) => boolean = createSyncFn(
24-
require.resolve("./utils/tailwindcss-api/worker/is-valid-class-name.mjs"),
24+
require.resolve("./worker/is-valid-class-name.mjs"),
2525
);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Warnings about the `*.mjs` worker files
2+
3+
⚠️ The `*.mjs` files in this folder are worker scripts which are ran in node's `worker_threads`.
4+
5+
🤓 This means that they do NOT not execute in the main thread, but in a separate thread.
6+
7+
😅 Because of this, expect some unusual things, like:
8+
9+
- `console.log` won't work within `vitest`
10+
- You cannot pass complex objects as arguments, only serializable ones.
11+
- You cannot retun complex objects, only serializable ones.
12+
- e.g. You cannot return the `utils.context` directly, but you can return some of its properties…
13+
14+
ℹ️ The `*.mjs` extension indicates that it is an ES module.
15+
16+
ℹ️ It won't be compiled, just **copied as is** into the dist package by the `build` script.
17+
18+
✅ We still check the syntax with TypeScript, but it is not a TypeScript file.
19+
20+
🌀 Using `*.ts` for these files would be tricky because `vitest` needs them "as is" while runtime will expect `*.mjs`.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* ⚠️ Make sure to read the warnings about the `*.mjs` workers
3+
* @see src/utils/tailwindcss-api/worker/README.md
4+
*/
5+
6+
// @ts-check
7+
8+
import { runAsWorker } from "synckit";
9+
import { TailwindUtils } from "tailwind-api-utils";
10+
11+
runAsWorker(
12+
async (
13+
/**
14+
* @type {string} The path to the Tailwind CSS config file
15+
*/
16+
cssConfigPath,
17+
/**
18+
* @type {Array<string>} List of class names to sort
19+
*/
20+
unorderedClassNames,
21+
) => {
22+
const utils = new TailwindUtils();
23+
await utils.loadConfigV4(cssConfigPath);
24+
if (!utils.context) {
25+
throw new Error(
26+
`Failed to load the Tailwind CSS theme using: "${cssConfigPath}"`,
27+
);
28+
}
29+
const sorted = await utils.getSortedClassNames(unorderedClassNames);
30+
return sorted;
31+
},
32+
);

0 commit comments

Comments
 (0)