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

Code before:
      path: pluginPath,
      plugin: await loadPlugin(pluginPath),
      options: pluginOptions,
    })),
  )

  let { pluginApi, resolvedConfig } = registerPlugins(plugins, designSystem, ast, configs)

  for (let customVariant of customVariants) {
    customVariant(designSystem)
  }

  for (let customUtility of customUtilities) {
    customUtility(designSystem)
  }

  // Replace `@apply` rules with the actual utility classes.
  if (css.includes('@apply')) {
    substituteAtApply(ast, designSystem)
  }

  // Replace `theme()` function calls with the actual theme variables. Plugins
  // could register new rules that include functions, and JS config files could
  // also contain functions or plugins that use functions so we need to evaluate
  // functions if either of those are present.
  if (css.includes(THEME_FUNCTION_INVOCATION) || plugins.length > 0 || configs.length > 0) {
    substituteFunctions(ast, pluginApi)
  }

  // Remove `@utility`, we couldn't replace it before yet because we had to
  // handle the nested `@apply` at-rules first.
  walk(ast, (node, { replaceWith }) => {
    if (node.kind !== 'rule') return

    if (node.selector[0] === '@' && node.selector.startsWith('@utility ')) {
      replaceWith([])
    }

    // The `@utility` has to be top-level, therefore we don't have to traverse
    // into nested trees.
    return WalkAction.Skip
  })

  for (let file of resolvedConfig.content.files) {
    if ('raw' in file) {
      throw new Error(
        `Error in the config file/plugin/preset. The \`content\` key contains a \`raw\` entry:\n\n${JSON.stringify(file, null, 2)}\n\nThis feature is not currently supported.`,
      )
    }

    globs.push({ origin: file.base, pattern: file.pattern })

Review comment (suggestion):
The `theme()` calls from utilities are *not* processed by this call to `substituteFunctions`. The call in `build()` handles that because the generated nodes are the ones that have theme().

This is purely required for the work where we're taking the config stuff and backfilling some values into the theme (which ultimately makes it into the "static" AST).

So maybe the comment could use some clarification.

Code after:
      path: pluginPath,
      plugin: await loadPlugin(pluginPath),
      options: pluginOptions,
    })),
  )

  let { pluginApi, resolvedConfig } = registerPlugins(plugins, designSystem, ast, configs)

  for (let customVariant of customVariants) {
    customVariant(designSystem)
  }

  for (let customUtility of customUtilities) {
    customUtility(designSystem)
  }

  // Replace `@apply` rules with the actual utility classes.
  if (css.includes('@apply')) {
    substituteAtApply(ast, designSystem)
  }

  // Replace `theme()` function calls with the actual theme variables. Plugins
  // could register new rules that include functions, and JS config files could
  // also contain functions or plugins that use functions so we need to evaluate
  // functions if either of those are present.
  if (plugins.length > 0 || configs.length > 0 || css.includes(THEME_FUNCTION_INVOCATION)) {
    substituteFunctions(ast, pluginApi)
  }

  // Remove `@utility`, we couldn't replace it before yet because we had to
  // handle the nested `@apply` at-rules first.
  walk(ast, (node, { replaceWith }) => {
    if (node.kind !== 'rule') return

    if (node.selector[0] === '@' && node.selector.startsWith('@utility ')) {
      replaceWith([])
    }

    // The `@utility` has to be top-level, therefore we don't have to traverse
    // into nested trees.
    return WalkAction.Skip
  })

  for (let file of resolvedConfig.content.files) {
    if ('raw' in file) {
      throw new Error(
        `Error in the config file/plugin/preset. The \`content\` key contains a \`raw\` entry:\n\n${JSON.stringify(file, null, 2)}\n\nThis feature is not currently supported.`,
      )
    }

    globs.push({ origin: file.base, pattern: file.pattern })