%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/forge/takeaseat.eco-n-tech.co.uk/node_modules/tailwindcss/jit/lib/
Upload File :
Create Path :
Current File : //home/forge/takeaseat.eco-n-tech.co.uk/node_modules/tailwindcss/jit/lib/expandTailwindAtRules.js

const fs = require('fs')
const path = require('path')
const fastGlob = require('fast-glob')
const parseGlob = require('parse-glob')
const sharedState = require('./sharedState')
const { generateRules } = require('./generateRules')
const { bigSign, cloneNodes } = require('./utils')

let env = sharedState.env
let contentMatchCache = sharedState.contentMatchCache

const BROAD_MATCH_GLOBAL_REGEXP = /[^<>"'`\s]*[^<>"'`\s:]/g
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g

function getDefaultExtractor(fileExtension) {
  return function (content) {
    if (fileExtension === 'svelte') {
      content = content.replace(/\sclass:/g, ' ')
    }
    let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || []
    let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []

    return [...broadMatches, ...innerMatches]
  }
}

function getExtractor(fileName, tailwindConfig) {
  const purgeOptions = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.options
  const fileExtension = path.extname(fileName).slice(1)

  if (!purgeOptions) {
    return getDefaultExtractor(fileExtension)
  }

  const fileSpecificExtractor = (purgeOptions.extractors || []).find((extractor) =>
    extractor.extensions.includes(fileExtension)
  )

  if (fileSpecificExtractor) {
    return fileSpecificExtractor.extractor
  }

  return purgeOptions.defaultExtractor || getDefaultExtractor(fileExtension)
}

// Scans template contents for possible classes. This is a hot path on initial build but
// not too important for subsequent builds. The faster the better though — if we can speed
// up these regexes by 50% that could cut initial build time by like 20%.
function getClassCandidates(content, extractor, contentMatchCache, candidates, seen) {
  for (let line of content.split('\n')) {
    line = line.trim()

    if (seen.has(line)) {
      continue
    }
    seen.add(line)

    if (contentMatchCache.has(line)) {
      for (let match of contentMatchCache.get(line)) {
        candidates.add(match)
      }
    } else {
      let extractorMatches = extractor(line)
      let lineMatchesSet = new Set(extractorMatches)

      for (let match of lineMatchesSet) {
        candidates.add(match)
      }

      contentMatchCache.set(line, lineMatchesSet)
    }
  }
}

function buildStylesheet(rules, context) {
  let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))

  let returnValue = {
    base: new Set(),
    components: new Set(),
    utilities: new Set(),
    screens: new Set(),
  }

  for (let [sort, rule] of sortedRules) {
    if (sort >= context.minimumScreen) {
      returnValue.screens.add(rule)
      continue
    }

    if (sort & context.layerOrder.base) {
      returnValue.base.add(rule)
      continue
    }

    if (sort & context.layerOrder.components) {
      returnValue.components.add(rule)
      continue
    }

    if (sort & context.layerOrder.utilities) {
      returnValue.utilities.add(rule)
      continue
    }
  }

  return returnValue
}

function expandTailwindAtRules(context, registerDependency) {
  return (root) => {
    let foundTailwind = false
    let layerNodes = {
      base: null,
      components: null,
      utilities: null,
      screens: null,
    }

    // Make sure this file contains Tailwind directives. If not, we can save
    // a lot of work and bail early. Also we don't have to register our touch
    // file as a dependency since the output of this CSS does not depend on
    // the source of any templates. Think Vue <style> blocks for example.
    root.walkAtRules('tailwind', (rule) => {
      foundTailwind = true

      if (rule.params === 'base') {
        layerNodes.base = rule
      }

      if (rule.params === 'components') {
        layerNodes.components = rule
      }

      if (rule.params === 'utilities') {
        layerNodes.utilities = rule
      }

      if (rule.params === 'screens') {
        layerNodes.screens = rule
      }
    })

    if (!foundTailwind) {
      return root
    }

    // ---

    if (sharedState.env.TAILWIND_DISABLE_TOUCH) {
      for (let maybeGlob of context.candidateFiles) {
        let {
          is: { glob: isGlob },
          base,
        } = parseGlob(maybeGlob)

        if (isGlob) {
          // register base dir as `dependency` _and_ `context-dependency` for
          // increased compatibility
          registerDependency(path.resolve(base))
          registerDependency(path.resolve(base), 'context-dependency')
        } else {
          registerDependency(path.resolve(maybeGlob))
        }
      }

      env.DEBUG && console.time('Finding changed files')
      let files = fastGlob.sync(context.candidateFiles)
      for (let file of files) {
        let prevModified = context.fileModifiedMap.has(file)
          ? context.fileModifiedMap.get(file)
          : -Infinity
        let modified = fs.statSync(file).mtimeMs

        if (!context.scannedContent || modified > prevModified) {
          context.changedFiles.add(file)
          context.fileModifiedMap.set(file, modified)
        }
      }
      context.scannedContent = true
      env.DEBUG && console.timeEnd('Finding changed files')
    } else {
      // Register our temp file as a dependency — we write to this file
      // to trigger rebuilds.
      if (context.touchFile) {
        registerDependency(context.touchFile)
      }

      // If we're not set up and watching files ourselves, we need to do
      // the work of grabbing all of the template files for candidate
      // detection.
      if (!context.scannedContent) {
        let files = fastGlob.sync(context.candidateFiles)
        for (let file of files) {
          context.changedFiles.add(file)
        }
        context.scannedContent = true
      }
    }

    // ---

    // Find potential rules in changed files
    let candidates = new Set(['*'])
    let seen = new Set()

    env.DEBUG && console.time('Reading changed files')
    for (let file of context.changedFiles) {
      let content = fs.readFileSync(file, 'utf8')
      let extractor = getExtractor(file, context.tailwindConfig)
      getClassCandidates(content, extractor, contentMatchCache, candidates, seen)
    }
    env.DEBUG && console.timeEnd('Reading changed files')

    // ---

    // Generate the actual CSS
    let classCacheCount = context.classCache.size

    env.DEBUG && console.time('Generate rules')
    let rules = generateRules(candidates, context)
    env.DEBUG && console.timeEnd('Generate rules')

    // We only ever add to the classCache, so if it didn't grow, there is nothing new.
    env.DEBUG && console.time('Build stylesheet')
    if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
      for (let rule of rules) {
        context.ruleCache.add(rule)
      }

      context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
    }
    env.DEBUG && console.timeEnd('Build stylesheet')

    let {
      base: baseNodes,
      components: componentNodes,
      utilities: utilityNodes,
      screens: screenNodes,
    } = context.stylesheetCache

    // ---

    // Replace any Tailwind directives with generated CSS

    if (layerNodes.base) {
      layerNodes.base.before(cloneNodes([...baseNodes]))
      layerNodes.base.remove()
    }

    if (layerNodes.components) {
      layerNodes.components.before(cloneNodes([...componentNodes]))
      layerNodes.components.remove()
    }

    if (layerNodes.utilities) {
      layerNodes.utilities.before(cloneNodes([...utilityNodes]))
      layerNodes.utilities.remove()
    }

    if (layerNodes.screens) {
      layerNodes.screens.before(cloneNodes([...screenNodes]))
      layerNodes.screens.remove()
    } else {
      root.append(cloneNodes([...screenNodes]))
    }

    // ---

    if (env.DEBUG) {
      console.log('Changed files: ', context.changedFiles.size)
      console.log('Potential classes: ', candidates.size)
      console.log('Active contexts: ', sharedState.contextSourcesMap.size)
      console.log('Content match entries', contentMatchCache.size)
    }

    // Clear the cache for the changed files
    context.changedFiles.clear()
  }
}

module.exports = expandTailwindAtRules

Zerion Mini Shell 1.0