Skip to content

Commit 9df5ba7

Browse files
Fix PostCSS crash when using toJSON() (#18083)
When I added source maps to PostCSS I mistakenly assumed that `.source` on a node could be `undefined`. The comment above the property in PostCSS says that `source` can be `undefined` but this is a commentary on the value upon **access** not its expected value on **write**: ```ts declare abstract class Node_ { /** * … * * The nodes that are created manually using the public APIs * provided by PostCSS will have `source` undefined and * will be absent in the source map. * * … */ source?: Node.Source } ``` Rather, what these types mean is that *if the property exists* it must be defined. But otherwise the property can be missing if a node has no source location metadata. This generally wasn't a problem with the string-returning APIs but the `toJSON()` API in PostCSS expects that `source` is defined if present. This caused a crash because our license comment doesn't have a source location. I've addressed this by deleting the `source` property from the node if source location data is not available. Fixes #18082 ref parcel-bundler/parcel#10161
1 parent a42251c commit 9df5ba7

File tree

1 file changed

+18
-4
lines changed
  • packages/@tailwindcss-postcss/src

1 file changed

+18
-4
lines changed

packages/@tailwindcss-postcss/src/ast.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
4949
}
5050
}
5151

52+
function updateSource(astNode: PostCssChildNode, loc: SourceLocation | undefined) {
53+
let source = toSource(loc)
54+
55+
// The `source` property on PostCSS nodes must be defined if present because
56+
// `toJSON()` reads each property and tries to read from source.input if it
57+
// sees a `source` property. This means for a missing or otherwise absent
58+
// source it must be *missing* from the object rather than just `undefined`
59+
if (source) {
60+
astNode.source = source
61+
} else {
62+
delete astNode.source
63+
}
64+
}
65+
5266
function transform(node: AstNode, parent: PostCssContainerNode) {
5367
// Declaration
5468
if (node.kind === 'declaration') {
@@ -57,14 +71,14 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
5771
value: node.value ?? '',
5872
important: node.important,
5973
})
60-
astNode.source = toSource(node.src)
74+
updateSource(astNode, node.src)
6175
parent.append(astNode)
6276
}
6377

6478
// Rule
6579
else if (node.kind === 'rule') {
6680
let astNode = postcss.rule({ selector: node.selector })
67-
astNode.source = toSource(node.src)
81+
updateSource(astNode, node.src)
6882
astNode.raws.semicolon = true
6983
parent.append(astNode)
7084
for (let child of node.nodes) {
@@ -75,7 +89,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
7589
// AtRule
7690
else if (node.kind === 'at-rule') {
7791
let astNode = postcss.atRule({ name: node.name.slice(1), params: node.params })
78-
astNode.source = toSource(node.src)
92+
updateSource(astNode, node.src)
7993
astNode.raws.semicolon = true
8094
parent.append(astNode)
8195
for (let child of node.nodes) {
@@ -90,7 +104,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
90104
// spaces.
91105
astNode.raws.left = ''
92106
astNode.raws.right = ''
93-
astNode.source = toSource(node.src)
107+
updateSource(astNode, node.src)
94108
parent.append(astNode)
95109
}
96110

0 commit comments

Comments
 (0)