import colors from 'picocolors'
import { createDebugger, getHash } from '../utils'
import {
  type PromiseWithResolvers,
  promiseWithResolvers,
} from '../../shared/utils'
import type { DevEnvironment } from '../server/environment'
import { devToScanEnvironment } from './scan'
import {
  addManuallyIncludedOptimizeDeps,
  addOptimizedDepInfo,
  createIsOptimizedDepFile,
  createIsOptimizedDepUrl,
  depsFromOptimizedDepInfo,
  depsLogString,
  discoverProjectDependencies,
  extractExportsData,
  getOptimizedDepPath,
  initDepsOptimizerMetadata,
  loadCachedDepOptimizationMetadata,
  optimizeExplicitEnvironmentDeps,
  runOptimizeDeps,
  toDiscoveredDependencies,
} from './index'
import type {
  DepOptimizationMetadata,
  DepOptimizationResult,
  DepsOptimizer,
  OptimizedDepInfo,
} from './index'

const debug = createDebugger('vite:deps')

/**
 * The amount to wait for requests to register newly found dependencies before triggering
 * a re-bundle + page reload
 */
const debounceMs = 100

export function createDepsOptimizer(
  environment: DevEnvironment,
): DepsOptimizer {
  const { logger } = environment
  const sessionTimestamp = Date.now().toString()

  let debounceProcessingHandle: NodeJS.Timeout | undefined

  let closed = false

  const options = environment.config.optimizeDeps

  const { noDiscovery, holdUntilCrawlEnd } = options

  let metadata: DepOptimizationMetadata = initDepsOptimizerMetadata(
    environment,
    sessionTimestamp,
  )

  const depsOptimizer: DepsOptimizer = {
    init,
    metadata,
    registerMissingImport,
    run: () => debouncedProcessing(0),
    isOptimizedDepFile: createIsOptimizedDepFile(environment),
    isOptimizedDepUrl: createIsOptimizedDepUrl(environment),
    getOptimizedDepId: (depInfo: OptimizedDepInfo) =>
      `${depInfo.file}?v=${depInfo.browserHash}`,
    close,
    options,
  }

  let newDepsDiscovered = false

  let newDepsToLog: string[] = []
  let newDepsToLogHandle: NodeJS.Timeout | undefined
  const logNewlyDiscoveredDeps = () => {
    if (newDepsToLog.length) {
      const dependencyLabel =
        newDepsToLog.length === 1 ? 'dependency' : 'dependencies'
      logger.info(
        colors.green(
          `${dependencyLabel} optimized: ${depsLogString(newDepsToLog)}`,
        ),
        {
          timestamp: true,
        },
      )
      newDepsToLog = []
    }
  }

  let discoveredDepsWhileScanning: string[] = []
  const logOptimizeDepsIncludeSuggestion = (reason: string) => {
    if (discoveredDepsWhileScanning.length) {
      logger.info(
        colors.magenta(
          `tip: consider adding ${depsLogString(
            discoveredDepsWhileScanning,
          )} to optimizeDeps.include to ${reason}`,
        ) +
          colors.dim(
            `\n  See https://vite.dev/guide/dep-pre-bundling.html#customizing-the-behavior`,
          ),
        {
          timestamp: true,
        },
      )
      discoveredDepsWhileScanning = []
    }
  }

  let depOptimizationProcessing = promiseWithResolvers<void>()
  let depOptimizationProcessingQueue: PromiseWithResolvers<void>[] = []
  const resolveEnqueuedProcessingPromises = () => {
    // Resolve all the processings (including the ones which were delayed)
    for (const processing of depOptimizationProcessingQueue) {
      processing.resolve()
    }
    depOptimizationProcessingQueue = []
  }

  let enqueuedRerun: (() => void) | undefined
  let currentlyProcessing = false

  let firstRunCalled = false
  let warnAboutMissedDependencies = false

  // If this is a cold run, we wait for static imports discovered
  // from the first request before resolving to minimize full page reloads.
  // On warm start or after the first optimization is run, we use a simpler
  // debounce strategy each time a new dep is discovered.
  let waitingForCrawlEnd = false

  let optimizationResult:
    | {
        cancel: () => Promise<void>
        result: Promise<DepOptimizationResult>
      }
    | undefined

  let discover:
    | {
        cancel: () => Promise<void>
        result: Promise<Record<string, string>>
      }
    | undefined

  async function close() {
    closed = true
    await Promise.allSettled([
      discover?.cancel(),
      depsOptimizer.scanProcessing,
      optimizationResult?.cancel(),
    ])
  }

  let initState: 'idle' | 'initializing' | 'initialized' = 'idle'
  async function init() {
    if (initState !== 'idle') return
    initState = 'initializing'

    const cachedMetadata = await loadCachedDepOptimizationMetadata(environment)

    firstRunCalled = !!cachedMetadata

    metadata = depsOptimizer.metadata =
      cachedMetadata || initDepsOptimizerMetadata(environment, sessionTimestamp)

    if (!cachedMetadata) {
      waitingForCrawlEnd = true

      // Enter processing state until crawl of static imports ends
      currentlyProcessing = true

      // Initialize discovered deps with manually added optimizeDeps.include info

      const manuallyIncludedDeps: Record<string, string> = {}
      await addManuallyIncludedOptimizeDeps(environment, manuallyIncludedDeps)

      const manuallyIncludedDepsInfo = toDiscoveredDependencies(
        environment,
        manuallyIncludedDeps,
        sessionTimestamp,
      )

      for (const depInfo of Object.values(manuallyIncludedDepsInfo)) {
        addOptimizedDepInfo(metadata, 'discovered', {
          ...depInfo,
          processing: depOptimizationProcessing.promise,
        })
        newDepsDiscovered = true
      }

      environment.waitForRequestsIdle().then(onCrawlEnd)

      if (noDiscovery) {
        // We don't need to scan for dependencies or wait for the static crawl to end
        // Run the first optimization run immediately
        runOptimizer()
      } else {
        // Important, the scanner is dev only
        depsOptimizer.scanProcessing = new Promise((resolve) => {
          // Runs in the background in case blocking high priority tasks
          ;(async () => {
            try {
              debug?.(colors.green(`scanning for dependencies...`))

              const scanTimer = setTimeout(() => {
                logger.info('[optimizer] scanning dependencies...', {
                  timestamp: true,
                })
              }, 1000)

              let deps: Record<string, string>
              try {
                discover = discoverProjectDependencies(
                  devToScanEnvironment(environment),
                )
                deps = await discover.result
                discover = undefined
              } catch (e) {
                environment.logger.error(
                  colors.red(
                    '(!) Failed to run dependency scan. ' +
                      'Skipping dependency pre-bundling. ' +
                      e.stack,
                  ),
                )
                return
              } finally {
                clearTimeout(scanTimer)
              }

              const manuallyIncluded = Object.keys(manuallyIncludedDepsInfo)
              discoveredDepsWhileScanning.push(
                ...Object.keys(metadata.discovered).filter(
                  (dep) => !deps[dep] && !manuallyIncluded.includes(dep),
                ),
              )

              // Add these dependencies to the discovered list, as these are currently
              // used by the preAliasPlugin to support aliased and optimized deps.
              // This is also used by the CJS externalization heuristics in legacy mode
              for (const id of Object.keys(deps)) {
                if (!metadata.discovered[id]) {
                  addMissingDep(id, deps[id])
                }
              }

              const knownDeps = prepareKnownDeps()
              startNextDiscoveredBatch()

              // For dev, we run the scanner and the first optimization
              // run on the background
              optimizationResult = runOptimizeDeps(environment, knownDeps)

              // If the holdUntilCrawlEnd strategy is used, we wait until crawling has
              // ended to decide if we send this result to the browser or we need to
              // do another optimize step
              if (!holdUntilCrawlEnd) {
                // If not, we release the result to the browser as soon as the scanner
                // is done. If the scanner missed any dependency, and a new dependency
                // is discovered while crawling static imports, then there will be a
                // full-page reload if new common chunks are generated between the old
                // and new optimized deps.
                optimizationResult.result.then((result) => {
                  // Check if the crawling of static imports has already finished. In that
                  // case, the result is handled by the onCrawlEnd callback
                  if (!waitingForCrawlEnd) return

                  optimizationResult = undefined // signal that we'll be using the result

                  runOptimizer(result)
                })
              }
            } catch (e) {
              logger.error(e.stack || e.message)
            } finally {
              resolve()
              depsOptimizer.scanProcessing = undefined
            }
          })()
        })
      }
    }
    initState = 'initialized'
  }

  function startNextDiscoveredBatch() {
    newDepsDiscovered = false

    // Add the current depOptimizationProcessing to the queue, these
    // promises are going to be resolved once a rerun is committed
    depOptimizationProcessingQueue.push(depOptimizationProcessing)

    // Create a new promise for the next rerun, discovered missing
    // dependencies will be assigned this promise from this point
    depOptimizationProcessing = promiseWithResolvers()
  }

  function prepareKnownDeps() {
    const knownDeps: Record<string, OptimizedDepInfo> = {}
    // Clone optimized info objects, fileHash, browserHash may be changed for them
    const metadata = depsOptimizer.metadata!
    for (const dep of Object.keys(metadata.optimized)) {
      knownDeps[dep] = { ...metadata.optimized[dep] }
    }
    for (const dep of Object.keys(metadata.discovered)) {
      // Clone the discovered info discarding its processing promise
      const { processing, ...info } = metadata.discovered[dep]
      knownDeps[dep] = info
    }
    return knownDeps
  }

  async function runOptimizer(preRunResult?: DepOptimizationResult) {
    // a successful completion of the optimizeDeps rerun will end up
    // creating new bundled version of all current and discovered deps
    // in the cache dir and a new metadata info object assigned
    // to _metadata. A fullReload is only issued if the previous bundled
    // dependencies have changed.

    // if the rerun fails, _metadata remains untouched, current discovered
    // deps are cleaned, and a fullReload is issued

    // All deps, previous known and newly discovered are rebundled,
    // respect insertion order to keep the metadata file stable

    const isRerun = firstRunCalled
    firstRunCalled = true

    // Ensure that rerun is called sequentially
    enqueuedRerun = undefined

    // Ensure that a rerun will not be issued for current discovered deps
    if (debounceProcessingHandle) clearTimeout(debounceProcessingHandle)

    if (closed) {
      currentlyProcessing = false
      depOptimizationProcessing.resolve()
      resolveEnqueuedProcessingPromises()
      return
    }

    currentlyProcessing = true

    try {
      let processingResult: DepOptimizationResult
      if (preRunResult) {
        processingResult = preRunResult
      } else {
        const knownDeps = prepareKnownDeps()
        startNextDiscoveredBatch()

        optimizationResult = runOptimizeDeps(environment, knownDeps)
        processingResult = await optimizationResult.result
        optimizationResult = undefined
      }

      if (closed) {
        currentlyProcessing = false
        processingResult.cancel()
        resolveEnqueuedProcessingPromises()
        return
      }

      const newData = processingResult.metadata

      const needsInteropMismatch = findInteropMismatches(
        metadata.discovered,
        newData.optimized,
      )

      // After a re-optimization, if the internal bundled chunks change a full page reload
      // is required. If the files are stable, we can avoid the reload that is expensive
      // for large applications. Comparing their fileHash we can find out if it is safe to
      // keep the current browser state.
      const needsReload =
        needsInteropMismatch.length > 0 ||
        metadata.hash !== newData.hash ||
        Object.keys(metadata.optimized).some((dep) => {
          return (
            metadata.optimized[dep].fileHash !== newData.optimized[dep].fileHash
          )
        })

      const commitProcessing = async () => {
        await processingResult.commit()

        // While optimizeDeps is running, new missing deps may be discovered,
        // in which case they will keep being added to metadata.discovered
        for (const id in metadata.discovered) {
          if (!newData.optimized[id]) {
            addOptimizedDepInfo(newData, 'discovered', metadata.discovered[id])
          }
        }

        // If we don't reload the page, we need to keep browserHash stable
        if (!needsReload) {
          newData.browserHash = metadata.browserHash
          for (const dep in newData.chunks) {
            newData.chunks[dep].browserHash = metadata.browserHash
          }
          for (const dep in newData.optimized) {
            newData.optimized[dep].browserHash = (
              metadata.optimized[dep] || metadata.discovered[dep]
            ).browserHash
          }
        }

        // Commit hash and needsInterop changes to the discovered deps info
        // object. Allow for code to await for the discovered processing promise
        // and use the information in the same object
        for (const o in newData.optimized) {
          const discovered = metadata.discovered[o]
          if (discovered) {
            const optimized = newData.optimized[o]
            discovered.browserHash = optimized.browserHash
            discovered.fileHash = optimized.fileHash
            discovered.needsInterop = optimized.needsInterop
            discovered.processing = undefined
          }
        }

        if (isRerun) {
          newDepsToLog.push(
            ...Object.keys(newData.optimized).filter(
              (dep) => !metadata.optimized[dep],
            ),
          )
        }

        metadata = depsOptimizer.metadata = newData
        resolveEnqueuedProcessingPromises()
      }

      if (!needsReload) {
        await commitProcessing()

        if (!debug) {
          if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
          newDepsToLogHandle = setTimeout(() => {
            newDepsToLogHandle = undefined
            logNewlyDiscoveredDeps()
            if (warnAboutMissedDependencies) {
              logOptimizeDepsIncludeSuggestion('speed up cold start')
              warnAboutMissedDependencies = false
            }
          }, 2 * debounceMs)
        } else {
          debug(
            colors.green(
              !isRerun
                ? `dependencies optimized`
                : `optimized dependencies unchanged`,
            ),
          )
        }
      } else {
        if (newDepsDiscovered) {
          // There are newly discovered deps, and another rerun is about to be
          // executed. Avoid the current full reload discarding this rerun result
          // We don't resolve the processing promise, as they will be resolved
          // once a rerun is committed
          processingResult.cancel()

          debug?.(
            colors.green(
              `delaying reload as new dependencies have been found...`,
            ),
          )
        } else {
          await commitProcessing()

          if (!debug) {
            if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
            newDepsToLogHandle = undefined
            logNewlyDiscoveredDeps()
            if (warnAboutMissedDependencies) {
              logOptimizeDepsIncludeSuggestion(
                'avoid a full page reload during cold start',
              )
              warnAboutMissedDependencies = false
            }
          }

          logger.info(
            colors.green(`optimized dependencies changed. reloading`),
            {
              timestamp: true,
            },
          )
          if (needsInteropMismatch.length > 0) {
            logger.warn(
              `Mixed ESM and CJS detected in ${colors.yellow(
                needsInteropMismatch.join(', '),
              )}, add ${
                needsInteropMismatch.length === 1 ? 'it' : 'them'
              } to optimizeDeps.needsInterop to speed up cold start`,
              {
                timestamp: true,
              },
            )
          }

          fullReload()
        }
      }
    } catch (e) {
      logger.error(
        colors.red(`error while updating dependencies:\n${e.stack}`),
        { timestamp: true, error: e },
      )
      resolveEnqueuedProcessingPromises()

      // Reset missing deps, let the server rediscover the dependencies
      metadata.discovered = {}
    }

    currentlyProcessing = false
    // @ts-expect-error `enqueuedRerun` could exist because `debouncedProcessing` may run while awaited
    enqueuedRerun?.()
  }

  function fullReload() {
    // Cached transform results have stale imports (resolved to
    // old locations) so they need to be invalidated before the page is
    // reloaded.
    environment.moduleGraph.invalidateAll()

    environment.hot.send({
      type: 'full-reload',
      path: '*',
    })
  }

  function rerun() {
    // debounce time to wait for new missing deps finished, issue a new
    // optimization of deps (both old and newly found) once the previous
    // optimizeDeps processing is finished
    const deps = Object.keys(metadata.discovered)
    const depsString = depsLogString(deps)
    debug?.(colors.green(`new dependencies found: ${depsString}`))
    runOptimizer()
  }

  function getDiscoveredBrowserHash(
    hash: string,
    deps: Record<string, string>,
    missing: Record<string, string>,
  ) {
    return getHash(
      hash + JSON.stringify(deps) + JSON.stringify(missing) + sessionTimestamp,
    )
  }

  function registerMissingImport(
    id: string,
    resolved: string,
  ): OptimizedDepInfo {
    const optimized = metadata.optimized[id]
    if (optimized) {
      return optimized
    }
    const chunk = metadata.chunks[id]
    if (chunk) {
      return chunk
    }
    let missing = metadata.discovered[id]
    if (missing) {
      // We are already discover this dependency
      // It will be processed in the next rerun call
      return missing
    }

    missing = addMissingDep(id, resolved)

    // Until the first optimize run is called, avoid triggering processing
    // We'll wait until the user codebase is eagerly processed by Vite so
    // we can get a list of every missing dependency before giving to the
    // browser a dependency that may be outdated, thus avoiding full page reloads

    // A module can be transformed between `createServer()` and `server.listen()`,
    // which discovers a dep before `init()` runs. Starting a run here would race
    // with `init()` resetting the metadata and crash in `commitProcessing`.
    if (initState === 'initialized' && !waitingForCrawlEnd) {
      // Debounced rerun, let other missing dependencies be discovered before
      // the running next optimizeDeps
      debouncedProcessing()
    }

    // Return the path for the optimized bundle, this path is known before
    // esbuild is run to generate the pre-bundle
    return missing
  }

  function addMissingDep(id: string, resolved: string) {
    newDepsDiscovered = true

    return addOptimizedDepInfo(metadata, 'discovered', {
      id,
      file: getOptimizedDepPath(environment, id),
      src: resolved,
      // Adding a browserHash to this missing dependency that is unique to
      // the current state of known + missing deps. If its optimizeDeps run
      // doesn't alter the bundled files of previous known dependencies,
      // we don't need a full reload and this browserHash will be kept
      browserHash: getDiscoveredBrowserHash(
        metadata.hash,
        depsFromOptimizedDepInfo(metadata.optimized),
        depsFromOptimizedDepInfo(metadata.discovered),
      ),
      // loading of this pre-bundled dep needs to await for its processing
      // promise to be resolved
      processing: depOptimizationProcessing.promise,
      exportsData: extractExportsData(environment, resolved),
    })
  }

  function debouncedProcessing(timeout = debounceMs) {
    // Debounced rerun, let other missing dependencies be discovered before
    // the next optimizeDeps run
    enqueuedRerun = undefined
    if (debounceProcessingHandle) clearTimeout(debounceProcessingHandle)
    if (newDepsToLogHandle) clearTimeout(newDepsToLogHandle)
    newDepsToLogHandle = undefined
    debounceProcessingHandle = setTimeout(() => {
      debounceProcessingHandle = undefined
      enqueuedRerun = rerun
      if (!currentlyProcessing) {
        enqueuedRerun()
      }
    }, timeout)
  }

  // onCrawlEnd is called once when the server starts and all static
  // imports after the first request have been crawled (dynamic imports may also
  // be crawled if the browser requests them right away).
  async function onCrawlEnd() {
    // switch after this point to a simple debounce strategy
    waitingForCrawlEnd = false

    debug?.(colors.green(`static imports crawl ended`))
    if (closed) {
      return
    }

    // Await for the scan+optimize step running in the background
    // It normally should be over by the time crawling of user code ended
    await depsOptimizer.scanProcessing

    if (optimizationResult && !options.noDiscovery) {
      // In the holdUntilCrawlEnd strategy, we don't release the result of the
      // post-scanner optimize step to the browser until we reach this point
      // If there are new dependencies, we do another optimize run, if not, we
      // use the post-scanner optimize result
      // If holdUntilCrawlEnd is false and we reach here, it means that the
      // scan+optimize step finished after crawl end. We follow the same
      // process as in the holdUntilCrawlEnd in this case.
      const afterScanResult = optimizationResult.result
      optimizationResult = undefined // signal that we'll be using the result

      const result = await afterScanResult
      currentlyProcessing = false

      const crawlDeps = Object.keys(metadata.discovered)
      const scanDeps = Object.keys(result.metadata.optimized)

      if (scanDeps.length === 0 && crawlDeps.length === 0) {
        debug?.(
          colors.green(
            `no dependencies found by the scanner or crawling static imports`,
          ),
        )
        // We still commit the result so the scanner isn't run on the next cold start
        // for projects without dependencies
        startNextDiscoveredBatch()
        runOptimizer(result)
        return
      }

      const needsInteropMismatch = findInteropMismatches(
        metadata.discovered,
        result.metadata.optimized,
      )
      const scannerMissedDeps = crawlDeps.some((dep) => !scanDeps.includes(dep))
      const outdatedResult =
        needsInteropMismatch.length > 0 || scannerMissedDeps

      if (outdatedResult) {
        // Drop this scan result, and perform a new optimization to avoid a full reload
        result.cancel()

        // Add deps found by the scanner to the discovered deps while crawling
        for (const dep of scanDeps) {
          if (!crawlDeps.includes(dep)) {
            addMissingDep(dep, result.metadata.optimized[dep].src!)
          }
        }
        if (scannerMissedDeps) {
          debug?.(
            colors.yellow(
              `new dependencies were found while crawling that weren't detected by the scanner`,
            ),
          )
        }
        debug?.(colors.green(`re-running optimizer`))
        debouncedProcessing(0)
      } else {
        debug?.(
          colors.green(
            `using post-scan optimizer result, the scanner found every used dependency`,
          ),
        )
        startNextDiscoveredBatch()
        runOptimizer(result)
      }
    } else if (!holdUntilCrawlEnd) {
      // The post-scanner optimize result has been released to the browser
      // If new deps have been discovered, issue a regular rerun of the
      // optimizer. A full page reload may still be avoided if the new
      // optimize result is compatible in this case
      if (newDepsDiscovered) {
        debug?.(
          colors.green(
            `new dependencies were found while crawling static imports, re-running optimizer`,
          ),
        )
        warnAboutMissedDependencies = true
        debouncedProcessing(0)
      }
    } else {
      const crawlDeps = Object.keys(metadata.discovered)
      currentlyProcessing = false

      if (crawlDeps.length === 0) {
        debug?.(
          colors.green(
            `no dependencies found while crawling the static imports`,
          ),
        )
        firstRunCalled = true
      }

      // queue the first optimizer run, even without deps so the result is cached
      debouncedProcessing(0)
    }
  }

  return depsOptimizer
}

export function createExplicitDepsOptimizer(
  environment: DevEnvironment,
): DepsOptimizer {
  const depsOptimizer = {
    metadata: initDepsOptimizerMetadata(environment),
    isOptimizedDepFile: createIsOptimizedDepFile(environment),
    isOptimizedDepUrl: createIsOptimizedDepUrl(environment),
    getOptimizedDepId: (depInfo: OptimizedDepInfo) =>
      `${depInfo.file}?v=${depInfo.browserHash}`,

    registerMissingImport: () => {
      throw new Error(
        `Vite Internal Error: registerMissingImport is not supported in dev ${environment.name}`,
      )
    },
    init,
    // noop, there is no scanning during dev SSR
    // the optimizer blocks the server start
    run: () => {},

    close: async () => {},
    options: environment.config.optimizeDeps,
  }

  let inited = false
  async function init() {
    if (inited) return
    inited = true

    depsOptimizer.metadata = await optimizeExplicitEnvironmentDeps(environment)
  }

  return depsOptimizer
}

function findInteropMismatches(
  discovered: Record<string, OptimizedDepInfo>,
  optimized: Record<string, OptimizedDepInfo>,
) {
  const needsInteropMismatch = []
  for (const dep in discovered) {
    const discoveredDepInfo = discovered[dep]
    if (discoveredDepInfo.needsInterop === undefined) continue

    const depInfo = optimized[dep]
    if (!depInfo) continue

    if (depInfo.needsInterop !== discoveredDepInfo.needsInterop) {
      // This only happens when a discovered dependency has mixed ESM and CJS syntax
      // and it hasn't been manually added to optimizeDeps.needsInterop
      needsInteropMismatch.push(dep)
      debug?.(colors.cyan(`needsInterop mismatch detected for ${dep}`))
    }
  }
  return needsInteropMismatch
}


#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    // different JSON Pointers
    json::json_pointer ptr1("/foo");
    json::json_pointer ptr2("/foo/0");

    // call empty()
    std::cout << "first reference token of \"" << ptr1 << "\" is \"" << ptr1.front() << "\"\n"
              << "first reference token of \"" << ptr2 << "\" is \"" << ptr2.front() << "\"" << std::endl;
}


# NLOHMANN_JSON_SERIALIZE_ENUM

```cpp
#define NLOHMANN_JSON_SERIALIZE_ENUM(type, conversion...)
```

By default, enum values are serialized to JSON as integers. In some cases, this could result in undesired behavior. If
an enum is modified or re-ordered after data has been serialized to JSON, the later deserialized JSON data may be
undefined or a different enum value than was originally intended.

The `NLOHMANN_JSON_SERIALIZE_ENUM` allows to define a user-defined serialization for every enumerator.

## Parameters

`type` (in)
:   name of the enum to serialize/deserialize

`conversion` (in)
:   a pair of an enumerator and a JSON serialization; arbitrary pairs can be given as a comma-separated list

## Default definition

The macro adds two functions to the namespace which take care of the serialization and deserialization:

```cpp
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, const type& e);
template<typename BasicJsonType>
inline void from_json(const BasicJsonType& j, type& e);
```

## Notes

!!! info "Prerequisites"

    The macro must be used inside the namespace of the enum.

!!! important "Important notes"

    - When using [`get<ENUM_TYPE>()`](../basic_json/get.md), undefined JSON values will default to the first specified
      conversion. Select this default pair carefully. See example 1 below.
    - If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the
      list will be returned when converting to or from JSON. See example 2 below.

## Examples

??? example "Example 1: Basic usage"

    The example shows how `NLOHMANN_JSON_SERIALIZE_ENUM` can be used to serialize/deserialize both classical enums and
    C++11 enum classes:

    ```cpp hl_lines="16 17 18 19 20 21 22 29 30 31 32 33"
    --8<-- "examples/nlohmann_json_serialize_enum.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/nlohmann_json_serialize_enum.output"
    ```

??? example "Example 2: Multiple conversions for one enumerator"

    The example shows how to use multiple conversions for a single enumerator. In the example, `Color::red` will always
    be *serialized* to `"red"`, because the first occurring conversion. The second conversion, however, offers an
    alternative *deserialization* from `"rot"` to `Color::red`.

    ```cpp hl_lines="17"
    --8<-- "examples/nlohmann_json_serialize_enum_2.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/nlohmann_json_serialize_enum_2.output"
    ```

## See also

- [Specializing enum conversion](../../features/enum_conversion.md)
- [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](./nlohmann_json_serialize_enum_strict.md)
- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md)

## Version history

Added in version 3.4.0.


//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#pragma once

#include <cstdio>   // fopen, fclose, FILE
#include <memory> // unique_ptr
#include <test_data.hpp>
#include <doctest.h>

namespace utils
{

inline bool check_testsuite_downloaded()
{
    using FilePtr = std::unique_ptr<FILE, int(*)(FILE*)>;
    const FilePtr file(std::fopen(TEST_DATA_DIRECTORY "/README.md", "r"), std::fclose);
    return file != nullptr;
}

TEST_CASE("check test suite is downloaded")
{
    REQUIRE_MESSAGE(utils::check_testsuite_downloaded(), "Test data not found in '" TEST_DATA_DIRECTORY "'. Please execute target 'download_test_data' before running this test suite. See <https://github.com/nlohmann/json#execute-unit-tests> for more information.");
}

}  // namespace utils


#include <iostream>
#include <string_view>
#include <nlohmann/json.hpp>

using namespace std::string_view_literals;
using json = nlohmann::json;

int main()
{
    // create a JSON object with different entry types
    json j =
    {
        {"integer", 1},
        {"floating", 42.23},
        {"string", "hello world"},
        {"boolean", true},
        {"object", {{"key1", 1}, {"key2", 2}}},
        {"array", {1, 2, 3}}
    };

    // access existing values
    int v_integer = j.value("integer"sv, 0);
    double v_floating = j.value("floating"sv, 47.11);

    // access nonexisting values and rely on default value
    std::string v_string = j.value("nonexisting"sv, "oops");
    bool v_boolean = j.value("nonexisting"sv, false);

    // output values
    std::cout << std::boolalpha << v_integer << " " << v_floating
              << " " << v_string << " " << v_boolean << "\n";
}


# <small>nlohmann::json_pointer::</small>pop_back

```cpp
void pop_back();
```

Remove the last reference token.

## Exceptions

Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent.

## Complexity

Constant.

## Examples

??? example

    The example shows the usage of `pop_back`.

    ```cpp
    --8<-- "examples/json_pointer__pop_back.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/json_pointer__pop_back.output"
    ```

## Version history

Added in version 3.6.0.


# <small>nlohmann::basic_json::</small>count

```cpp
// (1)
size_type count(const typename object_t::key_type& key) const;

// (2)
template<typename KeyType>
size_type count(KeyType&& key) const;
```

1. Returns the number of elements with key `key`. If `ObjectType` is the default `std::map` type, the return value will
   always be `0` (`key` was not found) or `1` (`key` was found).
2. See 1. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
   `#!cpp typename object_comparator_t::is_transparent` denotes a type.

## Template parameters

`KeyType`
:   A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
    [`string_t`](string_t.md) using  [`object_comparator_t`](object_comparator_t.md).
    This can also be a string view (C++17).

## Parameters

`key` (in)
:   key value of the element to count.

## Return value

Number of elements with key `key`. If the JSON value is not an object, the return value will be `0`.

## Exception safety

Strong exception safety: if an exception occurs, the original value stays intact.

## Complexity

Logarithmic in the size of the JSON object.

## Notes

This method always returns `0` when executed on a JSON type that is not an object.

## Examples

??? example "Example: (1) count number of elements"

    The example shows how `count()` is used.

    ```cpp
    --8<-- "examples/count__object_t_key_type.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/count__object_t_key_type.output"
    ```

??? example "Example: (2) count number of elements using string_view"

    The example shows how `count()` is used.

    ```cpp
    --8<-- "examples/count__keytype.c++17.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/count__keytype.c++17.output"
    ```

## See also

- [find](find.md) find a value in an object
- [contains](contains.md) checks whether a key exists

## Version history

1. Added in version 3.11.0.
2. Added in version 1.0.0. Changed parameter `key` type to `KeyType&&` in version 3.11.0.


# Security Policy

To report a security issue, please disclose it at [security
advisory](https://github.com/fmtlib/fmt/security/advisories/new).

This project is maintained by a team of volunteers on a
reasonable-effort basis. As such, please give us at least 90 days to
work on a fix before public disclosure.


use std::env;
use std::error::Error;
use std::io;
use std::process;

use grep_regex::RegexMatcher;
use grep_searcher::Searcher;
use grep_searcher::sinks::UTF8;

fn main() {
    if let Err(err) = example() {
        eprintln!("{}", err);
        process::exit(1);
    }
}

fn example() -> Result<(), Box<dyn Error>> {
    let pattern = match env::args().nth(1) {
        Some(pattern) => pattern,
        None => {
            return Err(From::from(format!("Usage: search-stdin <pattern>")));
        }
    };
    let matcher = RegexMatcher::new(&pattern)?;
    Searcher::new().search_reader(
        &matcher,
        io::stdin(),
        UTF8(|lnum, line| {
            print!("{}:{}", lnum, line);
            Ok(true)
        }),
    )?;
    Ok(())
}


import path from 'node:path'
import { type Plugin, type ViteDevServer, createServer } from 'vite'
import { afterEach, describe, expect, test } from 'vitest'
import { isServe } from '~utils'

let server: ViteDevServer | undefined

afterEach(async () => {
  await server?.close()
  server = undefined
})

// In full bundle mode the build is driven by Rolldown's dev engine, which is the
// one that invokes plugins' `buildStart`/`buildEnd` hooks. Regression test for
// `buildEnd` being called twice because both `bundledDev.close()` and
// `pluginContainer.close()` fired it on server close.
describe.runIf(isServe)('full bundle mode build hooks', () => {
  test('buildStart and buildEnd are each called only once', async () => {
    let buildStartCount = 0
    let buildEndCount = 0
    const countPlugin: Plugin = {
      name: 'count-build-hooks',
      buildStart() {
        buildStartCount++
      },
      buildEnd() {
        buildEndCount++
      },
    }

    server = await createServer({
      root: path.resolve(import.meta.dirname, '..'),
      configFile: false,
      logLevel: 'silent',
      experimental: { bundledDev: true },
      plugins: [countPlugin],
    })
    await server.listen()

    // the initial full-bundle build runs on listen and fires buildStart + buildEnd once
    await expect.poll(() => buildEndCount, { timeout: 10000 }).toBe(1)
    expect(buildStartCount).toBe(1)

    await server.close()
    server = undefined

    // closing must not fire buildStart/buildEnd again
    expect(buildStartCount).toBe(1)
    expect(buildEndCount).toBe(1)
  })
})


import { value } from './child'

if (import.meta.hot) {
  import.meta.hot.accept(() => {
    import.meta.hot.invalidate()
  })
}

log('(invalidation circular deps) parent is executing')
setTimeout(() => {
  globalThis.__HMR__['.invalidation-circular-deps'] = value
})


# <small>nlohmann::json_sax::</small>null

```cpp
virtual bool null() = 0;
```

A null value was read.

## Return value

Whether parsing should proceed.

## Examples

??? example

    The example below shows how the SAX interface is used.

    ```cpp
    --8<-- "examples/sax_parse.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/sax_parse.output"
    ```

## Version history

- Added in version 3.2.0.


//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#pragma once

#include <cstdint> // size_t
#include <utility> // declval
#include <string> // string

#include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>

NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{

template<typename T>
using null_function_t = decltype(std::declval<T&>().null());

template<typename T>
using boolean_function_t =
    decltype(std::declval<T&>().boolean(std::declval<bool>()));

template<typename T, typename Integer>
using number_integer_function_t =
    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));

template<typename T, typename Unsigned>
using number_unsigned_function_t =
    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));

template<typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T&>().number_float(
                                    std::declval<Float>(), std::declval<const String&>()));

template<typename T, typename String>
using string_function_t =
    decltype(std::declval<T&>().string(std::declval<String&>()));

template<typename T, typename Binary>
using binary_function_t =
    decltype(std::declval<T&>().binary(std::declval<Binary&>()));

template<typename T>
using start_object_function_t =
    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));

template<typename T, typename String>
using key_function_t =
    decltype(std::declval<T&>().key(std::declval<String&>()));

template<typename T>
using end_object_function_t = decltype(std::declval<T&>().end_object());

template<typename T>
using start_array_function_t =
    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));

template<typename T>
using end_array_function_t = decltype(std::declval<T&>().end_array());

template<typename T, typename Exception>
using parse_error_function_t = decltype(std::declval<T&>().parse_error(
        std::declval<std::size_t>(), std::declval<const std::string&>(),
        std::declval<const Exception&>()));

template<typename SAX, typename BasicJsonType>
struct is_sax
{
  private:
    static_assert(is_basic_json<BasicJsonType>::value,
                  "BasicJsonType must be of type basic_json<...>");

    using number_integer_t = typename BasicJsonType::number_integer_t;
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
    using number_float_t = typename BasicJsonType::number_float_t;
    using string_t = typename BasicJsonType::string_t;
    using binary_t = typename BasicJsonType::binary_t;
    using exception_t = typename BasicJsonType::exception;

  public:
    static constexpr bool value =
        is_detected_exact<bool, null_function_t, SAX>::value &&
        is_detected_exact<bool, boolean_function_t, SAX>::value &&
        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
        is_detected_exact<bool, start_object_function_t, SAX>::value &&
        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
        is_detected_exact<bool, end_object_function_t, SAX>::value &&
        is_detected_exact<bool, start_array_function_t, SAX>::value &&
        is_detected_exact<bool, end_array_function_t, SAX>::value &&
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
};

template<typename SAX, typename BasicJsonType>
struct is_sax_static_asserts
{
  private:
    static_assert(is_basic_json<BasicJsonType>::value,
                  "BasicJsonType must be of type basic_json<...>");

    using number_integer_t = typename BasicJsonType::number_integer_t;
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
    using number_float_t = typename BasicJsonType::number_float_t;
    using string_t = typename BasicJsonType::string_t;
    using binary_t = typename BasicJsonType::binary_t;
    using exception_t = typename BasicJsonType::exception;

  public:
    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
                  "Missing/invalid function: bool null()");
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
                  "Missing/invalid function: bool boolean(bool)");
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
                  "Missing/invalid function: bool boolean(bool)");
    static_assert(
        is_detected_exact<bool, number_integer_function_t, SAX,
        number_integer_t>::value,
        "Missing/invalid function: bool number_integer(number_integer_t)");
    static_assert(
        is_detected_exact<bool, number_unsigned_function_t, SAX,
        number_unsigned_t>::value,
        "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
    static_assert(is_detected_exact<bool, number_float_function_t, SAX,
                  number_float_t, string_t>::value,
                  "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
    static_assert(
        is_detected_exact<bool, string_function_t, SAX, string_t>::value,
        "Missing/invalid function: bool string(string_t&)");
    static_assert(
        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
        "Missing/invalid function: bool binary(binary_t&)");
    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
                  "Missing/invalid function: bool start_object(std::size_t)");
    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
                  "Missing/invalid function: bool key(string_t&)");
    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
                  "Missing/invalid function: bool end_object()");
    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
                  "Missing/invalid function: bool start_array(std::size_t)");
    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
                  "Missing/invalid function: bool end_array()");
    static_assert(
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
        "Missing/invalid function: bool parse_error(std::size_t, const "
        "std::string&, const exception&)");
};

}  // namespace detail
NLOHMANN_JSON_NAMESPACE_END


# <small>nlohmann::basic_json::</small>operator=

```cpp
basic_json& operator=(basic_json other) noexcept (
    std::is_nothrow_move_constructible<value_t>::value &&
    std::is_nothrow_move_assignable<value_t>::value &&
    std::is_nothrow_move_constructible<json_value>::value &&
    std::is_nothrow_move_assignable<json_value>::value &&
    std::is_nothrow_move_assignable<json_base_class_t>::value
);
```

Copy assignment operator. Copies a JSON value via the "copy and swap" strategy: It is expressed in terms of the copy
constructor, destructor, and the `swap()` member function.

## Parameters

`other` (in)
:   value to copy from

## Exception safety

Strong guarantee: if an exception is thrown while copying `other`, there are no changes to `#!cpp *this`.

## Complexity

Linear.

## Examples

??? example

    The code below shows and example for the copy assignment. It creates a copy of value `a` which is then swapped with
    `b`. Finally, the copy of `a` (which is the null value after the swap) is destroyed.

    ```cpp
    --8<-- "examples/basic_json__copyassignment.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/basic_json__copyassignment.output"
    ```

## See also

- [basic_json](basic_json.md) create a JSON value
- [swap](swap.md) exchanges the contents of two JSON values

## Version history

- Added in version 1.0.0.


import { expect, test } from 'vitest'
import { port } from './serve'
import { findAssetFile, isBuild, listAssets, page } from '~utils'

const url = `http://localhost:${port}`

test('should work when inlined', async () => {
  await page.goto(`${url}/static-light`)
  expect(await page.textContent('.static-light')).toMatch('42')
})

test('should work when output', async () => {
  await page.goto(`${url}/static-heavy`)
  expect(await page.textContent('.static-heavy')).toMatch('24')
})

test.runIf(isBuild)('should not contain wasm file when inlined', async () => {
  const assets = await listAssets()
  const lightWasm = assets.find((f) => /^light-[^-]+\.wasm$/.test(f))
  expect(lightWasm).toBeUndefined()

  const staticLight = await findAssetFile(/^static-light-.+\.js$/)
  expect(staticLight).toContain('data:application/wasm;base64,')
})

test.runIf(isBuild)(
  'should contain and reference wasm file when output',
  async () => {
    const assets = await listAssets()
    const heavyWasm = assets.find((f) => /heavy-.+\.wasm$/.test(f))
    expect(heavyWasm).toBeDefined()

    const staticHeavy = await findAssetFile(/^static-heavy-.+\.js$/)
    expect(staticHeavy).toContain(heavyWasm)
    expect(staticHeavy).not.toContain('data:application/wasm;base64,')
  },
)

test('direct wasm import', async () => {
  await page.goto(`${url}/direct-add`)
  expect(await page.textContent('.direct-add')).toMatch('3')
})

test.runIf(isBuild)(
  'direct wasm import should contain and reference wasm file',
  async () => {
    const assets = listAssets()
    const addWasm = assets.find((f) => /add-.+\.wasm$/.test(f))
    expect(addWasm).toBeDefined()

    const directAdd = findAssetFile(/^direct-add-.+\.js$/)
    expect(directAdd).toContain(addWasm)
    expect(directAdd).not.toContain('data:application/wasm;base64,')
  },
)

test('direct wasm import with wasm imports', async () => {
  await page.goto(`${url}/direct-light`)
  expect(await page.textContent('.direct-light')).toMatch('42')
})


# <small>nlohmann::basic_json::</small>other_error

```cpp
class other_error : public exception;
```

This exception is thrown in case of errors that cannot be classified with the other exception types.

Exceptions have ids 5xx (see [list of other errors](../../home/exceptions.md#further-exceptions)).

```mermaid
classDiagram
  direction LR

    class std_exception ["std::exception"] {
        <<interface>>
    }

    class json_exception ["basic_json::exception"] {
        +const int id
        +const char* what() const
    }

    class json_parse_error ["basic_json::parse_error"] {
        +const std::size_t byte
    }

    class json_invalid_iterator ["basic_json::invalid_iterator"]
    class json_type_error ["basic_json::type_error"]
    class json_out_of_range ["basic_json::out_of_range"]
    class json_other_error ["basic_json::other_error"]

    std_exception <|-- json_exception
    json_exception <|-- json_parse_error
    json_exception <|-- json_invalid_iterator
    json_exception <|-- json_type_error
    json_exception <|-- json_out_of_range
    json_exception <|-- json_other_error

    style json_other_error fill:#CCCCFF
```

## Member functions

- **what** - returns explanatory string

## Member variables

- **id** - the id of the exception

## Examples

??? example

    The following code shows how a `other_error` exception can be caught.

    ```cpp
    --8<-- "examples/other_error.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/other_error.output"
    ```

## See also

- [`exception`](exception.md) for the base class of all exceptions thrown by the library
- [List of other errors](../../home/exceptions.md#further-exceptions)
- [`parse_error`](parse_error.md) for exceptions indicating a parse error
- [`invalid_iterator`](invalid_iterator.md) for exceptions indicating errors with iterators
- [`type_error`](type_error.md) for exceptions indicating executing a member function with a wrong type
- [`out_of_range`](out_of_range.md) for exceptions indicating access out of the defined range

## Version history

- Since version 3.0.0.


import { expect, test } from 'vitest'
import viteConfig from '../vite.config'
import { isBundledDev, page } from '~utils'

const defines = viteConfig.define
const envDefines = viteConfig.environments.client.define

test('string', async () => {
  expect(await page.textContent('.exp')).toBe(
    String(typeof eval(defines.__EXP__)),
  )
  expect(await page.textContent('.string')).toBe(JSON.parse(defines.__STRING__))
  expect(await page.textContent('.number')).toBe(String(defines.__NUMBER__))
  expect(await page.textContent('.boolean')).toBe(String(defines.__BOOLEAN__))
  expect(await page.textContent('.undefined')).toBe('')

  expect(await page.textContent('.object')).toBe(
    JSON.stringify(defines.__OBJ__, null, 2),
  )
  expect(await page.textContent('.process-node-env')).toBe(
    JSON.parse(defines['process.env.NODE_ENV']),
  )
  expect(await page.textContent('.process-env')).toBe(
    JSON.stringify(defines['process.env'], null, 2),
  )
  expect(await page.textContent('.env-var')).toBe(
    JSON.parse(defines['process.env.SOMEVAR']),
  )
  expect(await page.textContent('.process-as-property')).toBe(
    defines.__OBJ__.process.env.SOMEVAR,
  )
  expect(await page.textContent('.spread-object')).toBe(
    JSON.stringify({ SOMEVAR: defines['process.env.SOMEVAR'] }),
  )
  expect(await page.textContent('.spread-array')).toBe(
    JSON.stringify([...defines.__STRING__]),
  )
  expect(await page.textContent('.dollar-identifier')).toBe(
    String(defines.$DOLLAR),
  )
  expect(await page.textContent('.unicode-identifier')).toBe(
    String(defines.ÖUNICODE_LETTERɵ),
  )
  expect(await page.textContent('.no-identifier-substring')).toBe(String(true))
  expect(await page.textContent('.no-property')).toBe(String(true))
  // html wouldn't need to define replacement
  expect(await page.textContent('.exp-define')).toBe('__EXP__')
  expect(await page.textContent('.import-json')).toBe('__EXP__')
  expect(await page.textContent('.define-in-dep')).toBe(
    defines.__STRINGIFIED_OBJ__,
  )
  expect(await page.textContent('.define-in-environment')).toBe(
    envDefines.__DEFINE_IN_ENVIRONMENT__,
  )
})

test('ignores constants in string literals', async () => {
  expect(
    await page.textContent('.ignores-string-literals .process-env-dot'),
  ).toBe('process.env.')
  expect(
    await page.textContent('.ignores-string-literals .global-process-env-dot'),
  ).toBe('global.process.env.')
  expect(
    await page.textContent(
      '.ignores-string-literals .globalThis-process-env-dot',
    ),
  ).toBe('globalThis.process.env.')
  expect(
    await page.textContent('.ignores-string-literals .process-env-NODE_ENV'),
  ).toBe('process.env.NODE_ENV')
  expect(
    await page.textContent(
      '.ignores-string-literals .global-process-env-NODE_ENV',
    ),
  ).toBe('global.process.env.NODE_ENV')
  expect(
    await page.textContent(
      '.ignores-string-literals .globalThis-process-env-NODE_ENV',
    ),
  ).toBe('globalThis.process.env.NODE_ENV')
  expect(
    await page.textContent('.ignores-string-literals .import-meta-hot'),
  ).toBe('import' + '.meta.hot')
})

test('replaces constants in template literal expressions', async () => {
  expect(
    await page.textContent(
      '.replaces-constants-in-template-literal-expressions .process-env-dot',
    ),
  ).toBe(JSON.parse(defines['process.env.SOMEVAR']))
  expect(
    await page.textContent(
      '.replaces-constants-in-template-literal-expressions .process-env-NODE_ENV',
    ),
  ).toBe('dev')
})

test('replace constants on import.meta.env when it is a invalid json', async () => {
  expect(
    await page.textContent(
      '.replace-undefined-constants-on-import-meta-env .import-meta-env-UNDEFINED',
    ),
  ).toBe('undefined')
  expect(
    await page.textContent(
      '.replace-undefined-constants-on-import-meta-env .import-meta-env-SOME_IDENTIFIER',
    ),
  ).toBe('true')
})

test('optional values are detected by pattern properly', async () => {
  expect(await page.textContent('.optional-env')).toBe(
    JSON.parse(defines['process.env.SOMEVAR']),
  )
})

// bundled dev serves `?query` env imports without injecting __DEFINES__
test.skipIf(isBundledDev)(
  'env import with query parameters works correctly',
  async () => {
    expect(await page.textContent('.env-with-query')).toBe('success')
  },
)


#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
using namespace nlohmann::literals;

int main()
{
    // create some JSON values
    json j_object = R"( {"key": "value"} )"_json;
    json j_array = R"( [1, 2, 3] )"_json;

    // call contains
    std::cout << std::boolalpha <<
              "j_object contains 'key': " << j_object.contains("key") << '\n' <<
              "j_object contains 'another': " << j_object.contains("another") << '\n' <<
              "j_array contains 'key': " << j_array.contains("key") << std::endl;
}


import sqlite3
from datetime import datetime

import click
from flask import current_app
from flask import g

def get_db():
    """Connect to the application's configured database. The connection
    is unique for each request and will be reused if this is called
    again.
    """
    if "db" not in g:
        g.db = sqlite3.connect(
            current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row

    return g.db

def close_db(e=None):
    """If this request connected to the database, close the
    connection.
    """
    db = g.pop("db", None)

    if db is not None:
        db.close()

def init_db():
    """Clear existing data and create new tables."""
    db = get_db()

    with current_app.open_resource("schema.sql") as f:
        db.executescript(f.read().decode("utf8"))

@click.command("init-db")
def init_db_command():
    """Clear existing data and create new tables."""
    init_db()
    click.echo("Initialized the database.")

sqlite3.register_converter("timestamp", lambda v: datetime.fromisoformat(v.decode()))

def init_app(app):
    """Register database functions with the Flask app. This is called by
    the application factory.
    """
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)


# <small>nlohmann::</small>json_sax

```cpp
template<typename BasicJsonType>
struct json_sax;
```

This class describes the SAX interface used by [sax_parse](../basic_json/sax_parse.md). Each function is called in
different situations while the input is parsed. The boolean return value informs the parser whether to continue
processing the input.

## Template parameters

`BasicJsonType`
:   a specialization of [`basic_json`](../basic_json/index.md)

## Member types

- [**number_integer_t**](../basic_json/number_integer_t.md) - `BasicJsonType`'s type for numbers (integer)
- [**number_unsigned_t**](../basic_json/number_unsigned_t.md) - `BasicJsonType`'s type for numbers (unsigned)
- [**number_float_t**](../basic_json/number_float_t.md) - `BasicJsonType`'s type for numbers (floating-point)
- [**string_t**](../basic_json/string_t.md) - `BasicJsonType`'s type for strings
- [**binary_t**](../basic_json/binary_t.md) - `BasicJsonType`'s type for binary arrays

## Member functions

- [**binary**](binary.md) (_virtual_) - a binary value was read
- [**boolean**](boolean.md) (_virtual_) - a boolean value was read
- [**end_array**](end_array.md) (_virtual_) - the end of an array was read
- [**end_object**](end_object.md) (_virtual_) - the end of an object was read
- [**key**](key.md) (_virtual_) - an object key was read
- [**null**](null.md) (_virtual_) - a null value was read
- [**number_float**](number_float.md) (_virtual_) - a floating-point number was read
- [**number_integer**](number_integer.md) (_virtual_) - an integer number was read
- [**number_unsigned**](number_unsigned.md) (_virtual_) - an unsigned integer number was read
- [**parse_error**](parse_error.md) (_virtual_) - a parse error occurred
- [**start_array**](start_array.md) (_virtual_) - the beginning of an array was read
- [**start_object**](start_object.md) (_virtual_) - the beginning of an object was read
- [**string**](string.md) (_virtual_) - a string value was read

## Version history

- Added in version 3.2.0.
- Support for binary values (`binary_t`, `binary`) added in version 3.8.0.


// This file is depended by main.css via this.addWatchFile
export const color = 'red'

// Self-accept so that updating this file would not trigger a page reload.
// We only want to observe main.css updating itself.
if (import.meta.hot) {
  import.meta.hot.accept()
}


#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    // create several JSON values
    json array_1 = {1, 2, 3};
    json array_2 = {1, 2, 4};
    json object_1 = {{"A", "a"}, {"B", "b"}};
    json object_2 = {{"B", "b"}, {"A", "a"}};
    json number_1 = 17;
    json number_2 = 17.000000000000001L;
    json string_1 = "foo";
    json string_2 = "bar";

    // output values and comparisons
    std::cout << std::boolalpha;
    std::cout << array_1 << " != " << array_2 << " " << (array_1 != array_2) << '\n';
    std::cout << object_1 << " != " << object_2 << " " << (object_1 != object_2) << '\n';
    std::cout << number_1 << " != " << number_2 << " " << (number_1 != number_2) << '\n';
    std::cout << string_1 << " != " << string_2 << " " << (string_1 != string_2) << '\n';
}


# <small>nlohmann::basic_json::</small>number_integer_t

```cpp
using number_integer_t = NumberIntegerType;
```

The type used to store JSON numbers (integers).

[RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows:
> The representation of numbers is similar to that used in most programming languages. A number is represented in base
> 10 using decimal digits. It contains an integer component that may be prefixed with an optional minus sign, which may
> be followed by a fraction part and/or an exponent part. Leading zeros are not allowed. (...) Numeric values that
> cannot be represented in the grammar below (such as Infinity and NaN) are not permitted.

This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is
known whether the number is a signed integer, an unsigned integer, or a floating-point number. Therefore, three different
types, `number_integer_t`,  [`number_unsigned_t`](number_unsigned_t.md) and [`number_float_t`](number_float_t.md) are
used.

To store integer numbers in C++, a type is defined by the template parameter `NumberIntegerType` which chooses the type
to use.

## Notes

#### Default type

With the default values for `NumberIntegerType` (`std::int64_t`), the default value for `number_integer_t` is
`#!cpp std::int64_t`.

#### Default behavior

- The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an
  interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++
  integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error.

#### Limits

[RFC 8259](https://tools.ietf.org/html/rfc8259) specifies:
> An implementation may set limits on the range and precision of numbers.

When the default type is used, the maximal integer number that can be stored is `9223372036854775807` (INT64_MAX) and
the minimal integer number that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of
range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers
will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md).

[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are
> interoperable in the sense that implementations will agree exactly on their numeric values.

As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is
interoperable.

#### Storage

Integer number values are stored directly inside a `basic_json` type.

## Examples

??? example

    The following code shows that `number_integer_t` is by default, a typedef to `#!cpp std::int64_t`.

    ```cpp
    --8<-- "examples/number_integer_t.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/number_integer_t.output"
    ```

## Version history

- Added in version 1.0.0.


#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    // create JSON values
    json j_empty_init_list = json({});
    json j_object = { {"one", 1}, {"two", 2} };
    json j_array = {1, 2, 3, 4};
    json j_nested_object = { {"one", {1}}, {"two", {1, 2}} };
    json j_nested_array = { {{1}, "one"}, {{1, 2}, "two"} };

    // serialize the JSON value
    std::cout << j_empty_init_list << '\n';
    std::cout << j_object << '\n';
    std::cout << j_array << '\n';
    std::cout << j_nested_object << '\n';
    std::cout << j_nested_array << '\n';
}


let base = `/${self.location.pathname.split('/')[1]}`
if (base.endsWith('.js') || base === `/worker-entries`) base = '' // for dev

importScripts(`${base}/classic.js`)

self.onconnect = (event) => {
  const port = event.ports[0]
  port.postMessage(self.constant)
}

// for sourcemap
console.log('classic-shared-worker.js')


from datetime import datetime
from datetime import timezone
from uuid import uuid4

import pytest
from markupsafe import Markup

from flask.json.tag import JSONTag
from flask.json.tag import TaggedJSONSerializer

@pytest.mark.parametrize(
    "data",
    (
        {" t": (1, 2, 3)},
        {" t__": b"a"},
        {" di": " di"},
        {"x": (1, 2, 3), "y": 4},
        (1, 2, 3),
        [(1, 2, 3)],
        b"\xff",
        Markup("<html>"),
        uuid4(),
        datetime.now(tz=timezone.utc).replace(microsecond=0),
    ),
)
def test_dump_load_unchanged(data):
    s = TaggedJSONSerializer()
    assert s.loads(s.dumps(data)) == data

def test_duplicate_tag():
    class TagDict(JSONTag):
        key = " d"

    s = TaggedJSONSerializer()
    pytest.raises(KeyError, s.register, TagDict)
    s.register(TagDict, force=True, index=0)
    assert isinstance(s.tags[" d"], TagDict)
    assert isinstance(s.order[0], TagDict)

def test_custom_tag():
    class Foo:  # noqa: B903, for Python2 compatibility
        def __init__(self, data):
            self.data = data

    class TagFoo(JSONTag):
        __slots__ = ()
        key = " f"

        def check(self, value):
            return isinstance(value, Foo)

        def to_json(self, value):
            return self.serializer.tag(value.data)

        def to_python(self, value):
            return Foo(value)

    s = TaggedJSONSerializer()
    s.register(TagFoo)
    assert s.loads(s.dumps(Foo("bar"))).data == "bar"

def test_tag_interface():
    t = JSONTag(None)
    pytest.raises(NotImplementedError, t.check, None)
    pytest.raises(NotImplementedError, t.to_json, None)
    pytest.raises(NotImplementedError, t.to_python, None)

def test_tag_order():
    class Tag1(JSONTag):
        key = " 1"

    class Tag2(JSONTag):
        key = " 2"

    s = TaggedJSONSerializer()

    s.register(Tag1, index=-1)
    assert isinstance(s.order[-2], Tag1)

    s.register(Tag2, index=None)
    assert isinstance(s.order[-1], Tag2)


import path from 'node:path'
import readFileContent from '@vitejs/test-read-file-content'
import primitiveExport from '@vitejs/test-primitive-export'
import tsDefaultExport, {
  hello as tsNamedExport,
} from '@vitejs/test-ts-transpiled-exports'
import objectAssignedExports from '@vitejs/test-object-assigned-exports'
import forwardedExport from '@vitejs/test-forwarded-export'
import bcrypt from '@node-rs/bcrypt'
import definePropertiesExports from '@vitejs/test-define-properties-exports'
import definePropertyExports from '@vitejs/test-define-property-exports'
import onlyObjectAssignedExports from '@vitejs/test-only-object-assigned-exports'
import requireAbsolute from '@vitejs/test-require-absolute'
import noExternalCjs from '@vitejs/test-no-external-cjs'
import importBuiltinCjs from '@vitejs/test-import-builtin-cjs'
import { hello as linkedNoExternal } from '@vitejs/test-linked-no-external'
import virtualMessage from '@vitejs/test-pkg-exports/virtual'
import moduleConditionMessage from '@vitejs/test-module-condition'
import '@vitejs/test-css-lib'

// This import will set a 'Hello World!" message in the nested-external non-entry dependency
import '@vitejs/test-non-optimized-with-nested-external'

import * as optimizedWithNestedExternal from '@vitejs/test-optimized-with-nested-external'
import * as optimizedCjsWithNestedExternal from '@vitejs/test-optimized-cjs-with-nested-external'
import * as optimizeDepsNestedInclude from '@vitejs/test-nested-exclude'

import { setMessage } from '@vitejs/test-external-entry/entry'
setMessage('Hello World!')
import externalUsingExternalEntry from '@vitejs/test-external-using-external-entry'
import isomorphicModuleMessage from 'virtual:isomorphic-module'

export async function render(url, rootDir) {
  let html = ''

  const encryptedMsg = await bcrypt.hash('Secret Message!', 10)
  html += `\n<p class="encrypted-msg">encrypted message: ${encryptedMsg}</p>`

  const fileContent = await readFileContent(path.resolve(rootDir, 'message'))
  html += `\n<p class="file-message">msg read via fs/promises: ${fileContent}</p>`

  html += `\n<p class="primitive-export-message">message from primitive export: ${primitiveExport}</p>`

  // `.default()` as incorrectly packaged
  const tsDefaultExportMessage = tsDefaultExport.default()
  html += `\n<p class="ts-default-export-message">message from ts-default-export: ${tsDefaultExportMessage}</p>`

  const tsNamedExportMessage = tsNamedExport()
  html += `\n<p class="ts-named-export-message">message from ts-named-export: ${tsNamedExportMessage}</p>`

  const objectAssignedExportsMessage = objectAssignedExports.hello()
  html += `\n<p class="object-assigned-exports-message">message from object-assigned-exports: ${objectAssignedExportsMessage}</p>`

  const forwardedExportMessage = forwardedExport.hello()
  html += `\n<p class="forwarded-export-message">message from forwarded-export: ${forwardedExportMessage}</p>`

  const definePropertiesExportsMsg = definePropertiesExports.hello()
  html += `\n<p class="define-properties-exports-msg">message from define-properties-exports: ${definePropertiesExportsMsg}</p>`

  const definePropertyExportsMsg = definePropertyExports.hello()
  html += `\n<p class="define-property-exports-msg">message from define-property-exports: ${definePropertyExportsMsg}</p>`

  const onlyObjectAssignedExportsMessage = onlyObjectAssignedExports.hello()
  html += `\n<p class="only-object-assigned-exports-msg">message from only-object-assigned-exports: ${onlyObjectAssignedExportsMessage}</p>`

  const requireAbsoluteMessage = requireAbsolute.hello()
  html += `\n<p class="require-absolute-msg">message from require-absolute: ${requireAbsoluteMessage}</p>`

  const noExternalCjsMessage = noExternalCjs.hello()
  html += `\n<p class="no-external-cjs-msg">message from no-external-cjs: ${noExternalCjsMessage}</p>`

  const importBuiltinCjsMessage = importBuiltinCjs.hello()
  html += `\n<p class="import-builtin-cjs-msg">message from import-builtin-cjs: ${importBuiltinCjsMessage}</p>`

  const optimizedWithNestedExternalMessage = optimizedWithNestedExternal.hello()
  html += `\n<p class="optimized-with-nested-external">message from optimized-with-nested-external: ${optimizedWithNestedExternalMessage}</p>`

  const optimizedCjsWithNestedExternalMessage =
    optimizedCjsWithNestedExternal.hello()
  html += `\n<p class="optimized-cjs-with-nested-external">message from optimized-cjs-with-nested-external: ${optimizedCjsWithNestedExternalMessage}</p>`

  const externalUsingExternalEntryMessage = externalUsingExternalEntry.hello()
  html += `\n<p class="external-using-external-entry">message from external-using-external-entry: ${externalUsingExternalEntryMessage}</p>`

  const linkedNoExternalMessage = linkedNoExternal()
  html += `\n<p class="linked-no-external">linked-no-external msg: ${linkedNoExternalMessage}</p>`

  html += `\n<p class="dep-virtual">message from dep-virtual: ${virtualMessage}</p>`

  html += `\n<p class="css-lib">I should be blue</p>`

  html += `\n<p class="module-condition">${moduleConditionMessage}</p>`

  html += `\n<p class="isomorphic-module-server">${isomorphicModuleMessage}</p>`

  html += `\n<p class="isomorphic-module-browser"></p>`

  html += `\n<p class="optimize-deps-nested-include">message from optimize-deps-nested-include: ${optimizeDepsNestedInclude.nestedInclude}</p>`

  return html + '\n'
}