Skip to content

Commit 4794bce

Browse files
Handle quotes in @plugin, @config, and @source (#387)
* Handle quotes in `@plugin`, `@config`, and `@source` * Update src/index.ts Co-authored-by: Robin Malfait <[email protected]> * Update changelog --------- Co-authored-by: Robin Malfait <[email protected]>
1 parent 20cdfeb commit 4794bce

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Don't augment global Prettier `ParserOptions` and `RequiredOptions` types ([#354](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/354))
1111
- Drop support for `prettier-plugin-import-sort` ([#385](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/385))
12+
- Format quotes in `@source`, `@plugin`, and `@config` ([#387](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/387))
1213

1314
## [0.6.14] - 2025-07-09
1415

src/index.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,38 @@ function transformJavaScript(
786786
}
787787

788788
function transformCss(ast: any, { env }: TransformerContext) {
789+
// `parseValue` inside Prettier's CSS parser is private API so we have to
790+
// produce the same result by parsing an import statement with the same params
791+
function tryParseAtRuleParams(name: string, params: any) {
792+
// It might already be an object or array. Could happen in the future if
793+
// Prettier decides to start parsing these.
794+
if (typeof params !== 'string') return params
795+
796+
// Otherwise we let prettier re-parse the params into its custom value AST
797+
// based on postcss-value parser.
798+
try {
799+
let parser = base.parsers.css
800+
let root = parser.parse(`@import ${params};`, env.options)
801+
802+
return root.nodes[0].params
803+
} catch (err) {
804+
console.warn(`[prettier-plugin-tailwindcss] Unable to parse at rule`)
805+
console.warn({ name, params })
806+
console.warn(err)
807+
}
808+
809+
return params
810+
}
811+
789812
ast.walk((node: any) => {
813+
if (
814+
node.name === 'plugin' ||
815+
node.name === 'config' ||
816+
node.name === 'source'
817+
) {
818+
node.params = tryParseAtRuleParams(node.name, node.params)
819+
}
820+
790821
if (node.type === 'css-atrule' && node.name === 'apply') {
791822
let isImportant = /\s+(?:!important|#{(['"]*)!important\1})\s*$/.test(
792823
node.params,

tests/tests.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ let css: TestEntry[] = [
4343
'@apply p-0\n sm:p-0;',
4444
{ tailwindPreserveWhitespace: true },
4545
],
46+
47+
// Quote conversion for custom at-rules
48+
[`@import "./file.css";`, `@import './file.css';`],
49+
[`@plugin "./file.js";`, `@plugin './file.js';`],
50+
[`@config "./file.js";`, `@config './file.js';`],
51+
[`@source "./file.js";`, `@source './file.js';`],
52+
[`@source not "./file.js";`, `@source not './file.js';`],
53+
[`@source inline("./file.js");`, `@source inline('./file.js');`],
4654
]
4755

4856
export let javascript: TestEntry[] = [

0 commit comments

Comments
 (0)