use std::collections::HashMap;

use {
    grep_matcher::{Captures, Match, Matcher},
    pcre2::bytes::{CaptureLocations, Regex, RegexBuilder},
};

use crate::error::Error;

/// A builder for configuring the compilation of a PCRE2 regex.
#[derive(Clone, Debug)]
pub struct RegexMatcherBuilder {
    builder: RegexBuilder,
    case_smart: bool,
    word: bool,
    fixed_strings: bool,
    whole_line: bool,
}

impl RegexMatcherBuilder {
    /// Create a new matcher builder with a default configuration.
    pub fn new() -> RegexMatcherBuilder {
        RegexMatcherBuilder {
            builder: RegexBuilder::new(),
            case_smart: false,
            word: false,
            fixed_strings: false,
            whole_line: false,
        }
    }

    /// Compile the given pattern into a PCRE matcher using the current
    /// configuration.
    ///
    /// If there was a problem compiling the pattern, then an error is
    /// returned.
    pub fn build(&self, pattern: &str) -> Result<RegexMatcher, Error> {
        self.build_many(&[pattern])
    }

    /// Compile all of the given patterns into a single regex that matches when
    /// at least one of the patterns matches.
    ///
    /// If there was a problem building the regex, then an error is returned.
    pub fn build_many<P: AsRef<str>>(
        &self,
        patterns: &[P],
    ) -> Result<RegexMatcher, Error> {
        let mut builder = self.builder.clone();
        let mut pats = Vec::with_capacity(patterns.len());
        for p in patterns.iter() {
            pats.push(if self.fixed_strings {
                format!("(?:{})", pcre2::escape(p.as_ref()))
            } else {
                format!("(?:{})", p.as_ref())
            });
        }
        let mut singlepat = if patterns.is_empty() {
            // A way to spell a pattern that can never match anything.
            r"[^\S\s]".to_string()
        } else {
            pats.join("|")
        };
        if self.case_smart && !has_uppercase_literal(&singlepat) {
            builder.caseless(true);
        }
        if self.whole_line {
            singlepat = format!(r"(?m:^)(?:{})(?m:$)", singlepat);
        } else if self.word {
            // We make this option exclusive with whole_line because when
            // whole_line is enabled, all matches necessary fall on word
            // boundaries. So this extra goop is strictly redundant.
            singlepat = format!(r"(?<!\w)(?:{})(?!\w)", singlepat);
        }
        log::trace!("final regex: {:?}", singlepat);
        builder.build(&singlepat).map_err(Error::regex).map(|regex| {
            let mut names = HashMap::new();
            for (i, name) in regex.capture_names().iter().enumerate() {
                if let Some(ref name) = *name {
                    names.insert(name.to_string(), i);
                }
            }
            RegexMatcher { regex, names }
        })
    }

    /// Enables case insensitive matching.
    ///
    /// If the `utf` option is also set, then Unicode case folding is used
    /// to determine case insensitivity. When the `utf` option is not set,
    /// then only standard ASCII case insensitivity is considered.
    ///
    /// This option corresponds to the `i` flag.
    pub fn caseless(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.caseless(yes);
        self
    }

    /// Whether to enable "smart case" or not.
    ///
    /// When smart case is enabled, the builder will automatically enable
    /// case insensitive matching based on how the pattern is written. Namely,
    /// case insensitive mode is enabled when both of the following things
    /// are believed to be true:
    ///
    /// 1. The pattern contains at least one literal character. For example,
    ///    `a\w` contains a literal (`a`) but `\w` does not.
    /// 2. Of the literals in the pattern, none of them are considered to be
    ///    uppercase according to Unicode. For example, `foo\pL` has no
    ///    uppercase literals but `Foo\pL` does.
    ///
    /// Note that the implementation of this is not perfect. Namely, `\p{Ll}`
    /// will prevent case insensitive matching even though it is part of a meta
    /// sequence. This bug will probably never be fixed.
    pub fn case_smart(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.case_smart = yes;
        self
    }

    /// Enables "dot all" matching.
    ///
    /// When enabled, the `.` metacharacter in the pattern matches any
    /// character, include `\n`. When disabled (the default), `.` will match
    /// any character except for `\n`.
    ///
    /// This option corresponds to the `s` flag.
    pub fn dotall(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.dotall(yes);
        self
    }

    /// Enable "extended" mode in the pattern, where whitespace is ignored.
    ///
    /// This option corresponds to the `x` flag.
    pub fn extended(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.extended(yes);
        self
    }

    /// Enable multiline matching mode.
    ///
    /// When enabled, the `^` and `$` anchors will match both at the beginning
    /// and end of a subject string, in addition to matching at the start of
    /// a line and the end of a line. When disabled, the `^` and `$` anchors
    /// will only match at the beginning and end of a subject string.
    ///
    /// This option corresponds to the `m` flag.
    pub fn multi_line(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.multi_line(yes);
        self
    }

    /// Enable matching of CRLF as a line terminator.
    ///
    /// When enabled, anchors such as `^` and `$` will match any of the
    /// following as a line terminator: `\r`, `\n` or `\r\n`.
    ///
    /// This is disabled by default, in which case, only `\n` is recognized as
    /// a line terminator.
    pub fn crlf(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.crlf(yes);
        self
    }

    /// Require that all matches occur on word boundaries.
    ///
    /// Enabling this option is subtly different than putting `\b` assertions
    /// on both sides of your pattern. In particular, a `\b` assertion requires
    /// that one side of it match a word character while the other match a
    /// non-word character. This option, in contrast, merely requires that
    /// one side match a non-word character.
    ///
    /// For example, `\b-2\b` will not match `foo -2 bar` since `-` is not a
    /// word character. However, `-2` with this `word` option enabled will
    /// match the `-2` in `foo -2 bar`.
    pub fn word(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.word = yes;
        self
    }

    /// Whether the patterns should be treated as literal strings or not. When
    /// this is active, all characters, including ones that would normally be
    /// special regex meta characters, are matched literally.
    pub fn fixed_strings(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.fixed_strings = yes;
        self
    }

    /// Whether each pattern should match the entire line or not. This is
    /// equivalent to surrounding the pattern with `(?m:^)` and `(?m:$)`.
    pub fn whole_line(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.whole_line = yes;
        self
    }

    /// Enable Unicode matching mode.
    ///
    /// When enabled, the following patterns become Unicode aware: `\b`, `\B`,
    /// `\d`, `\D`, `\s`, `\S`, `\w`, `\W`.
    ///
    /// When set, this implies UTF matching mode. It is not possible to enable
    /// Unicode matching mode without enabling UTF matching mode.
    ///
    /// This is disabled by default.
    pub fn ucp(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.ucp(yes);
        self
    }

    /// Enable UTF matching mode.
    ///
    /// When enabled, characters are treated as sequences of code units that
    /// make up a single codepoint instead of as single bytes. For example,
    /// this will cause `.` to match any single UTF-8 encoded codepoint, where
    /// as when this is disabled, `.` will any single byte (except for `\n` in
    /// both cases, unless "dot all" mode is enabled).
    ///
    /// Note that when UTF matching mode is enabled, every search performed
    /// will do a UTF-8 validation check, which can impact performance. The
    /// UTF-8 check can be disabled via the `disable_utf_check` option, but it
    /// is undefined behavior to enable UTF matching mode and search invalid
    /// UTF-8.
    ///
    /// This is disabled by default.
    pub fn utf(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.utf(yes);
        self
    }

    /// This is now deprecated and is a no-op.
    ///
    /// Previously, this option permitted disabling PCRE2's UTF-8 validity
    /// check, which could result in undefined behavior if the haystack was
    /// not valid UTF-8. But PCRE2 introduced a new option, `PCRE2_MATCH_INVALID_UTF`,
    /// in 10.34 which this crate always sets. When this option is enabled,
    /// PCRE2 claims to not have undefined behavior when the haystack is
    /// invalid UTF-8.
    ///
    /// Therefore, disabling the UTF-8 check is not something that is exposed
    /// by this crate.
    #[deprecated(
        since = "0.2.4",
        note = "now a no-op due to new PCRE2 features"
    )]
    pub fn disable_utf_check(&mut self) -> &mut RegexMatcherBuilder {
        self
    }

    /// Enable PCRE2's JIT and return an error if it's not available.
    ///
    /// This generally speeds up matching quite a bit. The downside is that it
    /// can increase the time it takes to compile a pattern.
    ///
    /// If the JIT isn't available or if JIT compilation returns an error, then
    /// regex compilation will fail with the corresponding error.
    ///
    /// This is disabled by default, and always overrides `jit_if_available`.
    pub fn jit(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.jit(yes);
        self
    }

    /// Enable PCRE2's JIT if it's available.
    ///
    /// This generally speeds up matching quite a bit. The downside is that it
    /// can increase the time it takes to compile a pattern.
    ///
    /// If the JIT isn't available or if JIT compilation returns an error,
    /// then a debug message with the error will be emitted and the regex will
    /// otherwise silently fall back to non-JIT matching.
    ///
    /// This is disabled by default, and always overrides `jit`.
    pub fn jit_if_available(&mut self, yes: bool) -> &mut RegexMatcherBuilder {
        self.builder.jit_if_available(yes);
        self
    }

    /// Set the maximum size of PCRE2's JIT stack, in bytes. If the JIT is
    /// not enabled, then this has no effect.
    ///
    /// When `None` is given, no custom JIT stack will be created, and instead,
    /// the default JIT stack is used. When the default is used, its maximum
    /// size is 32 KB.
    ///
    /// When this is set, then a new JIT stack will be created with the given
    /// maximum size as its limit.
    ///
    /// Increasing the stack size can be useful for larger regular expressions.
    ///
    /// By default, this is set to `None`.
    pub fn max_jit_stack_size(
        &mut self,
        bytes: Option<usize>,
    ) -> &mut RegexMatcherBuilder {
        self.builder.max_jit_stack_size(bytes);
        self
    }
}

/// An implementation of the `Matcher` trait using PCRE2.
#[derive(Clone, Debug)]
pub struct RegexMatcher {
    regex: Regex,
    names: HashMap<String, usize>,
}

impl RegexMatcher {
    /// Create a new matcher from the given pattern using the default
    /// configuration.
    pub fn new(pattern: &str) -> Result<RegexMatcher, Error> {
        RegexMatcherBuilder::new().build(pattern)
    }
}

impl Matcher for RegexMatcher {
    type Captures = RegexCaptures;
    type Error = Error;

    fn find_at(
        &self,
        haystack: &[u8],
        at: usize,
    ) -> Result<Option<Match>, Error> {
        Ok(self
            .regex
            .find_at(haystack, at)
            .map_err(Error::regex)?
            .map(|m| Match::new(m.start(), m.end())))
    }

    fn new_captures(&self) -> Result<RegexCaptures, Error> {
        Ok(RegexCaptures::new(self.regex.capture_locations()))
    }

    fn capture_count(&self) -> usize {
        self.regex.captures_len()
    }

    fn capture_index(&self, name: &str) -> Option<usize> {
        self.names.get(name).copied()
    }

    fn try_find_iter<F, E>(
        &self,
        haystack: &[u8],
        mut matched: F,
    ) -> Result<Result<(), E>, Error>
    where
        F: FnMut(Match) -> Result<bool, E>,
    {
        for result in self.regex.find_iter(haystack) {
            let m = result.map_err(Error::regex)?;
            match matched(Match::new(m.start(), m.end())) {
                Ok(true) => continue,
                Ok(false) => return Ok(Ok(())),
                Err(err) => return Ok(Err(err)),
            }
        }
        Ok(Ok(()))
    }

    fn captures_at(
        &self,
        haystack: &[u8],
        at: usize,
        caps: &mut RegexCaptures,
    ) -> Result<bool, Error> {
        Ok(self
            .regex
            .captures_read_at(&mut caps.locs, haystack, at)
            .map_err(Error::regex)?
            .is_some())
    }
}

/// Represents the match offsets of each capturing group in a match.
///
/// The first, or `0`th capture group, always corresponds to the entire match
/// and is guaranteed to be present when a match occurs. The next capture
/// group, at index `1`, corresponds to the first capturing group in the regex,
/// ordered by the position at which the left opening parenthesis occurs.
///
/// Note that not all capturing groups are guaranteed to be present in a match.
/// For example, in the regex, `(?P<foo>\w)|(?P<bar>\W)`, only one of `foo`
/// or `bar` will ever be set in any given match.
///
/// In order to access a capture group by name, you'll need to first find the
/// index of the group using the corresponding matcher's `capture_index`
/// method, and then use that index with `RegexCaptures::get`.
#[derive(Clone, Debug)]
pub struct RegexCaptures {
    /// Where the locations are stored.
    locs: CaptureLocations,
}

impl Captures for RegexCaptures {
    fn len(&self) -> usize {
        self.locs.len()
    }

    fn get(&self, i: usize) -> Option<Match> {
        self.locs.get(i).map(|(s, e)| Match::new(s, e))
    }
}

impl RegexCaptures {
    pub(crate) fn new(locs: CaptureLocations) -> RegexCaptures {
        RegexCaptures { locs }
    }
}

/// Determine whether the pattern contains an uppercase character which should
/// negate the effect of the smart-case option.
///
/// Ideally we would be able to check the AST in order to correctly handle
/// things like '\p{Ll}' and '\p{Lu}' (which should be treated as explicitly
/// cased), but PCRE doesn't expose enough details for that kind of analysis.
/// For now, our 'good enough' solution is to simply perform a semi-naïve
/// scan of the input pattern and ignore all characters following a '\'. The
/// This at least lets us support the most common cases, like 'foo\w' and
/// 'foo\S', in an intuitive manner.
fn has_uppercase_literal(pattern: &str) -> bool {
    let mut chars = pattern.chars();
    while let Some(c) = chars.next() {
        if c == '\\' {
            chars.next();
        } else if c.is_uppercase() {
            return true;
        }
    }
    false
}

#[cfg(test)]
mod tests {
    use grep_matcher::LineMatchKind;

    use super::*;

    // Test that enabling word matches does the right thing and demonstrate
    // the difference between it and surrounding the regex in `\b`.
    #[test]
    fn word() {
        let matcher =
            RegexMatcherBuilder::new().word(true).build(r"-2").unwrap();
        assert!(matcher.is_match(b"abc -2 foo").unwrap());

        let matcher =
            RegexMatcherBuilder::new().word(false).build(r"\b-2\b").unwrap();
        assert!(!matcher.is_match(b"abc -2 foo").unwrap());
    }

    // Test that enabling CRLF permits `$` to match at the end of a line.
    #[test]
    fn line_terminator_crlf() {
        // Test normal use of `$` with a `\n` line terminator.
        let matcher = RegexMatcherBuilder::new()
            .multi_line(true)
            .build(r"abc$")
            .unwrap();
        assert!(matcher.is_match(b"abc\n").unwrap());

        // Test that `$` doesn't match at `\r\n` boundary normally.
        let matcher = RegexMatcherBuilder::new()
            .multi_line(true)
            .build(r"abc$")
            .unwrap();
        assert!(!matcher.is_match(b"abc\r\n").unwrap());

        // Now check the CRLF handling.
        let matcher = RegexMatcherBuilder::new()
            .multi_line(true)
            .crlf(true)
            .build(r"abc$")
            .unwrap();
        assert!(matcher.is_match(b"abc\r\n").unwrap());
    }

    // Test that smart case works.
    #[test]
    fn case_smart() {
        let matcher =
            RegexMatcherBuilder::new().case_smart(true).build(r"abc").unwrap();
        assert!(matcher.is_match(b"ABC").unwrap());

        let matcher =
            RegexMatcherBuilder::new().case_smart(true).build(r"aBc").unwrap();
        assert!(!matcher.is_match(b"ABC").unwrap());
    }

    // Test that finding candidate lines works as expected.
    #[test]
    fn candidate_lines() {
        fn is_confirmed(m: LineMatchKind) -> bool {
            match m {
                LineMatchKind::Confirmed(_) => true,
                _ => false,
            }
        }

        let matcher = RegexMatcherBuilder::new().build(r"\wfoo\s").unwrap();
        let m = matcher.find_candidate_line(b"afoo ").unwrap().unwrap();
        assert!(is_confirmed(m));
    }
}


export { a, b } from './source'

if (import.meta.hot) {
  // import.meta.hot.accept('./source', (m) => {
  //   console.log(`accept-named reexport:${m.a},${m.b}`)
  // })
  import.meta.hot.acceptExports('a', (m) => {
    console.log(`accept-named reexport:${m.a},${m.b}`)
  })
}


<button id="dynamic-css-button">dynamic css</button>

## worker message:


import fs from 'node:fs/promises'
import path from 'node:path'
import { defineConfig } from 'vite'

const npmDirectServeConfig = {
  '/vue@3.4.38.js': 'vue34/dist/vue.runtime.esm-browser.js',
  '/slash@5.js': 'slash5/index.js',
}
/** @type {import('vite').Connect.NextHandleFunction} */
const serveNpmCodeDirectlyMiddleware = async (req, res, next) => {
  for (const [url, file] of Object.entries(npmDirectServeConfig)) {
    if (req.originalUrl === url) {
      const code = await fs.readFile(
        new URL(`./node_modules/${file}`, import.meta.url),
      )
      res.setHeader('Content-Type', 'text/javascript')
      res.end(code)
      return
    }
  }
  next()
}

export default defineConfig({
  optimizeDeps: {
    include: ['dep-that-imports', 'dep-that-requires'],
    exclude: ['vue', 'slash5'],
  },
  build: {
    minify: false,
    rolldownOptions: {
      external: ['vue', 'slash3', 'slash5'],
      transform: {
        inject: {
          require: path.resolve(import.meta.dirname, 'src/require-polyfill.js'),
        },
      },
    },
    commonjsOptions: {
      esmExternals: ['vue', 'slash5'],
      dynamicRequireTargets: ['test-no-op-fdir-glob'],
    },
  },
  plugins: [
    {
      name: 'serve-npm-code-directly',
      configureServer({ middlewares }) {
        middlewares.use(serveNpmCodeDirectlyMiddleware)
      },
      configurePreviewServer({ middlewares }) {
        middlewares.use(serveNpmCodeDirectlyMiddleware)
      },
    },
  ],
})


# License

<img align="right" src="https://149753425.v2.pressablecdn.com/wp-content/uploads/2009/06/OSIApproved_100X125.png">

The class is licensed under the [MIT License](https://opensource.org/licenses/MIT):

Copyright © 2013-2026 [Niels Lohmann](https://nlohmann.me)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

* * *

The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>

The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)

The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).


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

```cpp
virtual bool start_object(std::size_t elements) = 0;
```

The beginning of an object was read.

## Parameters

`elements` (in)
:   number of object elements, or `#!cpp std::numeric_limits<std::size_t>::max()` if unknown

## Return value

Whether parsing should proceed.

## Notes

Binary formats may report the number of elements.

## 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.


---
hide:
  - navigation
  - toc
---

# A modern formatting library

Safety

  Inspired by Python's formatting facility, {fmt} provides a safe replacement
  for the printf family of functions. Errors in format strings,
  which are a common source of vulnerabilities in C, are reported at
  compile time. For example:

fmt::format("{:d}", "I am not a number");

  will give a compile-time error because d is not a valid
  format specifier for strings. APIs like
  fmt::format prevent buffer overflow errors via
  automatic memory management.

→ Learn more

Extensibility

  Formatting of most standard types, including all containers, dates,
  and times is supported out-of-the-box. For example:

fmt::print("{}", std::vector{1, 2, 3});

  prints the vector in a JSON-like format:

[1, 2, 3]

  You can make your own types formattable and even make compile-time
  checks work for them.

→ Learn more

Performance

  {fmt} can be anywhere from tens of percent to 20-30 times faster than
  iostreams and sprintf, especially for numeric formatting.

  The library minimizes dynamic memory allocations and can optionally
  compile format strings to optimal code.

Unicode support

  {fmt} provides portable Unicode support on major operating systems
  with UTF-8 and char strings. For example:

fmt::print("Слава Україні!");

  will be printed correctly on Linux, macOS, and even Windows console,
  irrespective of the codepages.

  The default is locale-independent, but you can opt into localized
  formatting and {fmt} makes it work with Unicode, addressing issues in the
  standard library.

Fast compilation

  The library makes extensive use of type erasure to achieve fast
  compilation. fmt/base.h provides a subset of the API with
  minimal include dependencies and enough functionality to replace
  all uses of *printf.

  Code using {fmt} is usually several times faster to compile than the
  equivalent iostreams code, and while printf compiles faster
  still, the gap is narrowing.

→ Learn more

Small binary footprint

  Type erasure is also used to prevent template bloat, resulting in compact
  per-call binary code. For example, a call to fmt::print with
  a single argument is just a few
  instructions, comparable to printf despite adding
  runtime safety, and much smaller than the equivalent iostreams code.

  The library itself has small binary footprint and some components such as
  floating-point formatting can be disabled to make it even smaller for
  resource-constrained devices.

Portability

  {fmt} has a small self-contained codebase with the core consisting of
  just three headers and no external dependencies.

  The library is highly portable and requires only a minimal subset of
  C++11 features which are available in GCC 4.9, Clang 3.6, MSVC 19.10
  (2017) and later. Newer compiler and standard library features are used
  if available, and enable additional functionality.

  Where possible, the output of formatting functions is consistent across
  platforms.

Open source

  {fmt} is in the top hundred open-source C++ libraries on GitHub and has
  hundreds of
  all-time contributors.

  The library is distributed under a permissive MIT
  license and is
  relied upon by many open-source projects, including Blender, PyTorch,
  Apple's FoundationDB, Windows Terminal, MongoDB, and others.


//     __ _____ _____ _____
//  __|  |   __|     |   | |  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

#include "doctest_compatibility.h"

#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using nlohmann::json;

namespace
{
// special test case to check if memory is leaked if constructor throws
template<class T>
struct bad_allocator : std::allocator<T>
{
    using std::allocator<T>::allocator;

    bad_allocator() = default;
    template<class U> bad_allocator(const bad_allocator<U>& /*unused*/) { }

    template<class... Args>
    [[noreturn]] void construct(T* /*unused*/, Args&& ... /*unused*/) // NOLINT(cppcoreguidelines-missing-std-forward)
    {
        throw std::bad_alloc();
    }

    template <class U>
    struct rebind
    {
        using other = bad_allocator<U>;
    };
};
} // namespace

TEST_CASE("bad_alloc")
{
    SECTION("bad_alloc")
    {
        // create JSON type using the throwing allocator
        using bad_json = nlohmann::basic_json<std::map,
              std::vector,
              std::string,
              bool,
              std::int64_t,
              std::uint64_t,
              double,
              bad_allocator>;

        // creating an object should throw
        CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
    }
}

namespace
{
bool next_construct_fails = false;
bool next_destroy_fails = false;
bool next_deallocate_fails = false;

template<class T>
struct my_allocator : std::allocator<T>
{
    using std::allocator<T>::allocator;

    template<class... Args>
    void construct(T* p, Args&& ... args)
    {
        if (next_construct_fails)
        {
            next_construct_fails = false;
            throw std::bad_alloc();
        }

        ::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
    }

    void deallocate(T* p, std::size_t n)
    {
        if (next_deallocate_fails)
        {
            next_deallocate_fails = false;
            throw std::bad_alloc();
        }

        std::allocator<T>::deallocate(p, n);
    }

    void destroy(T* p)
    {
        if (next_destroy_fails)
        {
            next_destroy_fails = false;
            throw std::bad_alloc();
        }

        static_cast<void>(p); // fix MSVC's C4100 warning
        p->~T();
    }

    template <class U>
    struct rebind
    {
        using other = my_allocator<U>;
    };
};

// allows deletion of raw pointer, usually hold by json_value
template<class T>
void my_allocator_clean_up(T* p)
{
    assert(p != nullptr);
    my_allocator<T> alloc;
    alloc.destroy(p);
    alloc.deallocate(p, 1);
}
} // namespace

TEST_CASE("controlled bad_alloc")
{
    // create JSON type using the throwing allocator
    using my_json = nlohmann::basic_json<std::map,
          std::vector,
          std::string,
          bool,
          std::int64_t,
          std::uint64_t,
          double,
          my_allocator>;

    SECTION("class json_value")
    {
        SECTION("json_value(value_t)")
        {
            SECTION("object")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::object;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).object));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("array")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::array;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).array));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
            SECTION("string")
            {
                next_construct_fails = false;
                auto t = my_json::value_t::string;
                CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(t).string));
                next_construct_fails = true;
                CHECK_THROWS_AS(my_json::json_value(t), std::bad_alloc&);
                next_construct_fails = false;
            }
        }

        SECTION("json_value(const string_t&)")
        {
            next_construct_fails = false;
            const my_json::string_t v("foo");
            CHECK_NOTHROW(my_allocator_clean_up(my_json::json_value(v).string));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json::json_value(v), std::bad_alloc&);
            next_construct_fails = false;
        }
    }

    SECTION("class basic_json")
    {
        SECTION("basic_json(const CompatibleObjectType&)")
        {
            next_construct_fails = false;
            const std::map<std::string, std::string> v {{"foo", "bar"}};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const CompatibleArrayType&)")
        {
            next_construct_fails = false;
            const std::vector<std::string> v {"foo", "bar", "baz"};
            CHECK_NOTHROW(my_json(v));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            CHECK_NOTHROW(my_json("foo"));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json("foo"), std::bad_alloc&);
            next_construct_fails = false;
        }

        SECTION("basic_json(const typename string_t::value_type*)")
        {
            next_construct_fails = false;
            const std::string s("foo");
            CHECK_NOTHROW(my_json(s));
            next_construct_fails = true;
            CHECK_THROWS_AS(my_json(s), std::bad_alloc&);
            next_construct_fails = false;
        }
    }
}

namespace
{
template<class T>
struct allocator_no_forward : std::allocator<T>
{
    allocator_no_forward() = default;
    template <class U>
    allocator_no_forward(allocator_no_forward<U> /*unused*/) {}

    template <class U>
    struct rebind
    {
        using other =  allocator_no_forward<U>;
    };

    template <class... Args>
    void construct(T* p, const Args& ... args) noexcept(noexcept(::new (static_cast<void*>(p)) T(args...)))
    {
        // force copy even if move is available
        ::new (static_cast<void*>(p)) T(args...);
    }
};
} // namespace

TEST_CASE("bad my_allocator::construct")
{
    SECTION("my_allocator::construct doesn't forward")
    {
        using bad_alloc_json = nlohmann::basic_json<std::map,
              std::vector,
              std::string,
              bool,
              std::int64_t,
              std::uint64_t,
              double,
              allocator_no_forward>;

        bad_alloc_json j;
        j["test"] = bad_alloc_json::array_t();
        j["test"].push_back("should not leak");
    }
}


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

```cpp
enum class error_handler_t {
    strict,
    replace,
    ignore
};
```

This enumeration is used in the [`dump`](dump.md) function to choose how to treat decoding errors while serializing a
`basic_json` value. Three values are differentiated:

strict
:   throw a `type_error` exception in case of invalid UTF-8

replace
:   replace invalid UTF-8 sequences with U+FFFD (� REPLACEMENT CHARACTER)

ignore
:   ignore invalid UTF-8 sequences; all valid bytes are copied to the output unchanged, and invalid bytes are dropped

## Examples

??? example

    The example below shows how the different values of the `error_handler_t` influence the behavior of
    [`dump`](dump.md) when reading serializing an invalid UTF-8 sequence.

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

    Output:

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

## Version history

- Added in version 3.4.0.


import path from 'node:path'
import fs from 'node:fs'
import { transformWithEsbuild } from 'vite'
import { describe, expect, test } from 'vitest'
import { browserLogs, isBundledDev, isServe, serverLogs } from '~utils'

test.skipIf(isBundledDev)(
  'should respected each `tsconfig.json`s compilerOptions',
  () => {
    // main side effect should be called (because of `"verbatimModuleSyntax": true`)
    expect(browserLogs).toContain('main side effect')
    // main base setter should not be called (because of `"useDefineForClassFields": true"`)
    expect(browserLogs).not.toContain('data setter in MainBase')

    // nested side effect should not be called (because "verbatimModuleSyntax" is not set, defaults to false)
    expect(browserLogs).not.toContain('nested side effect')
    // nested base setter should be called (because of `"useDefineForClassFields": false"`)
    expect(browserLogs).toContain('data setter in NestedBase')

    // nested-with-extends side effect should be called (because "verbatimModuleSyntax" is extended from the main tsconfig.json, which is true)
    expect(browserLogs).toContain('nested-with-extends side effect')
    // nested-with-extends base setter should be called (because of `"useDefineForClassFields": false"`)
    expect(browserLogs).toContain('data setter in NestedWithExtendsBase')
  },
)

test.runIf(isServe)('scanner should not error with decorators', () => {
  expect(serverLogs).not.toStrictEqual(
    expect.arrayContaining([
      expect.stringContaining(
        'Parameter decorators only work when experimental decorators are enabled',
      ),
    ]),
  )
})

describe('transformWithEsbuild', () => {
  test('merge tsconfigRaw object', async () => {
    const main = path.resolve(import.meta.dirname, '../src/main.ts')
    const mainContent = fs.readFileSync(main, 'utf-8')
    const result = await transformWithEsbuild(mainContent, main, {
      tsconfigRaw: {
        compilerOptions: {
          useDefineForClassFields: false,
        },
      },
    })
    // "verbatimModuleSyntax": true from tsconfig.json should still work
    expect(result.code).toMatch(/import.*".\/not-used-type";/)
  })

  test('overwrite tsconfigRaw string', async () => {
    const main = path.resolve(import.meta.dirname, '../src/main.ts')
    const mainContent = fs.readFileSync(main, 'utf-8')
    const result = await transformWithEsbuild(mainContent, main, {
      tsconfigRaw: `{
        "compilerOptions": {
          "useDefineForClassFields": false
        }
      }`,
    })
    // "verbatimModuleSyntax": true from tsconfig.json should not be read
    // and defaults to false
    expect(result.code).not.toMatch(/import.*".\/not-used-type";/)
  })

  test('verbatimModuleSyntax', async () => {
    const main = path.resolve(import.meta.dirname, '../src/main.ts')
    const mainContent = fs.readFileSync(main, 'utf-8')
    const result = await transformWithEsbuild(mainContent, main, {
      tsconfigRaw: {
        compilerOptions: {
          useDefineForClassFields: false,
          verbatimModuleSyntax: false,
        },
      },
    })
    // "verbatimModuleSyntax": false from tsconfig.json should still work
    expect(result.code).not.toMatch(/import.*".\/not-used-type";/)
  })

  test('experimentalDecorators', async () => {
    const main = path.resolve(import.meta.dirname, '../src/decorator.ts')
    const mainContent = fs.readFileSync(main, 'utf-8')
    // Should not error when transpiling decorators as nearest tsconfig.json
    // has "experimentalDecorators": true
    const result = await transformWithEsbuild(mainContent, main, {
      target: 'es2020',
    })
    expect(result.code).toContain('__decorateClass')
  })
})


import { resolve } from 'node:path'
import { defineConfig } from 'vite'

const dirname = import.meta.dirname

export default defineConfig({
  input: {
    a0: resolve(dirname, 'entrypoints/a0.js'),
    a1: resolve(dirname, 'entrypoints/a1.js'),
    a2: resolve(dirname, 'entrypoints/a2.js'),
    a3: resolve(dirname, 'entrypoints/a3.js'),
    a4: resolve(dirname, 'entrypoints/a4.js'),
    a5: resolve(dirname, 'entrypoints/a5.js'),
    a6: resolve(dirname, 'entrypoints/a6.js'),
    a7: resolve(dirname, 'entrypoints/a7.js'),
    a8: resolve(dirname, 'entrypoints/a8.js'),
    a9: resolve(dirname, 'entrypoints/a9.js'),
    a10: resolve(dirname, 'entrypoints/a10.js'),
    a11: resolve(dirname, 'entrypoints/a11.js'),
    a12: resolve(dirname, 'entrypoints/a12.js'),
    a13: resolve(dirname, 'entrypoints/a13.js'),
    a14: resolve(dirname, 'entrypoints/a14.js'),
    a15: resolve(dirname, 'entrypoints/a15.js'),
    a16: resolve(dirname, 'entrypoints/a16.js'),
    a17: resolve(dirname, 'entrypoints/a17.js'),
    a18: resolve(dirname, 'entrypoints/a18.js'),
    a19: resolve(dirname, 'entrypoints/a19.js'),
    a20: resolve(dirname, 'entrypoints/a20.js'),
    a21: resolve(dirname, 'entrypoints/a21.js'),
    a22: resolve(dirname, 'entrypoints/a22.js'),
    a23: resolve(dirname, 'entrypoints/a23.js'),
    a24: resolve(dirname, 'entrypoints/a24.js'),
    index: resolve(dirname, './index.html'),
  },
  build: {
    outDir: './dist',
    emptyOutDir: true,
    rolldownOptions: {
      preserveEntrySignatures: 'strict',
    },
  },
})


import { resolve } from 'node:path'
import { describe, expect, test } from 'vitest'
import { searchForWorkspaceRoot } from '../searchRoot'

const dirname = import.meta.dirname

describe('searchForWorkspaceRoot', () => {
  test('lerna', () => {
    const resolved = searchForWorkspaceRoot(
      resolve(dirname, 'fixtures/lerna/nested'),
    )
    expect(resolved).toBe(resolve(dirname, 'fixtures/lerna'))
  })

  test('pnpm', () => {
    const resolved = searchForWorkspaceRoot(
      resolve(dirname, 'fixtures/pnpm/nested'),
    )
    expect(resolved).toBe(resolve(dirname, 'fixtures/pnpm'))
  })

  test('yarn', () => {
    const resolved = searchForWorkspaceRoot(
      resolve(dirname, 'fixtures/yarn/nested'),
    )
    expect(resolved).toBe(resolve(dirname, 'fixtures/yarn'))
  })

  test('yarn at root', () => {
    const resolved = searchForWorkspaceRoot(resolve(dirname, 'fixtures/yarn'))
    expect(resolved).toBe(resolve(dirname, 'fixtures/yarn'))
  })

  test('deno', () => {
    const resolved = searchForWorkspaceRoot(
      resolve(dirname, 'fixtures/deno/nested'),
    )
    expect(resolved).toBe(resolve(dirname, 'fixtures/deno'))
  })

  test('deno at root', () => {
    const resolved = searchForWorkspaceRoot(resolve(dirname, 'fixtures/deno'))
    expect(resolved).toBe(resolve(dirname, 'fixtures/deno'))
  })

  test('none', () => {
    const resolved = searchForWorkspaceRoot(
      resolve(dirname, 'fixtures/none/nested'),
    )
    // resolved to vite repo's root
    expect(resolved).toBe(resolve(dirname, '../../../../../..'))
  })
})


import type { HMRLogger } from '../shared/hmr'

const noop = (): void => {}

export const silentConsole: HMRLogger = {
  debug: noop,
  error: noop,
}

export const hmrLogger: HMRLogger = {
  debug: (...msg) => console.log('[vite]', ...msg),
  error: (error) => console.log('[vite]', error),
}


import fs from 'node:fs'
import path from 'node:path'
import colors from 'picocolors'
import type { PartialResolvedId } from 'rolldown'
import { viteResolvePlugin } from 'rolldown/experimental'
import { exports, imports } from 'resolve.exports'
import type { Plugin } from '../plugin'
import {
  CLIENT_ENTRY,
  DEP_VERSION_RE,
  DEV_PROD_CONDITION,
  ENV_ENTRY,
  FS_PREFIX,
  SPECIAL_QUERY_RE,
} from '../constants'
import {
  bareImportRE,
  createDebugger,
  deepImportRE,
  fsPathFromId,
  getNpmPackageName,
  injectQuery,
  isBuiltin,
  isDataUrl,
  isExternalUrl,
  isInNodeModules,
  isObject,
  isOptimizable,
  normalizePath,
  safeRealpathSync,
  tryStatSync,
} from '../utils'
import {
  isDepOptimizationDisabled,
  optimizedDepInfoFromFile,
  optimizedDepInfoFromId,
} from '../optimizer'
import type { DepsOptimizer } from '../optimizer'
import type { Environment } from '..'
import type { PackageCache, PackageData } from '../packages'
import { canExternalizeFile } from '../external'
import {
  findNearestMainPackageData,
  findNearestPackageData,
  loadPackageData,
  resolvePackageData,
} from '../packages'
import {
  cleanUrl,
  splitFileAndPostfix,
  withTrailingSlash,
} from '../../shared/utils'
import type { ResolvedConfig, ResolvedEnvironmentOptions } from '../config'

const normalizedClientEntry = normalizePath(CLIENT_ENTRY)
const normalizedEnvEntry = normalizePath(ENV_ENTRY)

const ERR_RESOLVE_PACKAGE_ENTRY_FAIL = 'ERR_RESOLVE_PACKAGE_ENTRY_FAIL'

// special id for paths marked with browser: false
// https://github.com/defunctzombie/package-browser-field-spec#ignore-a-module
export const browserExternalId = '__vite-browser-external'
// special id for packages that are optional peer deps
export const optionalPeerDepId = '__vite-optional-peer-dep'

const subpathImportsPrefix = '#'

const relativePrefixRE = /^\.\.?(?:[/\\]|$)/
const startsWithWordCharRE = /^\w/

const debug = createDebugger('vite:resolve-details', {
  onlyWhenFocused: true,
})

export interface EnvironmentResolveOptions {
  /**
   * @default ['browser', 'module', 'jsnext:main', 'jsnext']
   */
  mainFields?: string[]
  conditions?: string[]
  externalConditions?: string[]
  /**
   * @default ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']
   */
  extensions?: string[]
  dedupe?: string[]
  // TODO: better abstraction that works for the client environment too?
  /**
   * Prevent listed dependencies from being externalized and will get bundled in build.
   * Only works in server environments for now. Previously this was `ssr.noExternal`.
   * @experimental
   */
  noExternal?: string | RegExp | (string | RegExp)[] | true
  /**
   * Externalize the given dependencies and their transitive dependencies.
   * Only works in server environments for now. Previously this was `ssr.external`.
   * @experimental
   */
  external?: string[] | true
  /**
   * Array of strings or regular expressions that indicate what modules are builtin for the environment.
   */
  builtins?: (string | RegExp)[]
}

export interface ResolveOptions extends EnvironmentResolveOptions {
  /**
   * @default false
   */
  preserveSymlinks?: boolean
  /**
   * Enable tsconfig paths resolution
   *
   * @default false
   */
  tsconfigPaths?: boolean
}

interface ResolvePluginOptions {
  root: string
  isBuild: boolean
  isProduction: boolean
  packageCache?: PackageCache
  /**
   * src code mode also attempts the following:
   * - resolving /xxx as URLs
   * - resolving bare imports from optimized deps
   */
  asSrc?: boolean
  tryIndex?: boolean
  tryPrefix?: string
  preferRelative?: boolean
  isRequire?: boolean
  // True when resolving during the scan phase to discover dependencies
  scan?: boolean
  /**
   * @internal
   */
  skipMainField?: boolean

  /**
   * Optimize deps during dev, defaults to false // TODO: Review default
   * @internal
   */
  optimizeDeps?: boolean

  /**
   * Externalize using `resolve.external` and `resolve.noExternal` when running a build in
   * a server environment. Defaults to false (only for createResolver)
   * @internal
   */
  externalize?: boolean

  /**
   * Set by createResolver, we only care about the resolved id. moduleSideEffects
   * and other fields are discarded so we can avoid computing them.
   * @internal
   */
  idOnly?: boolean

  /**
   * Set by `nodeResolveWithVite`, disables optional peer dependency handling.
   * @internal
   */
  disableOptionalPeerDepHandling?: boolean

  /**
   * Enable when `legacy.inconsistentCjsInterop` is true. See that option for more details.
   */
  legacyInconsistentCjsInterop?: boolean
}

export interface InternalResolveOptions
  extends Required<ResolveOptions>, ResolvePluginOptions {}

// Defined ResolveOptions are used to overwrite the values for all environments
// It is used when creating custom resolvers (for CSS, scanning, etc)
export interface ResolvePluginOptionsWithOverrides
  extends ResolveOptions, ResolvePluginOptions {}

const perEnvironmentOrWorkerPlugin = (
  name: string,
  overrideEnvConfig: (ResolvedConfig & ResolvedEnvironmentOptions) | undefined,
  f: (
    env: {
      name: string
      config: ResolvedConfig & ResolvedEnvironmentOptions
    },
    getEnvironment: () => Environment,
  ) => Plugin,
): Plugin[] => {
  const envs: Record<string, Environment> = {}
  const getEnvironmentPlugin: Plugin = {
    name: `${name}:get-environment`,
    buildStart() {
      envs[this.environment.name] = this.environment
    },
    perEnvironmentStartEndDuringDev: true,
  }
  const createGetEnvironment = (name: string) => () => envs[name]

  if (overrideEnvConfig) {
    return [
      getEnvironmentPlugin,
      f(
        { name: 'client', config: overrideEnvConfig },
        createGetEnvironment('client'),
      ),
    ]
  }
  return [
    getEnvironmentPlugin,
    {
      name,
      applyToEnvironment(environment) {
        return f(environment, createGetEnvironment(environment.name))
      },
    },
  ]
}

export function oxcResolvePlugin(
  resolveOptions: ResolvePluginOptionsWithOverrides,
  overrideEnvConfig: (ResolvedConfig & ResolvedEnvironmentOptions) | undefined,
  isJsPluginContainer = false,
): Plugin[] {
  return [
    ...(resolveOptions.optimizeDeps && !resolveOptions.isBuild
      ? [optimizerResolvePlugin(resolveOptions)]
      : []),
    ...perEnvironmentOrWorkerPlugin(
      'vite:resolve-builtin',
      overrideEnvConfig,
      (partialEnv, getEnv) => {
        // The resolve plugin is used for createIdResolver and the depsOptimizer should be
        // disabled in that case, so deps optimization is opt-in when creating the plugin.
        const depsOptimizerEnabled =
          resolveOptions.optimizeDeps &&
          !resolveOptions.isBuild &&
          !partialEnv.config.isBundled &&
          !isDepOptimizationDisabled(partialEnv.config.optimizeDeps)
        const getDepsOptimizer = () => {
          const env = getEnv()
          if (env.mode !== 'dev')
            throw new Error('The environment mode should be dev')
          if (!env.depsOptimizer)
            throw new Error('The environment should have a depsOptimizer')
          return env.depsOptimizer
        }

        const options: InternalResolveOptions = {
          ...partialEnv.config.resolve,
          ...resolveOptions, // plugin options + resolve options overrides
        }
        const noExternal =
          Array.isArray(options.noExternal) || options.noExternal === true
            ? options.noExternal
            : [options.noExternal]

        const plugin = viteResolvePlugin({
          resolveOptions: {
            isBuild: options.isBuild,
            isProduction: options.isProduction,
            asSrc: options.asSrc ?? false,
            preferRelative: options.preferRelative ?? false,
            isRequire: options.isRequire,
            root: options.root,
            scan: options.scan ?? false,

            mainFields: options.skipMainField
              ? options.mainFields
              : options.mainFields.concat(['main']),
            conditions: options.conditions,
            externalConditions: options.externalConditions,
            extensions: options.extensions,
            tryIndex: options.tryIndex ?? true,
            tryPrefix: options.tryPrefix,
            preserveSymlinks: options.preserveSymlinks,
            tsconfigPaths: options.tsconfigPaths,
          },
          environmentConsumer: partialEnv.config.consumer,
          environmentName: partialEnv.name,
          builtins: partialEnv.config.resolve.builtins,
          external: options.external,
          noExternal: noExternal,
          dedupe: options.dedupe,
          disableCache:
            partialEnv.config.command === 'serve' &&
            // eslint-disable-next-line eqeqeq
            partialEnv.config.server.watch === null,
          legacyInconsistentCjsInterop: options.legacyInconsistentCjsInterop,
          finalizeBareSpecifier: !depsOptimizerEnabled
            ? undefined
            : (resolvedId, rawId, importer) => {
                const depsOptimizer = getDepsOptimizer()
                // if we reach here, it's a valid dep import that hasn't been optimized.
                const isJsType = isOptimizable(
                  resolvedId,
                  depsOptimizer.options,
                )
                const exclude = depsOptimizer?.options.exclude

                // check for deep import, e.g. "my-lib/foo"
                const deepMatch = deepImportRE.exec(rawId)
                // package name doesn't include postfixes
                // trim them to support importing package with queries (e.g. `import css from 'normalize.css?inline'`)
                const pkgId = deepMatch
                  ? deepMatch[1] || deepMatch[2]
                  : cleanUrl(rawId)

                const skipOptimization =
                  depsOptimizer.options.noDiscovery ||
                  !isJsType ||
                  (importer && isInNodeModules(importer)) ||
                  exclude?.includes(pkgId) ||
                  exclude?.includes(rawId) ||
                  SPECIAL_QUERY_RE.test(resolvedId)

                let newId = resolvedId
                if (skipOptimization) {
                  // excluded from optimization
                  // Inject a version query to npm deps so that the browser
                  // can cache it without re-validation, but only do so for known js types.
                  // otherwise we may introduce duplicated modules for externalized files
                  // from pre-bundled deps.
                  const versionHash = depsOptimizer!.metadata.browserHash
                  if (versionHash && isJsType) {
                    newId = injectQuery(newId, `v=${versionHash}`)
                  }
                } else {
                  // this is a missing import, queue optimize-deps re-run and
                  // get a resolved its optimized info
                  const optimizedInfo = depsOptimizer!.registerMissingImport(
                    rawId,
                    newId,
                  )
                  newId = depsOptimizer!.getOptimizedDepId(optimizedInfo)
                }
                return newId
              },
          finalizeOtherSpecifiers: !depsOptimizerEnabled
            ? undefined
            : (resolvedId, rawId) => {
                const depsOptimizer = getDepsOptimizer()
                const newResolvedId = ensureVersionQuery(
                  resolvedId,
                  rawId,
                  options,
                  depsOptimizer,
                )
                return newResolvedId === resolvedId ? undefined : newResolvedId
              },
          resolveSubpathImports(id, importer, isRequire, scan) {
            return resolveSubpathImports(id, importer, {
              ...options,
              isRequire: resolveOptions.isRequire ?? isRequire,
              scan,
            })
          },

          ...(partialEnv.config.command === 'serve' || isJsPluginContainer
            ? {
                async onWarn(msg) {
                  // use `partialEnv` instead of `getEnv()` because `buildStart` is
                  // not called for plugin container used by `createIdResolver`
                  partialEnv.config.logger.warn(`warning: ${msg}`, {
                    clear: true,
                    timestamp: true,
                  })
                },
              }
            : {}),
          ...(debug
            ? {
                async onDebug(message) {
                  debug(message)
                },
              }
            : {}),
        })
        ;(plugin as Plugin).perEnvironmentWatchChangeDuringDev = true
        return plugin
      },
    ),
  ]
}

function optimizerResolvePlugin(
  resolveOptions: ResolvePluginOptionsWithOverrides,
): Plugin {
  const { root, asSrc } = resolveOptions

  return {
    name: 'vite:resolve-dev',
    applyToEnvironment(environment) {
      return (
        !environment.config.isBundled &&
        !isDepOptimizationDisabled(environment.config.optimizeDeps)
      )
    },
    resolveId: {
      filter: {
        id: {
          exclude: [
            /^\0/,
            /^virtual:/,
            // When injected directly in html/client code
            /^\/virtual:/,
            /^__vite-/,
          ],
        },
      },
      async handler(id, importer, resolveOpts) {
        // The resolve plugin is used for createIdResolver and the depsOptimizer should be
        // disabled in that case, so deps optimization is opt-in when creating the plugin.
        const depsOptimizer =
          resolveOptions.optimizeDeps && this.environment.mode === 'dev'
            ? this.environment.depsOptimizer
            : undefined
        if (!depsOptimizer) {
          return
        }

        const options: InternalResolveOptions = {
          isRequire: resolveOpts.kind === 'require-call',
          ...this.environment.config.resolve,
          ...resolveOptions,
          scan: resolveOpts.scan ?? resolveOptions.scan,
        }
        options.preferRelative ||= importer?.endsWith('.html')

        // resolve pre-bundled deps requests, these could be resolved by
        // tryFileResolve or /fs/ resolution but these files may not yet
        // exists if we are in the middle of a deps re-processing
        if (asSrc && depsOptimizer.isOptimizedDepUrl(id)) {
          const optimizedPath = id.startsWith(FS_PREFIX)
            ? fsPathFromId(id)
            : normalizePath(path.resolve(root, id.slice(1)))
          return optimizedPath
        }

        if (!isDataUrl(id) && !isExternalUrl(id)) {
          if (
            id[0] === '.' ||
            (options.preferRelative && startsWithWordCharRE.test(id))
          ) {
            const basedir = importer ? path.dirname(importer) : root
            const fsPath = path.resolve(basedir, id)
            // handle browser field mapping for relative imports

            const normalizedFsPath = normalizePath(fsPath)

            if (depsOptimizer.isOptimizedDepFile(normalizedFsPath)) {
              // Optimized files could not yet exist in disk, resolve to the full path
              // Inject the current browserHash version if the path doesn't have one
              if (!DEP_VERSION_RE.test(normalizedFsPath)) {
                const browserHash = optimizedDepInfoFromFile(
                  depsOptimizer.metadata,
                  normalizedFsPath,
                )?.browserHash
                if (browserHash) {
                  return injectQuery(normalizedFsPath, `v=${browserHash}`)
                }
              }
              return normalizedFsPath
            }
          }

          // bare package imports, perform node resolve
          if (bareImportRE.test(id)) {
            let res: string | PartialResolvedId | undefined
            if (
              asSrc &&
              !options.scan &&
              (res = await tryOptimizedResolve(
                depsOptimizer,
                id,
                importer,
                options.preserveSymlinks,
                options.packageCache,
              ))
            ) {
              return res
            }
          }
        }
      },
    },
  }
}

function resolveSubpathImports(
  id: string,
  importer: string | undefined,
  options: InternalResolveOptions,
) {
  if (!importer || !id.startsWith(subpathImportsPrefix)) return
  const basedir = path.dirname(importer)
  const pkgData = findNearestPackageData(basedir, options.packageCache)
  if (!pkgData) return

  let { file: idWithoutPostfix, postfix } = splitFileAndPostfix(id.slice(1))
  idWithoutPostfix = '#' + idWithoutPostfix

  let importsPath = resolveExportsOrImports(
    pkgData.data,
    idWithoutPostfix,
    options,
    'imports',
  )

  if (importsPath?.[0] === '.') {
    importsPath = path.relative(basedir, path.join(pkgData.dir, importsPath))

    if (!relativePrefixRE.test(importsPath)) {
      importsPath = `./${importsPath}`
    }
  }

  if (importsPath == null) return
  return importsPath + postfix
}

function ensureVersionQuery(
  resolved: string,
  id: string,
  options: InternalResolveOptions,
  depsOptimizer?: DepsOptimizer,
): string {
  if (
    !options.isBuild &&
    !options.scan &&
    depsOptimizer &&
    !(resolved === normalizedClientEntry || resolved === normalizedEnvEntry)
  ) {
    // Ensure that direct imports of node_modules have the same version query
    // as if they would have been imported through a bare import
    // Use the original id to do the check as the resolved id may be the real
    // file path after symlinks resolution
    const isNodeModule = isInNodeModules(id) || isInNodeModules(resolved)

    if (isNodeModule && !DEP_VERSION_RE.test(resolved)) {
      const versionHash = depsOptimizer.metadata.browserHash
      if (versionHash && isOptimizable(resolved, depsOptimizer.options)) {
        resolved = injectQuery(resolved, `v=${versionHash}`)
      }
    }
  }
  return resolved
}

export function tryFsResolve(
  fsPath: string,
  options: InternalResolveOptions,
  tryIndex = true,
  skipPackageJson = false,
): string | undefined {
  // Dependencies like es5-ext use `#` in their paths. We don't support `#` in user
  // source code so we only need to perform the check for dependencies.
  // We don't support `?` in node_modules paths, so we only need to check in this branch.
  const hashIndex = fsPath.indexOf('#')
  if (hashIndex >= 0 && isInNodeModules(fsPath)) {
    const queryIndex = fsPath.indexOf('?')
    // We only need to check foo#bar?baz and foo#bar, ignore foo?bar#baz
    if (queryIndex < 0 || queryIndex > hashIndex) {
      const file = queryIndex > hashIndex ? fsPath.slice(0, queryIndex) : fsPath
      const res = tryCleanFsResolve(file, options, tryIndex, skipPackageJson)
      if (res) return res + fsPath.slice(file.length)
    }
  }

  const { file, postfix } = splitFileAndPostfix(fsPath)
  const res = tryCleanFsResolve(file, options, tryIndex, skipPackageJson)
  if (res) return res + postfix
}

const knownTsOutputRE = /\.(?:js|mjs|cjs|jsx)$/
const isPossibleTsOutput = (url: string): boolean => knownTsOutputRE.test(url)

function tryCleanFsResolve(
  file: string,
  options: InternalResolveOptions,
  tryIndex = true,
  skipPackageJson = false,
): string | undefined {
  const { tryPrefix, extensions, preserveSymlinks } = options

  // Optimization to get the real type or file type (directory, file, other)
  const fileResult = tryResolveRealFileOrType(file, options.preserveSymlinks)

  if (fileResult?.path) return fileResult.path

  let res: string | undefined

  // If path.dirname is a valid directory, try extensions and ts resolution logic
  const possibleJsToTs = isPossibleTsOutput(file)
  if (possibleJsToTs || options.extensions.length || tryPrefix) {
    const dirPath = path.dirname(file)
    if (isDirectory(dirPath)) {
      if (possibleJsToTs) {
        // try resolve .js, .mjs, .cjs or .jsx import to typescript file
        const fileExt = path.extname(file)
        const fileName = file.slice(0, -fileExt.length)
        if (
          (res = tryResolveRealFile(
            fileName + fileExt.replace('js', 'ts'),
            preserveSymlinks,
          ))
        )
          return res
        // for .js, also try .tsx
        if (
          fileExt === '.js' &&
          (res = tryResolveRealFile(fileName + '.tsx', preserveSymlinks))
        )
          return res
      }

      if (
        (res = tryResolveRealFileWithExtensions(
          file,
          extensions,
          preserveSymlinks,
        ))
      )
        return res

      if (tryPrefix) {
        const prefixed = `${dirPath}/${options.tryPrefix}${path.basename(file)}`

        if ((res = tryResolveRealFile(prefixed, preserveSymlinks))) return res

        if (
          (res = tryResolveRealFileWithExtensions(
            prefixed,
            extensions,
            preserveSymlinks,
          ))
        )
          return res
      }
    }
  }

  if (tryIndex && fileResult?.type === 'directory') {
    // Path points to a directory, check for package.json and entry and /index file
    const dirPath = file

    if (!skipPackageJson) {
      let pkgPath = `${dirPath}/package.json`
      try {
        if (fs.existsSync(pkgPath)) {
          if (!options.preserveSymlinks) {
            pkgPath = safeRealpathSync(pkgPath)
          }
          // path points to a node package
          const pkg = loadPackageData(pkgPath)
          return resolvePackageEntry(dirPath, pkg, options)
        }
      } catch (e) {
        // This check is best effort, so if an entry is not found, skip error for now
        if (e.code !== ERR_RESOLVE_PACKAGE_ENTRY_FAIL && e.code !== 'ENOENT')
          throw e
      }
    }

    if (
      (res = tryResolveRealFileWithExtensions(
        `${dirPath}/index`,
        extensions,
        preserveSymlinks,
      ))
    )
      return res

    if (tryPrefix) {
      if (
        (res = tryResolveRealFileWithExtensions(
          `${dirPath}/${options.tryPrefix}index`,
          extensions,
          preserveSymlinks,
        ))
      )
        return res
    }
  }
}

export function tryNodeResolve(
  id: string,
  importer: string | null | undefined,
  options: InternalResolveOptions,
  depsOptimizer?: DepsOptimizer,
  externalize?: boolean,
): PartialResolvedId | undefined {
  const { root, dedupe, isBuild, preserveSymlinks, packageCache } = options

  // check for deep import, e.g. "my-lib/foo"
  const deepMatch = deepImportRE.exec(id)
  // package name doesn't include postfixes
  // trim them to support importing package with queries (e.g. `import css from 'normalize.css?inline'`)
  const pkgId = deepMatch ? deepMatch[1] || deepMatch[2] : cleanUrl(id)

  let basedir: string
  if (dedupe.includes(pkgId)) {
    basedir = root
  } else if (
    importer &&
    path.isAbsolute(importer) &&
    // css processing appends `*` for importer
    (importer.endsWith('*') || fs.existsSync(cleanUrl(importer)))
  ) {
    basedir = path.dirname(importer)
  } else {
    basedir = root
  }

  const isModuleBuiltin = (id: string) => isBuiltin(options.builtins, id)

  let selfPkg = null
  if (!isModuleBuiltin(id) && !id.includes('\0') && bareImportRE.test(id)) {
    // check if it's a self reference dep.
    const selfPackageData = findNearestPackageData(basedir, packageCache)
    selfPkg =
      selfPackageData?.data.exports && selfPackageData.data.name === pkgId
        ? selfPackageData
        : null
  }

  const pkg =
    selfPkg ||
    resolvePackageData(pkgId, basedir, preserveSymlinks, packageCache)
  if (!pkg) {
    // if import can't be found, check if it's an optional peer dep.
    // if so, we can resolve to a special id that errors only when imported.
    if (
      !options.disableOptionalPeerDepHandling &&
      basedir !== root && // root has no peer dep
      !isModuleBuiltin(id) &&
      !id.includes('\0') &&
      bareImportRE.test(id)
    ) {
      const mainPkg = findNearestMainPackageData(basedir, packageCache)?.data
      if (mainPkg) {
        const pkgName = getNpmPackageName(id)
        if (
          pkgName != null &&
          mainPkg.peerDependencies?.[pkgName] &&
          mainPkg.peerDependenciesMeta?.[pkgName]?.optional
        ) {
          return {
            id: `${optionalPeerDepId}:${id}:${mainPkg.name}`,
          }
        }
      }
    }
    return
  }

  const resolveId = deepMatch ? resolveDeepImport : resolvePackageEntry
  const unresolvedId = deepMatch ? '.' + id.slice(pkgId.length) : id

  let resolved = resolveId(unresolvedId, pkg, options, externalize)
  if (!resolved) {
    return
  }

  const processResult = (resolved: PartialResolvedId) => {
    if (!externalize) {
      return resolved
    }
    if (!canExternalizeFile(resolved.id)) {
      return resolved
    }

    let resolvedId = id
    if (
      deepMatch &&
      !pkg.data.exports &&
      path.extname(id) !== path.extname(resolved.id)
    ) {
      // id date-fns/locale
      // resolve.id ...date-fns/esm/locale/index.js
      const index = resolved.id.indexOf(id)
      if (index > -1) {
        resolvedId = resolved.id.slice(index)
        debug?.(
          `[processResult] ${colors.cyan(id)} -> ${colors.dim(resolvedId)}`,
        )
      }
    }
    return { ...resolved, id: resolvedId, external: true }
  }

  if (!options.idOnly && ((!options.scan && isBuild) || externalize)) {
    // Resolve package side effects for build so that rollup can better
    // perform tree-shaking
    return processResult({
      id: resolved,
      moduleSideEffects: pkg.hasSideEffects(resolved),
      packageJsonPath: findNearestPackagePath(
        resolved,
        options.legacyInconsistentCjsInterop,
        options.packageCache,
        isBuild,
      ),
    })
  }

  if (
    !isInNodeModules(resolved) || // linked
    !depsOptimizer || // resolving before listening to the server
    options.scan // initial esbuild scan phase
  ) {
    return { id: resolved }
  }

  // if we reach here, it's a valid dep import that hasn't been optimized.
  const isJsType = isOptimizable(resolved, depsOptimizer.options)
  const exclude = depsOptimizer.options.exclude

  const skipOptimization =
    depsOptimizer.options.noDiscovery ||
    !isJsType ||
    (importer && isInNodeModules(importer)) ||
    exclude?.includes(pkgId) ||
    exclude?.includes(id) ||
    SPECIAL_QUERY_RE.test(resolved)

  if (skipOptimization) {
    // excluded from optimization
    // Inject a version query to npm deps so that the browser
    // can cache it without re-validation, but only do so for known js types.
    // otherwise we may introduce duplicated modules for externalized files
    // from pre-bundled deps.
    const versionHash = depsOptimizer.metadata.browserHash
    if (versionHash && isJsType) {
      resolved = injectQuery(resolved, `v=${versionHash}`)
    }
  } else {
    // this is a missing import, queue optimize-deps re-run and
    // get a resolved its optimized info
    const optimizedInfo = depsOptimizer.registerMissingImport(id, resolved)
    resolved = depsOptimizer.getOptimizedDepId(optimizedInfo)
  }

  return { id: resolved }
}

export async function tryOptimizedResolve(
  depsOptimizer: DepsOptimizer,
  id: string,
  importer?: string,
  preserveSymlinks?: boolean,
  packageCache?: PackageCache,
): Promise<string | undefined> {
  // TODO: we need to wait until scanning is done here as this function
  // is used in the preAliasPlugin to decide if an aliased dep is optimized,
  // and avoid replacing the bare import with the resolved path.
  // We should be able to remove this in the future
  await depsOptimizer.scanProcessing

  const metadata = depsOptimizer.metadata

  const depInfo = optimizedDepInfoFromId(metadata, id)
  if (depInfo) {
    return depsOptimizer.getOptimizedDepId(depInfo)
  }

  if (!importer) return

  // further check if id is imported by nested dependency
  let idPkgDir: string | undefined
  const nestedIdMatch = `> ${id}`

  for (const optimizedData of metadata.depInfoList) {
    if (!optimizedData.src) continue // Ignore chunks

    // check where "foo" is nested in "my-lib > foo"
    if (!optimizedData.id.endsWith(nestedIdMatch)) continue

    // lazily initialize idPkgDir
    if (idPkgDir == null) {
      const pkgName = getNpmPackageName(id)
      if (!pkgName) break
      idPkgDir = resolvePackageData(
        pkgName,
        importer,
        preserveSymlinks,
        packageCache,
      )?.dir
      // if still null, it likely means that this id isn't a dep for importer.
      // break to bail early
      if (idPkgDir == null) break
      idPkgDir = normalizePath(idPkgDir)
    }

    // match by src to correctly identify if id belongs to nested dependency
    if (optimizedData.src.startsWith(withTrailingSlash(idPkgDir))) {
      return depsOptimizer.getOptimizedDepId(optimizedData)
    }
  }
}

export function resolvePackageEntry(
  id: string,
  { dir, data, setResolvedCache, getResolvedCache }: PackageData,
  options: InternalResolveOptions,
  externalize?: boolean,
): string | undefined {
  const { file: idWithoutPostfix, postfix } = splitFileAndPostfix(id)

  const cached = getResolvedCache('.', options)
  if (cached) {
    return cached + postfix
  }

  try {
    let entryPoint: string | undefined

    // resolve exports field with highest priority
    // using https://github.com/lukeed/resolve.exports
    if (data.exports) {
      entryPoint = resolveExportsOrImports(
        data,
        '.',
        options,
        'exports',
        externalize,
      )
    }

    // fallback to mainFields if still not resolved
    if (!entryPoint) {
      for (const field of options.mainFields) {
        if (typeof data[field] === 'string') {
          entryPoint = data[field]
          break
        } else if (field === 'browser') {
          const browser = data[field]
          if (isObject(browser) && browser['.']) {
            entryPoint = browser['.']
            break
          }
        }
      }
    }
    entryPoint ||= data.main

    // try default entry when entry is not define
    // https://nodejs.org/api/modules.html#all-together
    const entryPoints = entryPoint
      ? [entryPoint]
      : ['index.js', 'index.json', 'index.node']

    for (let entry of entryPoints) {
      // make sure we don't get scripts when looking for sass
      let skipPackageJson = false
      if (
        options.mainFields[0] === 'sass' &&
        !options.extensions.includes(path.extname(entry))
      ) {
        entry = ''
        skipPackageJson = true
      } else {
        // resolve object browser field in package.json
        const { browser: browserField } = data
        if (options.mainFields.includes('browser') && isObject(browserField)) {
          entry = mapWithBrowserField(entry, browserField) || entry
        }
      }

      const entryPointPath = path.join(dir, entry)
      const resolvedEntryPoint = tryFsResolve(
        entryPointPath,
        options,
        true,
        skipPackageJson,
      )
      if (resolvedEntryPoint) {
        debug?.(
          `[package entry] ${colors.cyan(idWithoutPostfix)} -> ${colors.dim(
            resolvedEntryPoint,
          )}${postfix !== '' ? ` (postfix: ${postfix})` : ''}`,
        )
        setResolvedCache('.', resolvedEntryPoint, options)
        return resolvedEntryPoint + postfix
      }
    }
  } catch (e) {
    packageEntryFailure(id, e.message)
  }
  packageEntryFailure(id)
}

function packageEntryFailure(id: string, details?: string) {
  const err: any = new Error(
    `Failed to resolve entry for package "${id}". ` +
      `The package may have incorrect main/module/exports specified in its package.json` +
      (details ? ': ' + details : '.'),
  )
  err.code = ERR_RESOLVE_PACKAGE_ENTRY_FAIL
  throw err
}

function getConditions(
  conditions: string[],
  isProduction: boolean,
  isRequire: boolean | undefined,
) {
  const resolvedConditions = conditions.map((condition) => {
    if (condition === DEV_PROD_CONDITION) {
      return isProduction ? 'production' : 'development'
    }
    return condition
  })

  if (isRequire) {
    resolvedConditions.push('require')
  } else {
    resolvedConditions.push('import')
  }

  return resolvedConditions
}

function resolveExportsOrImports(
  pkg: PackageData['data'],
  key: string,
  options: InternalResolveOptions,
  type: 'imports' | 'exports',
  externalize?: boolean,
) {
  const conditions = getConditions(
    externalize ? options.externalConditions : options.conditions,
    options.isProduction,
    options.isRequire,
  )

  const fn = type === 'imports' ? imports : exports
  const result = fn(pkg, key, { conditions, unsafe: true })
  return result ? result[0] : undefined
}

function resolveDeepImport(
  id: string,
  { setResolvedCache, getResolvedCache, dir, data }: PackageData,
  options: InternalResolveOptions,
  externalize?: boolean,
): string | undefined {
  const cache = getResolvedCache(id, options)
  if (cache) {
    return cache
  }

  let relativeId: string | undefined | void = id
  const { exports: exportsField, browser: browserField } = data

  // map relative based on exports data
  if (exportsField) {
    if (isObject(exportsField) && !Array.isArray(exportsField)) {
      // resolve without postfix (see #7098)
      const { file, postfix } = splitFileAndPostfix(relativeId)
      const exportsId = resolveExportsOrImports(
        data,
        file,
        options,
        'exports',
        externalize,
      )
      if (exportsId !== undefined) {
        relativeId = exportsId + postfix
      } else {
        relativeId = undefined
      }
    } else {
      // not exposed
      relativeId = undefined
    }
    if (!relativeId) {
      throw new Error(
        `Package subpath '${relativeId}' is not defined by "exports" in ` +
          `${path.join(dir, 'package.json')}.`,
      )
    }
  } else if (options.mainFields.includes('browser') && isObject(browserField)) {
    // resolve without postfix (see #7098)
    const { file, postfix } = splitFileAndPostfix(relativeId)
    const mapped = mapWithBrowserField(file, browserField)
    if (mapped) {
      relativeId = mapped + postfix
    } else if (mapped === false) {
      setResolvedCache(id, browserExternalId, options)
      return browserExternalId
    }
  }

  if (relativeId) {
    const resolved = tryFsResolve(
      path.join(dir, relativeId),
      options,
      !exportsField, // try index only if no exports field
    )
    if (resolved) {
      debug?.(
        `[node/deep-import] ${colors.cyan(id)} -> ${colors.dim(resolved)}`,
      )
      setResolvedCache(id, resolved, options)
      return resolved
    }
  }
}

/**
 * given a relative path in pkg dir,
 * return a relative path in pkg dir,
 * mapped with the "map" object
 *
 * - Returning `undefined` means there is no browser mapping for this id
 * - Returning `false` means this id is explicitly externalized for browser
 */
function mapWithBrowserField(
  relativePathInPkgDir: string,
  map: Record<string, string | false>,
): string | false | undefined {
  const normalizedPath = path.posix.normalize(relativePathInPkgDir)

  for (const key in map) {
    const normalizedKey = path.posix.normalize(key)
    if (
      normalizedPath === normalizedKey ||
      equalWithoutSuffix(normalizedPath, normalizedKey, '.js') ||
      equalWithoutSuffix(normalizedPath, normalizedKey, '/index.js')
    ) {
      return map[key]
    }
  }
}

function equalWithoutSuffix(path: string, key: string, suffix: string) {
  return key.endsWith(suffix) && key.slice(0, -suffix.length) === path
}

function tryResolveRealFile(
  file: string,
  preserveSymlinks?: boolean,
): string | undefined {
  const stat = tryStatSync(file)
  if (stat?.isFile()) return getRealPath(file, preserveSymlinks)
}

function tryResolveRealFileWithExtensions(
  filePath: string,
  extensions: string[],
  preserveSymlinks?: boolean,
): string | undefined {
  for (const ext of extensions) {
    const res = tryResolveRealFile(filePath + ext, preserveSymlinks)
    if (res) return res
  }
}

function tryResolveRealFileOrType(
  file: string,
  preserveSymlinks?: boolean,
): { path?: string; type: 'directory' | 'file' } | undefined {
  const fileStat = tryStatSync(file)
  if (fileStat?.isFile()) {
    return { path: getRealPath(file, preserveSymlinks), type: 'file' }
  }
  if (fileStat?.isDirectory()) {
    return { type: 'directory' }
  }
  return
}

function getRealPath(resolved: string, preserveSymlinks?: boolean): string {
  if (!preserveSymlinks) {
    resolved = safeRealpathSync(resolved)
  }
  return normalizePath(resolved)
}

function isDirectory(path: string): boolean {
  const stat = tryStatSync(path)
  return stat?.isDirectory() ?? false
}

function findNearestPackagePath(
  file: string,
  legacyInconsistentCjsInterop: boolean | undefined,
  packageCache: PackageCache | undefined,
  isBuild: boolean,
) {
  if (!isBuild || legacyInconsistentCjsInterop) return
  const pkgData = findNearestPackageData(file, packageCache)
  return pkgData ? path.join(pkgData.dir, 'package.json') : null
}


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

using json = nlohmann::json;

int main()
{
    // create several JSON values
    json array = {1, 2, 3};
    json object = {{"A", "a"}, {"B", "b"}};
    json number = 17;
    json string = "foo";
    json null;

    // output values and comparisons
    std::cout << std::boolalpha;
    std::cout << array << " == nullptr " << (array == nullptr) << '\n';
    std::cout << object << " == nullptr " << (object == nullptr) << '\n';
    std::cout << number << " == nullptr " << (number == nullptr) << '\n';
    std::cout << string << " == nullptr " << (string == nullptr) << '\n';
    std::cout << null << " == nullptr " << (null == nullptr) << '\n';
}


{% extends 'base.html' %}

{% block header %}

{% block title %}Posts{% endblock %}

  {% if g.user %}
    New
  {% endif %}
{% endblock %}

{% block content %}
  {% for post in posts %}

{{ post['title'] }}

by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}

        {% if g.user['id'] == post['author_id'] %}
          Edit
        {% endif %}

{{ post['body'] }}

    {% if not loop.last %}

    {% endif %}
  {% endfor %}
{% endblock %}


# <small>nlohmann::json_pointer::</small>operator string_t

```cpp
operator string_t() const
```

Return a string representation of the JSON pointer.

## Return value

A string representation of the JSON pointer

## Possible implementation

```cpp
operator string_t() const
{
    return to_string();
}
```

## Notes

!!! warning "Deprecation"

    This function is deprecated in favor of [`to_string`](to_string.md) and will be removed in a future major version
    release.

## Examples

??? example

    The example shows how JSON Pointers can be implicitly converted to strings.

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

    Output:

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

## See also

- [string_t](../basic_json/string_t.md)- type for strings

## Version history

- Since version 2.0.0.
- Changed type to `string_t` and deprecated in version 3.11.0.


# JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26

```cpp
#define JSON_HAS_CPP_11
#define JSON_HAS_CPP_14
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_20
#define JSON_HAS_CPP_23
#define JSON_HAS_CPP_26
```

The library targets C++11, but also supports some features introduced in later C++ versions (e.g., `std::string_view`
support for C++17). For these new features, the library implements some preprocessor checks to determine the C++
standard. By defining any of these symbols, the internal check is overridden and the provided C++ version is
unconditionally assumed. This can be helpful for compilers that only implement parts of the standard and would be
detected incorrectly.

## Default definition

The default value is detected based on preprocessor macros such as `#!cpp __cplusplus`, `#!cpp _HAS_CXX17`, or
`#!cpp _MSVC_LANG`.

## Notes

- When the C++ standard is detected automatically, `#!cpp JSON_HAS_CPP_11` is always defined. When you override the
  detection by defining one of these macros manually, the automatic detection is skipped entirely, so you should define
  all applicable macros (including `#!cpp JSON_HAS_CPP_11`) yourself.
- All macros are undefined outside the library.

## Examples

??? example

    The code below forces the library to use the C++14 standard:

    ```cpp
    #define JSON_HAS_CPP_14 1
    #include <nlohmann/json.hpp>

    ...
    ```

## Version history

- Added in version 3.10.5.
- Added `JSON_HAS_CPP_23` in version 3.12.0.
- Added `JSON_HAS_CPP_26` in version 3.13.0.


# Building for Production

When it is time to deploy your app for production, simply run the `vite build` command. By default, it uses `<root>/index.html` as the build entry point, and produces an application bundle that is suitable to be served over a static hosting service. Check out the [Deploying a Static Site](./static-deploy) for guides about popular services.

<ScrimbaLink href="https://scrimba.com/intro-to-vite-c03p6pbbdq/~037q?via=vite" title="Building for Production">Watch an interactive lesson on Scrimba</ScrimbaLink>

## Browser Compatibility

By default, the production bundle targets the minimum browser versions compatible with [Baseline](https://web-platform-dx.github.io/baseline/) Widely Available as of a date fixed for each major release. The default browser support range for this major is:

<!-- Search for the `ESBUILD_BASELINE_WIDELY_AVAILABLE_TARGET` constant for more information -->

- Chrome >=111
- Edge >=111
- Firefox >=114
- Safari >=16.4

You can specify custom targets via the [`build.target` config option](/config/build-options.md#build-target), where the lowest target is `es2015`. If a lower target is set, Vite will still require these minimum browser support ranges as it relies on [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import), and [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta):

<!-- Search for the `defaultEsbuildSupported` constant for more information -->

- Chrome >=64
- Firefox >=67
- Safari >=11.1
- Edge >=79

Note that by default, Vite only handles syntax transforms and **does not cover polyfills**. You can check out https://cdnjs.cloudflare.com/polyfill/ which automatically generates polyfill bundles based on the user's browser UserAgent string.

Legacy browsers can be supported via [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy), which will automatically generate legacy chunks and corresponding ES language feature polyfills. The legacy chunks are conditionally loaded only in browsers that do not have native ESM support.

## Public Base Path

- Related: [Asset Handling](./assets)

If you are deploying your project under a nested public path, simply specify the [`base` config option](/config/shared-options.md#base) and all asset paths will be rewritten accordingly. This option can also be specified as a command line flag, e.g. `vite build --base=/my/public/path/`.

JS-imported asset URLs, CSS `url()` references, and asset references in your `.html` files are all automatically adjusted to respect this option during build.

The exception is when you need to dynamically concatenate URLs on the fly. In this case, you can use the globally injected `import.meta.env.BASE_URL` variable which will be the public base path. Note this variable is statically replaced during build so it must appear exactly as-is (i.e. `import.meta.env['BASE_URL']` won't work).

For advanced base path control, check out [Advanced Base Options](#advanced-base-options).

### Relative base

If you don't know the base path in advance, you may set a relative base path with `"base": "./"` or `"base": ""`. This will make all generated URLs to be relative to each file.

:::warning Support for older browsers when using relative bases

`import.meta` support is required for relative bases. If you need to support [browsers that do not support `import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta), you can use [the `legacy` plugin](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy).

:::

## Customizing the Build

The build can be customized via various [build config options](/config/build-options.md). Specifically, you can directly adjust the underlying [Rolldown options](https://rolldown.rs/reference/) via `build.rolldownOptions`:

```js [vite.config.js]
export default defineConfig({
  build: {
    rolldownOptions: {
      // https://rolldown.rs/reference/
    },
  },
})
```

For example, you can specify multiple Rolldown outputs with plugins that are only applied during build.

## Chunking Strategy

You can configure how chunks are split using [`build.rolldownOptions.output.codeSplitting`](https://rolldown.rs/reference/OutputOptions.codeSplitting) (see [Rolldown docs](https://rolldown.rs/in-depth/manual-code-splitting)). If you use a framework, refer to their documentation for configuring how chunks are split.

## Load Error Handling

Vite emits `vite:preloadError` event when it fails to load dynamic imports. `event.payload` contains the original import error. If you call `event.preventDefault()`, the error will not be thrown.

```js twoslash
window.addEventListener('vite:preloadError', (event) => {
  window.location.reload() // for example, refresh the page
})
```

When a new deployment occurs, the hosting service may delete the assets from previous deployments. As a result, a user who visited your site before the new deployment might encounter an import error. This error happens because the assets running on that user's device are outdated and it tries to import the corresponding old chunk, which is deleted. This event is useful for addressing this situation. In this case, make sure to set `Cache-Control: no-cache` on the HTML file, otherwise the old assets will be still referenced.

## Rebuild on Files Changes

You can enable Rolldown watcher with `vite build --watch`. Or, you can directly adjust the underlying [`WatcherOptions`](https://rolldown.rs/reference/InputOptions.watch) via `build.watch`:

```js [vite.config.js]
export default defineConfig({
  build: {
    watch: {
      // https://rolldown.rs/reference/InputOptions.watch
    },
  },
})
```

With the `--watch` flag enabled, changes to files to be bundled will trigger a rebuild. Note that changes to the config and its dependencies require restarting the build command.

## Multi-Page App

Suppose you have the following source code structure:

```
├── package.json
├── vite.config.js
├── index.html
├── main.js
└── nested
    ├── index.html
    └── nested.js
```

During dev, simply navigate or link to `/nested/` - it works as expected, just like for a normal static file server.

During build, all you need to do is to specify multiple `.html` files as entry points:

```js twoslash [vite.config.js]
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  input: {
    main: resolve(import.meta.dirname, 'index.html'),
    nested: resolve(import.meta.dirname, 'nested/index.html'),
  },
})
```

If you specify a different root, remember that `import.meta.dirname` will still be the folder of your `vite.config.js` file when resolving the input paths. Therefore, you will need to add your `root` entry to the arguments for `resolve`.

Note that for HTML files, Vite ignores the name given to the entry in the `rolldownOptions.input` object and instead respects the resolved id of the file when generating the HTML asset in the dist folder. This ensures a consistent structure with the way the dev server works.

## Library Mode

When you are developing a browser-oriented library, you are likely spending most of the time on a test/demo page that imports your actual library. With Vite, you can use your `index.html` for that purpose to get the smooth development experience.

When it is time to bundle your library for distribution, use the [`build.lib` config option](/config/build-options.md#build-lib). Make sure to also externalize any dependencies that you do not want to bundle into your library, e.g. `vue` or `react`:

::: code-group

```js twoslash [vite.config.js (single entry)]
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(import.meta.dirname, 'lib/main.js'),
      name: 'MyLib',
      // the proper extensions will be added
      fileName: 'my-lib',
    },
    rolldownOptions: {
      // make sure to externalize deps that shouldn't be bundled
      // into your library
      external: ['vue'],
      output: {
        // Provide global variables to use in the UMD build
        // for externalized deps
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})
```

```js twoslash [vite.config.js (multiple entries)]
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: {
        'my-lib': resolve(import.meta.dirname, 'lib/main.js'),
        secondary: resolve(import.meta.dirname, 'lib/secondary.js'),
      },
      name: 'MyLib',
    },
    rolldownOptions: {
      // make sure to externalize deps that shouldn't be bundled
      // into your library
      external: ['vue'],
      output: {
        // Provide global variables to use in the UMD build
        // for externalized deps
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})
```

:::

The entry file would contain exports that can be imported by users of your package:

```js [lib/main.js]
import Foo from './Foo.vue'
import Bar from './Bar.vue'
export { Foo, Bar }
```

Running `vite build` with this config uses a Rollup preset that is oriented towards shipping libraries and produces two bundle formats:

- `es` and `umd` (for single entry)
- `es` and `cjs` (for multiple entries)

The formats can be configured with the [`build.lib.formats`](/config/build-options.md#build-lib) option.

```
$ vite build
building for production...
dist/my-lib.js      0.08 kB / gzip: 0.07 kB
dist/my-lib.umd.cjs 0.30 kB / gzip: 0.16 kB
```

Recommended `package.json` for your lib:

::: code-group

```json [package.json (single entry)]
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.umd.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.umd.cjs"
    }
  }
}
```

```json [package.json (multiple entries)]
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.cjs"
    },
    "./secondary": {
      "import": "./dist/secondary.js",
      "require": "./dist/secondary.cjs"
    }
  }
}
```

:::

### CSS support

If your library imports any CSS, it will be bundled as a single CSS file besides the built JS files, e.g. `dist/my-lib.css`. The name defaults to `build.lib.fileName`, but can also be changed with [`build.lib.cssFileName`](/config/build-options.md#build-lib).

You can export the CSS file in your `package.json` to be imported by users:

```json {12}
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.umd.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.umd.cjs"
    },
    "./style.css": "./dist/my-lib.css"
  }
}
```

::: tip File Extensions
If the `package.json` does not contain `"type": "module"`, Vite will generate different file extensions for Node.js compatibility. `.js` will become `.mjs` and `.cjs` will become `.js`.
:::

::: tip Environment Variables
In library mode, all [`import.meta.env.*`](./env-and-mode.md) usage are statically replaced when building for production. However, `process.env.*` usage are not, so that consumers of your library can dynamically change it. If this is undesirable, you can use `define: { 'process.env.NODE_ENV': '"production"' }` for example to statically replace them, or use [`esm-env`](https://github.com/benmccann/esm-env) for better compatibility with bundlers and runtimes.
:::

::: warning Advanced Usage
Library mode includes a simple and opinionated configuration for browser-oriented and JS framework libraries. If you are building non-browser libraries, or require advanced build flows, you can use [tsdown](https://tsdown.dev/) or [Rolldown](https://rolldown.rs/) directly.
:::

## Advanced Base Options

::: warning
This feature is experimental. [Give Feedback](https://github.com/vitejs/vite/discussions/13834).
:::

For advanced use cases, the deployed assets and public files may be in different paths, for example to use different cache strategies.
A user may choose to deploy in three different paths:

- The generated entry HTML files (which may be processed during SSR)
- The generated hashed assets (JS, CSS, and other file types like images)
- The copied [public files](assets.md#the-public-directory)

A single static [base](#public-base-path) isn't enough in these scenarios. Vite provides experimental support for advanced base options during build, using `experimental.renderBuiltUrl`.

```ts twoslash
import type { UserConfig } from 'vite'
// prettier-ignore
const config: UserConfig = {
// ---cut-before---
experimental: {
  renderBuiltUrl(filename, { hostType }) {
    if (hostType === 'js') {
      return { runtime: `window.__toCdnUrl(${JSON.stringify(filename)})` }
    } else {
      return { relative: true }
    }
  },
},
// ---cut-after---
}
```

If the hashed assets and public files aren't deployed together, options for each group can be defined independently using asset `type` included in the second `context` param given to the function.

```ts twoslash
import type { UserConfig } from 'vite'
import path from 'node:path'
// prettier-ignore
const config: UserConfig = {
// ---cut-before---
experimental: {
  renderBuiltUrl(filename, { hostId, hostType, type }) {
    if (type === 'public') {
      return 'https://www.domain.com/' + filename
    } else if (path.extname(hostId) === '.js') {
      return {
        runtime: `window.__assetsPath(${JSON.stringify(filename)})`
      }
    } else {
      return 'https://cdn.domain.com/assets/' + filename
    }
  },
},
// ---cut-after---
}
```

Note that the `filename` passed is a decoded URL, and if the function returns a URL string, it should also be decoded. Vite will handle the encoding automatically when rendering the URLs. If an object with `runtime` is returned, encoding should be handled yourself where needed as the runtime code will be rendered as is.