Repository: tailwindlabs/tailwindcss
File: packages/tailwindcss/src/index.ts (TypeScript)

Code before:
    let candidates = node.selector
      .slice(7 /* Ignore `@apply ` when parsing the selector */)
      .trim()
      .split(/\s+/g)

    // Replace the `@apply` rule with the actual utility classes
    {
      // Parse the candidates to an AST that we can replace the `@apply` rule
      // with.
      let candidateAst = compileCandidates(candidates, designSystem, {
        onInvalidCandidate: (candidate) => {
          throw new Error(`Cannot apply unknown utility class: ${candidate}`)
        },
      }).astNodes

      // Collect the nodes to insert in place of the `@apply` rule. When a rule
      // was used, we want to insert its children instead of the rule because we
      // don't want the wrapping selector.
      let newNodes: AstNode[] = []
      for (let candidateNode of candidateAst) {
        if (candidateNode.kind === 'rule' && candidateNode.selector[0] !== '@') {
          for (let child of candidateNode.nodes) {
            newNodes.push(child)
          }
        } else {
          newNodes.push(candidateNode)
        }
      }

      // Verify that we don't have any circular dependencies by verifying that
      // the current node does not appear in the new nodes.
      walk(newNodes, (child) => {
        if (child !== node) return

        // At this point we already know that we have a circular dependency.
        //
        // Figure out which candidate caused the circular dependency. This will
        // help to create a useful error message for the end user.
        let candidate = candidates.find((candidate) => {
          let selector = `.${escape(candidate)}`
          let found = false

          for (let rule of candidateAst) {
            if (rule.kind !== 'rule') continue
            if (rule.selector !== selector) continue

            walk(rule.nodes, (child) => {
              if (child === node) {
                found = true
                return WalkAction.Stop
              }

Review comment (suggestion):
This function is a copy of the existing `@apply` handling.

The only differences are:
1. This additional walk to detect circular dependencies
2. The early returns at the top to reduce the level of nesting

Code after:
    {
      // Parse the candidates to an AST that we can replace the `@apply` rule
      // with.
      let candidateAst = compileCandidates(candidates, designSystem, {
        onInvalidCandidate: (candidate) => {
          throw new Error(`Cannot apply unknown utility class: ${candidate}`)
        },
      }).astNodes

      // Collect the nodes to insert in place of the `@apply` rule. When a rule
      // was used, we want to insert its children instead of the rule because we
      // don't want the wrapping selector.
      let newNodes: AstNode[] = []
      for (let candidateNode of candidateAst) {
        if (candidateNode.kind === 'rule' && candidateNode.selector[0] !== '@') {
          for (let child of candidateNode.nodes) {
            newNodes.push(child)
          }
        } else {
          newNodes.push(candidateNode)
        }
      }

      // Verify that we don't have any circular dependencies by verifying that
      // the current node does not appear in the new nodes.
      walk(newNodes, (child) => {
        if (child !== node) return

        // At this point we already know that we have a circular dependency.
        //
        // Figure out which candidate caused the circular dependency. This will
        // help to create a useful error message for the end user.
        for (let candidate of candidates) {
          let selector = `.${escape(candidate)}`

          for (let rule of candidateAst) {
            if (rule.kind !== 'rule') continue
            if (rule.selector !== selector) continue

            walk(rule.nodes, (child) => {
              if (child !== node) return

              throw new Error(
                `You cannot \`@apply\` the \`${candidate}\` utility here because it creates a circular dependency.`,
              )
            })
          }
        }
      })

      replaceWith(newNodes)