Home / Function/ upgradeToFullPluginSupport() — tailwindcss Function Reference

upgradeToFullPluginSupport() — tailwindcss Function Reference

Architecture documentation for the upgradeToFullPluginSupport() function in apply-compat-hooks.ts from the tailwindcss codebase.

Entity Profile

Dependency Diagram

graph TD
  0f8ac574_990e_8595_a6ed_11422b8a8ec4["upgradeToFullPluginSupport()"]
  9e2f12c0_83ef_256b_739b_9ec6ebc69b08["applyCompatibilityHooks()"]
  9e2f12c0_83ef_256b_739b_9ec6ebc69b08 -->|calls| 0f8ac574_990e_8595_a6ed_11422b8a8ec4
  678b66f4_0a04_0d6e_1925_b3716614324d["resolveConfig()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| 678b66f4_0a04_0d6e_1925_b3716614324d
  f2c40930_6a99_f9d8_d175_a2d0244b3fec["createCompatConfig()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| f2c40930_6a99_f9d8_d175_a2d0244b3fec
  ad196438_55f7_af7b_1604_1d75c1c27d8e["buildPluginApi()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| ad196438_55f7_af7b_1604_1d75c1c27d8e
  e512528a_2506_964d_514b_bab67f99b575["resolveThemeValue()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| e512528a_2506_964d_514b_bab67f99b575
  ffa1d3be_8116_7cd8_db2c_a42892f9c21a["applyConfigToTheme()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| ffa1d3be_8116_7cd8_db2c_a42892f9c21a
  15c35223_4bac_dcb1_403b_78f4fe4852da["applyKeyframesToTheme()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| 15c35223_4bac_dcb1_403b_78f4fe4852da
  2f08182a_6def_3641_10ac_c1d0b85a8e6f["registerThemeVariantOverrides()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| 2f08182a_6def_3641_10ac_c1d0b85a8e6f
  cae2462d_b48b_78d8_8df1_2534f7aac297["registerScreensConfig()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| cae2462d_b48b_78d8_8df1_2534f7aac297
  b5baf1fc_1222_c1c9_8f71_6bf5775586b4["registerContainerCompat()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| b5baf1fc_1222_c1c9_8f71_6bf5775586b4
  aac1ce38_87b8_e2ee_838b_b9196b3e9299["cssContext()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| aac1ce38_87b8_e2ee_838b_b9196b3e9299
  c3b56f1d_0d90_0f17_2f55_85f3419d74bd["styleRule()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| c3b56f1d_0d90_0f17_2f55_85f3419d74bd
  e9d556bc_f22d_356c_1bd2_27442c34b5c7["walk()"]
  0f8ac574_990e_8595_a6ed_11422b8a8ec4 -->|calls| e9d556bc_f22d_356c_1bd2_27442c34b5c7
  style 0f8ac574_990e_8595_a6ed_11422b8a8ec4 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

packages/tailwindcss/src/compat/apply-compat-hooks.ts lines 217–423

function upgradeToFullPluginSupport({
  designSystem,
  base,
  ast,
  sources,
  configs,
  pluginDetails,
}: {
  designSystem: DesignSystem
  base: string
  ast: AstNode[]
  sources: { base: string; pattern: string; negated: boolean }[]
  configs: {
    path: string
    base: string
    config: UserConfig
    reference: boolean
    src: SourceLocation | undefined
  }[]
  pluginDetails: {
    path: string
    base: string
    plugin: Plugin
    options: CssPluginOptions | null
    reference: boolean
    src: SourceLocation | undefined
  }[]
}) {
  let features = Features.None
  let pluginConfigs = pluginDetails.map((detail) => {
    if (!detail.options) {
      return {
        config: { plugins: [detail.plugin] },
        base: detail.base,
        reference: detail.reference,
        src: detail.src,
      }
    }

    if ('__isOptionsFunction' in detail.plugin) {
      return {
        config: { plugins: [detail.plugin(detail.options)] },
        base: detail.base,
        reference: detail.reference,
        src: detail.src,
      }
    }

    throw new Error(`The plugin "${detail.path}" does not accept options`)
  })

  let userConfig = [...pluginConfigs, ...configs]

  let { resolvedConfig } = resolveConfig(designSystem, [
    { config: createCompatConfig(designSystem.theme), base, reference: true, src: undefined },
    ...userConfig,
    { config: { plugins: [darkModePlugin] }, base, reference: true, src: undefined },
  ])
  let { resolvedConfig: resolvedUserConfig, replacedThemeKeys } = resolveConfig(
    designSystem,
    userConfig,
  )

  let pluginApiConfig = {
    designSystem,
    ast,
    resolvedConfig,
    featuresRef: {
      set current(value: number) {
        features |= value
      },
    },
  }

  let sharedPluginApi = buildPluginApi({
    ...pluginApiConfig,
    referenceMode: false,
    src: undefined,
  })

  // Replace `resolveThemeValue` with a version that is backwards compatible
  // with dot-notation but also aware of any JS theme configurations registered
  // by plugins or JS config files. This is significantly slower than just
  // upgrading dot-notation keys so we only use this version if plugins or
  // config files are actually being used. In the future we may want to optimize
  // this further by only doing this if plugins or config files _actually_
  // registered JS config objects.
  let defaultResolveThemeValue = designSystem.resolveThemeValue
  designSystem.resolveThemeValue = function resolveThemeValue(path: string, forceInline?: boolean) {
    if (path[0] === '-' && path[1] === '-') {
      return defaultResolveThemeValue(path, forceInline)
    }

    let resolvedValue = sharedPluginApi.theme(path, undefined)

    // When a tuple is returned, return the first element
    if (Array.isArray(resolvedValue) && resolvedValue.length === 2) {
      return resolvedValue[0]
    }

    // Arrays get serialized into a comma-separated lists
    else if (Array.isArray(resolvedValue)) {
      return resolvedValue.join(', ')
    }

    // If we're dealing with an object that has the `DEFAULT` key, return the
    // default value
    else if (
      typeof resolvedValue === 'object' &&
      resolvedValue !== null &&
      'DEFAULT' in resolvedValue
    ) {
      return resolvedValue.DEFAULT
    }

    // Otherwise only allow string values here, objects (and namespace maps)
    // are treated as non-resolved values for the CSS `theme()` function.
    else if (typeof resolvedValue === 'string') {
      return resolvedValue
    }
  }

  for (let { handler, reference, src } of resolvedConfig.plugins) {
    // Each plugin gets its own instance of the plugin API because nodes added
    // to the AST may need to point to the `@config` or `@plugin` that they
    // originated from
    let api = buildPluginApi({
      ...pluginApiConfig,
      referenceMode: reference ?? false,
      src,
    })

    handler(api)
  }

  // Merge the user-configured theme keys into the design system. The compat
  // config would otherwise expand into namespaces like `background-color` which
  // core utilities already read from.
  applyConfigToTheme(designSystem, resolvedUserConfig, replacedThemeKeys)
  applyKeyframesToTheme(designSystem, resolvedUserConfig)

  registerThemeVariantOverrides(resolvedUserConfig, designSystem)
  registerScreensConfig(resolvedUserConfig, designSystem)
  registerContainerCompat(resolvedUserConfig, designSystem)

  // If a prefix has already been set in CSS don't override it
  if (!designSystem.theme.prefix && resolvedConfig.prefix) {
    if (resolvedConfig.prefix.endsWith('-')) {
      resolvedConfig.prefix = resolvedConfig.prefix.slice(0, -1)

      console.warn(
        `The prefix "${resolvedConfig.prefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only and is written as a variant before all utilities. We have fixed up the prefix for you. Remove the trailing \`-\` to silence this warning.`,
      )
    }

    if (!IS_VALID_PREFIX.test(resolvedConfig.prefix)) {
      throw new Error(
        `The prefix "${resolvedConfig.prefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.`,
      )
    }

    designSystem.theme.prefix = resolvedConfig.prefix
  }

  // If an important strategy has already been set in CSS don't override it
  if (!designSystem.important && resolvedConfig.important === true) {
    designSystem.important = true
  }

  if (typeof resolvedConfig.important === 'string') {
    let wrappingSelector = resolvedConfig.important

    walk(ast, (node, _ctx) => {
      if (node.kind !== 'at-rule') return
      if (node.name !== '@tailwind' || node.params !== 'utilities') return

      let ctx = cssContext(_ctx)

      // The AST node was already manually wrapped so there's nothing to do
      if (ctx.parent?.kind === 'rule' && ctx.parent.selector === wrappingSelector) {
        return WalkAction.Stop
      }

      return WalkAction.ReplaceStop(styleRule(wrappingSelector, [node]))
    })
  }

  for (let candidate of resolvedConfig.blocklist) {
    designSystem.invalidCandidates.add(candidate)
  }

  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.`,
      )
    }

    let negated = false
    if (file.pattern[0] == '!') {
      negated = true
      file.pattern = file.pattern.slice(1)
    }
    sources.push({ ...file, negated })
  }
  return features
}

Subdomains

Frequently Asked Questions

What does upgradeToFullPluginSupport() do?
upgradeToFullPluginSupport() is a function in the tailwindcss codebase.
What does upgradeToFullPluginSupport() call?
upgradeToFullPluginSupport() calls 12 function(s): applyConfigToTheme, applyKeyframesToTheme, buildPluginApi, createCompatConfig, cssContext, registerContainerCompat, registerScreensConfig, registerThemeVariantOverrides, and 4 more.
What calls upgradeToFullPluginSupport()?
upgradeToFullPluginSupport() is called by 1 function(s): applyCompatibilityHooks.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free