Repository: tailwindlabs/tailwindcss
File: packages/@tailwindcss-upgrade/src/codemods/migrate-at-config.ts (TypeScript)

Code before:

    // We already have a `@config`
    if (hasConfig) return

    // We don't have a sheet with a file path
    if (!sheet.file) return

    // Should this sheet have an `@config`?
    // 1. It should be a root CSS file
    if (sheet.parents.size > 0) return

    // 2. It should include a `@import "tailwindcss"`
    let hasTailwindImport = false
    root.walkAtRules('import', (node) => {
      if (node.params.includes('tailwindcss')) {
        hasTailwindImport = true
        return false
      }
    })
    if (!hasTailwindImport) return

    // Figure out the path to the config file
    let sheetPath = sheet.file
    let configPath = configFilePath

    let relativePath = path.relative(path.dirname(sheetPath), configPath).replaceAll('\\', '/')
    if (relativePath[0] !== '.') {
      relativePath = `./${relativePath}`
    }

    // Inject the `@config` in a sensible place
    let locationNode = null as AtRule | null

    walk(root, (node) => {
      if (node.type === 'atrule' && (node.name === 'import' || node.name === 'theme')) {
        locationNode = node
      }

      return WalkAction.Skip
    })

    let configNode = new AtRule({ name: 'config', params: `"${relativePath}"` })

    if (!locationNode) {
      root.prepend(configNode)
    } else if (locationNode.name === 'import') {
      locationNode.after(configNode)
    } else if (locationNode.name === 'theme') {
      locationNode.before(configNode)
    }
  }

Review comment (suggestion):
I don't completely recall but we have a normalizePath function in `@tailwindcss/node` and I _think_ it can handle relative paths. Might be good to use that here.

Code after:

    // Skip if there is already a `@config` directive
    {
      let hasConfig = false
      root.walkAtRules('config', () => {
        hasConfig = true
        return false
      })
      if (hasConfig) return
    }

    // Figure out the path to the config file
    let sheetPath = sheet.file
    let configPath = configFilePath

    let relative = path.relative(path.dirname(sheetPath), configPath)
    if (relative[0] !== '.') {
      relative = `./${relative}`
    }
    // Ensure relative is a posix style path since we will merge it with the
    // glob.
    relative = normalizePath(relative)

    // Inject the `@config` in a sensible place
    // 1. Below the last `@import`
    // 2. At the top of the file
    let locationNode = null as AtRule | null

    walk(root, (node) => {
      if (node.type === 'atrule' && node.name === 'import') {
        locationNode = node
      }

      return WalkAction.Skip
    })

    let configNode = new AtRule({ name: 'config', params: `"${relative}"` })

    if (!locationNode) {
      root.prepend(configNode)
    } else if (locationNode.name === 'import') {
      locationNode.after(configNode)
    }
  }

  function migrate(root: Root) {
    // We can only migrate if there is an `@import "tailwindcss"` (or sub-import)
    let hasTailwindImport = false
    let hasFullTailwindImport = false
    root.walkAtRules('import', (node) => {
      if (node.params.match(/['"]tailwindcss['"]/)) {