Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/tailwind4.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const tailwind4 = {
descriptors: defaultSyntax.properties,
},
source: {
prelude: "<string>",
prelude: "<url> | inline( <string># ) | not inline( <string># )",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double-check: Can url() be used with @source? I couldn't find that in the docs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot double-check this please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right - url() is not supported with @source in Tailwind CSS 4. I incorrectly added that syntax. The @source directive is specifically for safelisting utilities and only supports inline() and not inline() functions. I've removed the URL support in commit 95547d4.

},
utility: {
prelude: "<ident>",
Expand Down
94 changes: 94 additions & 0 deletions tests/tailwind4.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,100 @@ describe("Tailwind 4", function () {
]
});
});

it("should parse @source with inline function", () => {
const tree = toPlainObject(parse("@source inline('{hover:,focus:,}underline');"));
assert.deepStrictEqual(tree, {
type: "StyleSheet",
loc: null,
children: [
{
type: "Atrule",
name: "source",
prelude: {
type: "AtrulePrelude",
loc: null,
children: [
{
type: "Function",
name: "inline",
children: [
{
type: "String",
value: "{hover:,focus:,}underline",
loc: null
}
],
loc: null
}
]
},
block: null,
loc: null
}
]
});
});

it("should parse @source with not inline function", () => {
const tree = toPlainObject(parse("@source not inline('container');"));
assert.deepStrictEqual(tree, {
type: "StyleSheet",
loc: null,
children: [
{
type: "Atrule",
name: "source",
prelude: {
type: "AtrulePrelude",
loc: null,
children: [
{
type: "Identifier",
name: "not",
loc: null
},
{
type: "Function",
name: "inline",
children: [
{
type: "String",
value: "container",
loc: null
}
],
loc: null
}
]
},
block: null,
loc: null
}
]
});
});

it("should validate @source with URL syntax", () => {
const tree = parse("@source url('https://example.com/styles.css');");
const atrule = tree.children.toArray()[0];
const validation = lexer.matchAtrulePrelude(atrule.name, atrule.prelude);
assert.strictEqual(validation.error, null);
});

it("should validate @source with inline function", () => {
const tree = parse("@source inline('{hover:,focus:,}underline');");
const atrule = tree.children.toArray()[0];
const validation = lexer.matchAtrulePrelude(atrule.name, atrule.prelude);
assert.strictEqual(validation.error, null);
});

it("should validate @source with not inline function", () => {
const tree = parse("@source not inline('container');");
const atrule = tree.children.toArray()[0];
const validation = lexer.matchAtrulePrelude(atrule.name, atrule.prelude);
assert.strictEqual(validation.error, null);
});
});

describe("@variant", () => {
Expand Down