Repository: tailwindlabs/tailwindcss
File: packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts (TypeScript)

Code before:
      return [substituteFunctionsInValue(ast, toTheme), null]
    }

    // Only a single `theme(…)` with a modifier left, that modifier will be
    // migrated to a candidate modifier.
    let modifier: CandidateModifier | null = null
    let result = substituteFunctionsInValue(ast, (path, fallback) => {
      let parts = segment(path, '/').map((part) => part.trim())

      // Multiple `/` separators, which makes this an invalid path
      if (parts.length > 2) {
        return null
      }

      // The path contains a `/`, which means that there is a modifier such as
      // `theme(colors.red.500/50%)`.
      //
      // Currently, we are assuming that this is only being used for colors,
      // which means that we can typically convert them to a modifier on the
      // candidate itself.
      //
      // If however the `theme(…)` is used with a color, and other ast nodes
      // exists then we don't want to handle it as a modifier because it's not
      // guaranteed that the value is a color.
      //
      // E.g.: `inset 0px 1px theme(colors.red.500/50%)` is a shadow, not a color.
      if (ast.length === 1 && parts.length === 2 && options & Convert.MigrateModifier) {
        let [pathPart, modifierPart] = parts

        // 50% -> /50
        if (/^\d+%$/.test(modifierPart)) {
          modifier = { kind: 'named', value: modifierPart.slice(0, -1) }
        }

        // .12 -> /12
        // .12345 -> /[12.345]
        else if (/^0?\.\d+$/.test(modifierPart)) {
          let value = Number(modifierPart) * 100
          modifier = {
            kind: Number.isInteger(value) ? 'named' : 'arbitrary',
            value: value.toString(),
          }
        }

        // Anything else becomes arbitrary
        else {
          modifier = { kind: 'arbitrary', value: modifierPart }
        }

        // Update path to be the first part
        path = pathPart

Review comment (suggestion):
```suggestion
      //
      // If there is more than one node in the AST though, `theme(…)` must not
      // be the whole value so it's not safe to use a modifier instead.
      //
      // E.g.: `inset 0px 1px theme(colors.red.500/50%)` is a shadow, not a color.
```

Code after:
      return [substituteFunctionsInValue(ast, toTheme), null]
    }

    // Only a single `theme(…)` with a modifier left, that modifier will be
    // migrated to a candidate modifier.
    let modifier: CandidateModifier | null = null
    let result = substituteFunctionsInValue(ast, (path, fallback) => {
      let parts = segment(path, '/').map((part) => part.trim())

      // Multiple `/` separators, which makes this an invalid path
      if (parts.length > 2) {
        return null
      }

      // The path contains a `/`, which means that there is a modifier such as
      // `theme(colors.red.500/50%)`.
      //
      // Currently, we are assuming that this is only being used for colors,
      // which means that we can typically convert them to a modifier on the
      // candidate itself.
      //
      // If there is more than one node in the AST though, `theme(…)` must not
      // be the whole value so it's not safe to use a modifier instead.
      //
      // E.g.: `inset 0px 1px theme(colors.red.500/50%)` is a shadow, not a color.
      if (ast.length === 1 && parts.length === 2 && options & Convert.MigrateModifier) {
        let [pathPart, modifierPart] = parts

        // 50% -> /50
        if (/^\d+%$/.test(modifierPart)) {
          modifier = { kind: 'named', value: modifierPart.slice(0, -1) }
        }

        // .12 -> /12
        // .12345 -> /[12.345]
        else if (/^0?\.\d+$/.test(modifierPart)) {
          let value = Number(modifierPart) * 100
          modifier = {
            kind: Number.isInteger(value) ? 'named' : 'arbitrary',
            value: value.toString(),
          }
        }

        // Anything else becomes arbitrary
        else {
          modifier = { kind: 'arbitrary', value: modifierPart }
        }

        // Update path to be the first part
        path = pathPart
      }