use std::{
    ops::{Add, AddAssign},
    time::Duration,
};

use crate::util::NiceDuration;

/// Summary statistics produced at the end of a search.
///
/// When statistics are reported by a printer, they correspond to all searches
/// executed with that printer.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Stats {
    elapsed: NiceDuration,
    searches: u64,
    searches_with_match: u64,
    bytes_searched: u64,
    bytes_printed: u64,
    matched_lines: u64,
    matches: u64,
}

impl Stats {
    /// Return a new value for tracking aggregate statistics across searches.
    ///
    /// All statistics are set to `0`.
    pub fn new() -> Stats {
        Stats::default()
    }

    /// Return the total amount of time elapsed.
    pub fn elapsed(&self) -> Duration {
        self.elapsed.0
    }

    /// Return the total number of searches executed.
    pub fn searches(&self) -> u64 {
        self.searches
    }

    /// Return the total number of searches that found at least one match.
    pub fn searches_with_match(&self) -> u64 {
        self.searches_with_match
    }

    /// Return the total number of bytes searched.
    pub fn bytes_searched(&self) -> u64 {
        self.bytes_searched
    }

    /// Return the total number of bytes printed.
    pub fn bytes_printed(&self) -> u64 {
        self.bytes_printed
    }

    /// Return the total number of lines that participated in a match.
    ///
    /// When matches may contain multiple lines then this includes every line
    /// that is part of every match.
    pub fn matched_lines(&self) -> u64 {
        self.matched_lines
    }

    /// Return the total number of matches.
    ///
    /// There may be multiple matches per line.
    pub fn matches(&self) -> u64 {
        self.matches
    }

    /// Add to the elapsed time.
    pub fn add_elapsed(&mut self, duration: Duration) {
        self.elapsed.0 += duration;
    }

    /// Add to the number of searches executed.
    pub fn add_searches(&mut self, n: u64) {
        self.searches += n;
    }

    /// Add to the number of searches that found at least one match.
    pub fn add_searches_with_match(&mut self, n: u64) {
        self.searches_with_match += n;
    }

    /// Add to the total number of bytes searched.
    pub fn add_bytes_searched(&mut self, n: u64) {
        self.bytes_searched += n;
    }

    /// Add to the total number of bytes printed.
    pub fn add_bytes_printed(&mut self, n: u64) {
        self.bytes_printed += n;
    }

    /// Add to the total number of lines that participated in a match.
    pub fn add_matched_lines(&mut self, n: u64) {
        self.matched_lines += n;
    }

    /// Add to the total number of matches.
    pub fn add_matches(&mut self, n: u64) {
        self.matches += n;
    }
}

impl Add for Stats {
    type Output = Stats;

    fn add(self, rhs: Stats) -> Stats {
        self + &rhs
    }
}

impl<'a> Add<&'a Stats> for Stats {
    type Output = Stats;

    fn add(self, rhs: &'a Stats) -> Stats {
        Stats {
            elapsed: NiceDuration(self.elapsed.0 + rhs.elapsed.0),
            searches: self.searches + rhs.searches,
            searches_with_match: self.searches_with_match
                + rhs.searches_with_match,
            bytes_searched: self.bytes_searched + rhs.bytes_searched,
            bytes_printed: self.bytes_printed + rhs.bytes_printed,
            matched_lines: self.matched_lines + rhs.matched_lines,
            matches: self.matches + rhs.matches,
        }
    }
}

impl AddAssign for Stats {
    fn add_assign(&mut self, rhs: Stats) {
        *self += &rhs;
    }
}

impl<'a> AddAssign<&'a Stats> for Stats {
    fn add_assign(&mut self, rhs: &'a Stats) {
        self.elapsed.0 += rhs.elapsed.0;
        self.searches += rhs.searches;
        self.searches_with_match += rhs.searches_with_match;
        self.bytes_searched += rhs.bytes_searched;
        self.bytes_printed += rhs.bytes_printed;
        self.matched_lines += rhs.matched_lines;
        self.matches += rhs.matches;
    }
}

#[cfg(feature = "serde")]
impl serde::Serialize for Stats {
    fn serialize<S: serde::Serializer>(
        &self,
        s: S,
    ) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeStruct;

        let mut state = s.serialize_struct("Stats", 7)?;
        state.serialize_field("elapsed", &self.elapsed)?;
        state.serialize_field("searches", &self.searches)?;
        state.serialize_field(
            "searches_with_match",
            &self.searches_with_match,
        )?;
        state.serialize_field("bytes_searched", &self.bytes_searched)?;
        state.serialize_field("bytes_printed", &self.bytes_printed)?;
        state.serialize_field("matched_lines", &self.matched_lines)?;
        state.serialize_field("matches", &self.matches)?;
        state.end()
    }
}


import path from 'node:path'
import { readdir } from 'node:fs/promises'
import { expect, test } from 'vitest'
import {
  addFile,
  editFile,
  findAssetFile,
  isBuild,
  isBundledDev,
  page,
  removeFile,
} from '~utils'

const filteredResult = {
  './alias.js': {
    default: 'hi',
  },
  './foo.js': {
    msg: 'foo',
  },
  "./quote'.js": {
    msg: 'single-quote',
  },
}

const json = {
  msg: 'baz',
  default: {
    msg: 'baz',
  },
}

const globWithAlias = {
  '/dir/alias.js': {
    default: 'hi',
  },
}

const allResult = {
  // JSON file should be properly transformed
  '/dir/alias.js': {
    default: 'hi',
  },
  '/dir/baz.json': json,
  '/dir/foo.css': {},
  '/dir/foo.js': {
    msg: 'foo',
  },
  '/dir/index.js': isBuild
    ? {
        modules: filteredResult,
        globWithAlias,
      }
    : {
        globWithAlias,
        modules: filteredResult,
      },
  '/dir/nested/bar.js': {
    modules: {
      '../baz.json': json,
    },
    msg: 'bar',
  },
  "/dir/quote'.js": {
    msg: 'single-quote',
  },
}

const nodeModulesResult = {
  '/dir/node_modules/hoge.js': { msg: 'hoge' },
}

const rawResult = {
  '/dir/baz.json': {
    msg: 'baz',
  },
}

const relativeRawResult = {
  './dir/baz.json': {
    msg: 'baz',
  },
}

const baseRawResult = {
  './baz.json': {
    msg: 'baz',
  },
}

test('should work', async () => {
  await expect
    .poll(async () => JSON.parse(await page.textContent('.result')))
    .toStrictEqual(allResult)
  await expect
    .poll(async () => JSON.parse(await page.textContent('.result-eager')))
    .toStrictEqual(allResult)
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.result-node_modules')),
    )
    .toStrictEqual(nodeModulesResult)
})

test('import glob raw', async () => {
  expect(await page.textContent('.globraw')).toBe(
    JSON.stringify(rawResult, null, 2),
  )
})

test('import property access', async () => {
  expect(await page.textContent('.property-access')).toBe(
    JSON.stringify(rawResult['/dir/baz.json'], null, 2),
  )
})

test('import relative glob raw', async () => {
  expect(await page.textContent('.relative-glob-raw')).toBe(
    JSON.stringify(relativeRawResult, null, 2),
  )
})

test('unassigned import processes', async () => {
  expect(await page.textContent('.side-effect-result')).toBe(
    'Hello from side effect',
  )
})

test('import glob in package', async () => {
  expect(await page.textContent('.in-package')).toBe(
    JSON.stringify(['/pkg-pages/foo.js']),
  )
})

if (!isBuild) {
  test.skipIf(isBundledDev)('hmr for adding/removing files', async () => {
    const resultElement = page.locator('.result')

    addFile('root/dir/a.js', '')
    await expect
      .poll(async () => {
        const actualAdd = await resultElement.textContent()
        return JSON.parse(actualAdd)
      })
      .toStrictEqual({
        '/dir/a.js': {},
        ...allResult,
        '/dir/index.js': {
          ...allResult['/dir/index.js'],
          modules: {
            './a.js': {},
            ...allResult['/dir/index.js'].modules,
          },
        },
      })

    // edit the added file
    editFile('root/dir/a.js', () => 'export const msg ="a"')
    await expect
      .poll(async () => {
        const actualEdit = await resultElement.textContent()
        return JSON.parse(actualEdit)
      })
      .toStrictEqual({
        '/dir/a.js': {
          msg: 'a',
        },
        ...allResult,
        '/dir/index.js': {
          ...allResult['/dir/index.js'],
          modules: {
            './a.js': {
              msg: 'a',
            },
            ...allResult['/dir/index.js'].modules,
          },
        },
      })

    removeFile('root/dir/a.js')
    await expect
      .poll(async () => {
        const actualRemove = await resultElement.textContent()
        return JSON.parse(actualRemove)
      })
      .toStrictEqual(allResult)
  })

  test('no hmr for adding/removing files', async () => {
    let request = page.waitForResponse(/dir\/index\.js$/, { timeout: 200 })
    addFile('root/nohmr.js', '')
    let response = await request.catch(() => ({ status: () => -1 }))
    expect(response.status()).toBe(-1)

    request = page.waitForResponse(/dir\/index\.js$/, { timeout: 200 })
    removeFile('root/nohmr.js')
    response = await request.catch(() => ({ status: () => -1 }))
    expect(response.status()).toBe(-1)
  })

  test.skipIf(isBundledDev)(
    'hmr for adding/removing files in package',
    async () => {
      const resultElement = page.locator('.in-package')

      addFile('root/pkg-pages/bar.js', '// empty')
      await expect
        .poll(async () => JSON.parse(await resultElement.textContent()))
        .toStrictEqual(['/pkg-pages/foo.js', '/pkg-pages/bar.js'].sort())

      removeFile('root/pkg-pages/bar.js')
      await expect
        .poll(async () => JSON.parse(await resultElement.textContent()))
        .toStrictEqual(['/pkg-pages/foo.js'])
    },
  )

  test.skipIf(isBundledDev)(
    'hmr for adding/removing files with array patterns and exclusions',
    async () => {
      const resultElement = page.locator('.array-result')
      await expect
        .poll(async () => JSON.parse(await resultElement.textContent()))
        .toStrictEqual({
          './array-test-dir/included.js': 'included',
        })

      addFile('root/array-test-dir/new-file.js', 'export default "new"')
      await expect
        .poll(async () => JSON.parse(await resultElement.textContent()))
        .toStrictEqual({
          './array-test-dir/included.js': 'included',
          './array-test-dir/new-file.js': 'new',
        })

      removeFile('root/array-test-dir/new-file.js')
      await expect
        .poll(async () => JSON.parse(await resultElement.textContent()))
        .toStrictEqual({
          './array-test-dir/included.js': 'included',
        })
    },
  )
}

test('follow symlinks', async () => {
  await expect
    .poll(async () => JSON.parse(await page.textContent('.follow-symlinks')))
    .toStrictEqual({
      './follow-symlinks/linked/my-lib/components/a.js': 'a',
      './follow-symlinks/linked/my-lib/components/b.js': 'b',
    })
})

test('follow symlinks same reference', async () => {
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.follow-symlinks-same-ref')),
    )
    .toStrictEqual({
      a: true,
      b: true,
    })
})

test('alias exclusion', async () => {
  await expect
    .poll(async () => JSON.parse(await page.textContent('.alias-exclusion')))
    .toSatisfy((keys: string[]) => {
      return keys.length > 0 && keys.every((k) => !k.includes('alias'))
    })
})

test('array pattern with exclusions', async () => {
  await expect
    .poll(async () => JSON.parse(await page.textContent('.array-result')))
    .toStrictEqual({
      './array-test-dir/included.js': 'included',
    })
})

// https://github.com/vitejs/vite/issues/22170
test('array pattern with sibling directories sharing a prefix', async () => {
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.array-common-base-result')),
    )
    .toStrictEqual({
      '/array-common-base/pattern1/a.js': 'a',
      '/array-common-base/pattern2/b.js': 'b',
    })
})

test('tree-shake eager css', async () => {
  expect(await page.textContent('.no-tree-shake-eager-css-result')).toMatch(
    '.no-tree-shake-eager-css',
  )

  if (isBuild) {
    const content = findAssetFile(/index-[-\w]+\.js/, '../root/dist')
    expect(content).not.toMatch('.tree-shake-eager-css')
  }
})

test('escapes special chars in globs without mangling user supplied glob suffix', async () => {
  // the escape dir contains subdirectories where each has a name that needs escaping for glob safety
  // inside each of them is a glob.js that exports the result of a relative glob `./**/*.js`
  // and an alias glob `@escape_<dirname>_mod/**/*.js`. The matching aliases are generated in vite.config.ts
  // index.html has a script that loads all these glob.js files and prints the globs that returned the expected result
  // this test finally compares the printed output of index.js with the list of directories with special chars,
  // expecting that they all work
  const files = await readdir(
    path.join(import.meta.dirname, '..', 'root', 'escape'),
    {
      withFileTypes: true,
    },
  )
  const expectedNames = files
    .filter((f) => f.isDirectory())
    .map((f) => `/escape/${f.name}/glob.js`)
    .sort()
  await expect
    .poll(async () => {
      const text = await page.textContent('.escape-relative')
      return text.split('\n').sort()
    })
    .toEqual(expectedNames)
  await expect
    .poll(async () => {
      const text = await page.textContent('.escape-alias')
      return text.split('\n').sort()
    })
    .toEqual(expectedNames)
})

test('escape literal parenthesis in glob pattern', async () => {
  // https://github.com/vitejs/vite/issues/22166
  // Backslash-escaped parens must match literal "(" / ")" in both dev and build.
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.escape-literal-parenthesis')),
    )
    .toStrictEqual(['/escape/(parenthesis)/mod/index.js'])
})

test('subpath imports', async () => {
  await expect
    .poll(async () => await page.textContent('.subpath-imports'))
    .toMatch('bar foo')
})

test('subpath imports (sub dir)', async () => {
  await expect
    .poll(async () => await page.textContent('.subpath-imports-sub-dir'))
    .toMatch('bar foo')
})

test('#alias imports', async () => {
  await expect
    .poll(async () => await page.textContent('.hash-alias-imports'))
    .toMatch('bar foo')
})

test('import base glob raw', async () => {
  await expect
    .poll(async () => await page.textContent('.result-base'))
    .toBe(JSON.stringify(baseRawResult, null, 2))
})

test('import.meta.glob and dynamic import vars transformations should be visible to post transform plugins', async () => {
  await expect
    .poll(async () => await page.textContent('.transform-visibility'))
    .toBe(
      JSON.stringify({ globTransformed: true, dynamicImportTransformed: true }),
    )
})

test('caseSensitiveMatch option', async () => {
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.case-sensitive-true')),
    )
    .toStrictEqual(['./case-sensitive-dir/data-test.js'])

  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.case-sensitive-false')),
    )
    .toStrictEqual([
      './case-sensitive-dir/DATA-other.js',
      './case-sensitive-dir/data-test.js',
    ])
})
test('absolute base with files outside of root', async () => {
  await expect
    .poll(async () =>
      JSON.parse(await page.textContent('.absolute-base-outside-root')),
    )
    .toStrictEqual({
      '../external/x.js': 'hello from x',
      '../external/y.js': 'hello from y',
    })
})


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

using json = nlohmann::json;

int main()
{
    // a JSON text
    auto text = R"(
    {
        "Image": {
            "Width":  800,
            "Height": 600,
            "Title":  "View from 15th Floor",
            "Thumbnail": {
                "Url":    "http://www.example.com/image/481989943",
                "Height": 125,
                "Width":  100
            },
            "Animated" : false,
            "IDs": [116, 943, 234, 38793]
        }
    }
    )";

    // parse and serialize JSON
    json j_complete = json::parse(text);
    std::cout << std::setw(4) << j_complete << "\n\n";

    // define parser callback
    json::parser_callback_t cb = [](int depth, json::parse_event_t event, json & parsed)
    {
        // skip object elements with key "Thumbnail"
        if (event == json::parse_event_t::key and parsed == json("Thumbnail"))
        {
            return false;
        }
        else
        {
            return true;
        }
    };

    // parse (with callback) and serialize JSON
    json j_filtered = json::parse(text, cb);
    std::cout << std::setw(4) << j_filtered << '\n';
}


use crate::lib::*;

#[cfg(any(feature = "std", feature = "alloc"))]
#[doc(hidden)]
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> {
    String::from_utf8_lossy(bytes)
}

// The generated code calls this like:
//
//     let value = &_serde::__private::from_utf8_lossy(bytes);
//     Err(_serde::de::Error::unknown_variant(value, VARIANTS))
//
// so it is okay for the return type to be different from the std case as long
// as the above works.
#[cfg(not(any(feature = "std", feature = "alloc")))]
#[doc(hidden)]
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
    // Three unicode replacement characters if it fails. They look like a
    // white-on-black question mark. The user will recognize it as invalid
    // UTF-8.
    str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
}


# Modules

This library has experimental support for C++ modules, introduced in C++20. The library can be imported by writing `import nlohmann.json;` instead of `#include <nlohmann/json.hpp>`.

Please be aware that the module is experimental and a full test is outstanding, and the exported symbols are subject to change.

## Requirements
The `nlohmann.json` module requires that the build system is configured to build and resolve modules when imported. Obviously, as modules were introduced in C++20, this feature can only be used in C++20 and subsequent versions.

To enable building the `nlohmann.json` module (which is not done by default), the macro `NLOHMANN_JSON_BUILD_MODULES` must be passed to the build system.

## Example
When using modules rather than headers, the previous example for creating a `json` object through a JSON file, would instead be:
```cpp
import std;
import nlohmann.json;

using json = nlohmann::json;

// ...

std::ifstream f("example.json");
json data = json::parse(f);
```

## Modules do not export macros
It should be noted that as modules do not export macros, the `nlohmann.json` module will not export any macros.

## Exported symbols

Only the following symbols are exported from `nlohmann.json`:

- `nlohmann::adl_serializer`
- `nlohmann::basic_json`
- `nlohmann::json`
- `nlohmann::json_pointer`
- `nlohmann::ordered_json`
- `nlohmann::ordered_map`
- `nlohmann::to_string`
- `nlohmann::literals::json_literals::operator""_json`
- `nlohmann::literals::json_literals::operator""_json_pointer`

Additionally, the following `nlohmann::detail` symbols are exported, solely to work around an MSVC compilation issue
([#3970](https://github.com/nlohmann/json/issues/3970)). They are implementation details, not part of the public API,
and should not be used directly:

- `nlohmann::detail::json_sax_dom_callback_parser`
- `nlohmann::detail::unknown_size`

## Known issues

C++20 modules support is exercised in CI against current GCC and Clang on Ubuntu, and the default MSVC toolset on Windows Server 2022 — there is no documented minimum compiler version, unlike feature-test-macro-gated features such as [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md).

!!! info "Known compiler issues"

    - **GCC** may emit "redefinition" errors when `#include <nlohmann/json.hpp>` appears in a module preamble together with other imports. This is an upstream GCC bug, not yet resolved as of GCC 16. Workarounds: include `nlohmann/json.hpp` before other `#include`s, use `import nlohmann.json;` instead, or upgrade GCC. ([issue #5103](https://github.com/nlohmann/json/issues/5103))
    - **MSVC** could fail with `C2039: 'json_sax_dom_callback_parser' is not a member of ... detail`; fixed by exporting the required internal symbols from `json.cppm` (see [Exported symbols](#exported-symbols) above). ([issue #3970](https://github.com/nlohmann/json/issues/3970))

    If you hit a different module-related build failure, search [existing issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+modules) before filing a new one.


# JSON Pointer

## Introduction

The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as an alternative means to
address structured values. A JSON Pointer is a string that identifies a specific value within a JSON document.

Consider the following JSON document

```json
{
    "array": ["A", "B", "C"],
    "nested": {
        "one": 1,
        "two": 2,
        "three": [true, false]
    }
}
```

Then every value inside the JSON document can be identified as follows:

| JSON Pointer      | JSON value                                                                       |
|-------------------|----------------------------------------------------------------------------------|
| ``                | `#!json {"array":["A","B","C"],"nested":{"one":1,"two":2,"three":[true,false]}}` |
| `/array`          | `#!json ["A","B","C"]`                                                           |
| `/array/0`        | `#!json A`                                                                       |
| `/array/1`        | `#!json B`                                                                       |
| `/array/2`        | `#!json C`                                                                       |
| `/nested`         | `#!json {"one":1,"two":2,"three":[true,false]}`                                  |
| `/nested/one`     | `#!json 1`                                                                       |
| `/nested/two`     | `#!json 2`                                                                       |
| `/nested/three`   | `#!json [true,false]`                                                            |
| `/nested/three/0` | `#!json true`                                                                    |
| `/nested/three/1` | `#!json false`                                                                   |

Note `/` does not identify the root (i.e., the whole document), but an object entry with empty key `""`. See
[RFC 6901](https://tools.ietf.org/html/rfc6901) for more information.

## JSON Pointer creation

JSON Pointers can be created from a string:

```cpp
json::json_pointer p("/nested/one");
```

Furthermore, a user-defined string literal can be used to achieve the same result:

```cpp
auto p = "/nested/one"_json_pointer;
```

The escaping rules of [RFC 6901](https://tools.ietf.org/html/rfc6901) are implemented. See the
[constructor documentation](../api/json_pointer/json_pointer.md) for more information.

## Value access

JSON Pointers can be used in the [`at`](../api/basic_json/at.md), [`operator[]`](../api/basic_json/operator%5B%5D.md),
and [`value`](../api/basic_json/value.md) functions just like object keys or array indices.

```cpp
// the JSON value from above
auto j = json::parse(R"({
    "array": ["A", "B", "C"],
    "nested": {
        "one": 1,
        "two": 2,
        "three": [true, false]
    }
})");

// access values
auto val = j[""_json_pointer];                              // {"array":["A","B","C"],...}
auto val1 = j["/nested/one"_json_pointer];                  // 1
auto val2 = j.at(json::json_pointer("/nested/three/1"));    // false
auto val3 = j.value(json::json_pointer("/nested/four"), 0); // 0
```

!!! note "Creating intermediate levels that don't exist"

    See the [`operator[]` notes](../api/basic_json/operator%5B%5D.md#return-value) for how array vs. object is
    decided when a pointer creates intermediate levels that don't exist yet.

## Flatten / unflatten

The library implements a function [`flatten`](../api/basic_json/flatten.md) to convert any JSON document into a JSON
object where each key is a JSON Pointer and each value is a primitive JSON value (i.e., a string, boolean, number, or
null).

```cpp
// the JSON value from above
auto j = json::parse(R"({
    "array": ["A", "B", "C"],
    "nested": {
        "one": 1,
        "two": 2,
        "three": [true, false]
    }
})");

// create flattened value
auto j_flat = j.flatten();
```

The resulting value `j_flat` is:

```json
{
  "/array/0": "A",
  "/array/1": "B",
  "/array/2": "C",
  "/nested/one": 1,
  "/nested/two": 2,
  "/nested/three/0": true,
  "/nested/three/1": false
}
```

The reverse function, [`unflatten`](../api/basic_json/unflatten.md) recreates the original value.

```cpp
auto j_original = j_flat.unflatten();
```

## See also

- Class [`json_pointer`](../api/json_pointer/index.md)
- Function [`flatten`](../api/basic_json/flatten.md)
- Function [`unflatten`](../api/basic_json/unflatten.md)
- [JSON Patch](json_patch.md)


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

/*
This file implements a parser test suitable for fuzz testing. Given a byte
array data, it performs the following steps:

- j1 = from_cbor(data)
- vec = to_cbor(j1)
- j2 = from_cbor(vec)
- assert(j1 == j2)

The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
drivers.
*/

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

using json = nlohmann::json;

// see http://llvm.org/docs/LibFuzzer.html
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    try
    {
        // step 1: parse input
        std::vector<uint8_t> const vec1(data, data + size);
        json const j1 = json::from_cbor(vec1);

        try
        {
            // step 2: round trip
            std::vector<uint8_t> const vec2 = json::to_cbor(j1);

            // parse serialization
            json const j2 = json::from_cbor(vec2);

            // serializations must match
            assert(json::to_cbor(j2) == vec2);
        }
        catch (const json::parse_error&)
        {
            // parsing a CBOR serialization must not fail
            assert(false);
        }
    }
    catch (const json::parse_error&)
    {
        // parse errors are ok, because input may be random bytes
    }
    catch (const json::type_error&)
    {
        // type errors can occur during parsing, too
    }
    catch (const json::out_of_range&)
    {
        // out of range errors can occur during parsing, too
    }

    // return 0 - non-zero return values are reserved for future use
    return 0;
}


import { expect, test } from 'vitest'
import { tests } from './tests'
import { page } from '~utils'

test('module type should be supported', async () => {
  expect(await page.textContent('#module-type-json-pre')).toBe('json')
  expect(await page.textContent('#module-type-json-post')).toBe('js')
  expect(await page.textContent('#module-type-json-virtual-pre')).toBe('json')
  expect(await page.textContent('#module-type-json-virtual-post')).toBe('js')
})

test('lazy hook filter should be applied', async () => {
  expect(await page.textContent('#lazy-hook-filter')).toBe('success')
})

tests()


// verifies `import.meta.hot.data` persists across HMR updates (#23001)
const data = import.meta.hot?.data ?? {}

// direct mutation: must survive each update, so `count` keeps climbing
data.count = (data.count ?? 0) + 1
text('.data-count', data.count)

// written by the dispose callback below: proves the disposer is handed the
// *existing* data object rather than a freshly allocated one
text('.data-disposed', data.disposed ?? 0)

if (import.meta.hot) {
  import.meta.hot.dispose((prev) => {
    prev.disposed = (prev.disposed ?? 0) + 1
  })
  import.meta.hot.accept()
}

globalThis.__hmrBump = 'initial'

function text(el, value) {
  document.querySelector(el).textContent = String(value)
}


<button id="test-error">Test error</button>
<button id="test-unhandledrejection">Test unhandledrejection</button>
<button id="test-console-error">Test console.error</button>
<button id="test-dep-error">Test dependency error</button>
<script type="module" src="/src/main.ts"></script>


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

```cpp
// (1)
template<typename InputType>
static basic_json from_msgpack(InputType&& i,
                               const bool strict = true,
                               const bool allow_exceptions = true);
// (2)
template<typename IteratorType, typename SentinelType = IteratorType>
static basic_json from_msgpack(IteratorType first, SentinelType last,
                               const bool strict = true,
                               const bool allow_exceptions = true);
```

Deserializes a given input to a JSON value using the MessagePack serialization format.

1. Reads from a compatible input.
2. Reads from an iterator range, or an iterator and a sentinel of a different type (C++20 ranges support).

The exact mapping and its limitations are described on a [dedicated page](../../features/binary_formats/messagepack.md).

## Template parameters

`InputType`
:   A compatible input, for instance:

    - an `std::istream` object
    - a `FILE` pointer
    - a C-style array of characters
    - a pointer to a null-terminated string of single byte characters
    - a container `obj` for which `begin(obj)` and `end(obj)` produce a valid pair of iterators
      (as found via ADL or member functions, with semantics compatible to `std::begin` and `std::end`)

`IteratorType`
:   a compatible iterator type

`SentinelType`
:   defaults to `IteratorType`; may be a different type comparable to `IteratorType` via `operator!=`, for instance.

    - a custom sentinel type for C++20 ranges
    - `std::default_sentinel_t`, when `IteratorType` is `std::counted_iterator`

## Parameters

`i` (in)
:   an input in MessagePack format convertible to an input adapter

`first` (in)
:   iterator to the start of the input

`last` (in)
:   iterator to the end of the input, or a sentinel value that compares equal to the end iterator with `operator!=`

`strict` (in)
:   whether to expect the input to be consumed until EOF (`#!cpp true` by default)

`allow_exceptions` (in)
:   whether to throw exceptions in case of a parse error (optional, `#!cpp true` by default)

## Return value

deserialized JSON value; in case of a parse error and `allow_exceptions` set to `#!cpp false`, the return value will be
`value_t::discarded`. The latter can be checked with [`is_discarded`](is_discarded.md).

## Exception safety

Strong guarantee: if an exception is thrown, there are no changes in the JSON value.

## Exceptions

- Throws [parse_error.110](../../home/exceptions.md#jsonexceptionparse_error110) if the given input ends prematurely or
  the end of the file was not reached when `strict` was set to true
- Throws [parse_error.112](../../home/exceptions.md#jsonexceptionparse_error112) if unsupported features from
  MessagePack were used in the given input or if the input is not valid MessagePack
- Throws [parse_error.113](../../home/exceptions.md#jsonexceptionparse_error113) if a string was expected as a map key,
  but not found

## Complexity

Linear in the size of the input.

## Examples

??? example

    The example shows the deserialization of a byte vector in MessagePack format to a JSON value.

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

    Output:

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

## See also

- [to_msgpack](to_msgpack.md) create a MessagePack serialization of a JSON value
- [from_cbor](from_cbor.md) create a JSON value from an input in CBOR format
- [from_bson](from_bson.md) create a JSON value from an input in BSON format
- [from_ubjson](from_ubjson.md) create a JSON value from an input in UBJSON format
- [from_bjdata](from_bjdata.md) create a JSON value from an input in BJData format

## Version history

- Added in version 2.0.9.
- Parameter `start_index` since version 2.1.1.
- Changed to consume input adapters, removed `start_index` parameter, and added `strict` parameter in version 3.0.0.
- Added `allow_exceptions` parameter in version 3.2.0.
- Extended container support (1) to include types with lvalue-only ADL `begin`/`end` (matching `std::begin`/`std::end` semantics) in version 3.13.0.
- Extended overload (2) to accept heterogeneous iterator+sentinel pairs (C++20 ranges support) in version 3.13.0.

!!! warning "Deprecation"

    - Overload (2) replaces calls to `from_msgpack` with a pointer and a length as first two parameters, which has been
      deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
      `#!cpp from_msgpack(ptr, len, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`.
    - Overload (2) replaces calls to `from_msgpack` with a pair of iterators as their first parameter, which has been
      deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like
      `#!cpp from_msgpack({ptr, ptr+len}, ...);` with `#!cpp from_msgpack(ptr, ptr+len, ...);`.

    You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated
    function.


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

// relative paths in `assetsInclude` are resolved against the current working
// directory. The tests run with a different cwd, so change it to the config
// directory to align with running Vite from the project root.
process.chdir(import.meta.dirname)

export default defineConfig({
  base: '/foo/bar',
  publicDir: 'static',
  resolve: {
    alias: {
      '@': path.resolve(import.meta.dirname, 'nested'),
      fragment: path.resolve(import.meta.dirname, 'nested/fragment-bg.svg'),
    },
  },
  assetsInclude: ['**/*.unknown', './nested/*.custom'],
  build: {
    outDir: 'dist/foo',
    assetsInlineLimit: 8000, // 8 kB
    manifest: true,
    watch: {},
  },
})


# Governance

The governance model for the JSON for Modern C++ project is a **Benevolent Dictator for Life (BDFL)** structure. As the
sole maintainer, [Niels Lohmann](https://github.com/nlohmann) is responsible for all key aspects of the project. The
project governance may evolve as the project grows, but any changes will be documented here and communicated to
contributors.

## Overview

This project is led by a benevolent dictator, [Niels Lohmann](https://github.com/nlohmann), and managed by the
community. That is, the community actively contributes to the day-to-day maintenance of the project, but the general
strategic line is drawn by the benevolent dictator. In case of disagreement, they have the last word. It is the
benevolent dictator’s job to resolve disputes within the community and to ensure that the project is able to progress in
a coordinated way. In turn, it is the community’s job to guide the decisions of the benevolent dictator through active
engagement and contribution.

## Roles and responsibilities

### Benevolent dictator (project lead)

Typically, the benevolent dictator, or project lead, is self-appointed. However, because the community always has the
ability to fork, this person is fully answerable to the community. The project lead’s role is a difficult one: they set
the strategic objectives of the project and communicate these clearly to the community. They also have to understand the
community as a whole and strive to satisfy as many conflicting needs as possible, while ensuring that the project
survives in the long term.

In many ways, the role of the benevolent dictator is less about dictatorship and more about diplomacy. The key is to
ensure that, as the project expands, the right people are given influence over it and the community rallies behind the
vision of the project lead. The lead’s job is then to ensure that the committers (see below) make the right decisions on
behalf of the project. Generally speaking, as long as the committers are aligned with the project’s strategy, the
project lead will allow them to proceed as they desire.

### Committers

Committers are contributors who have made several valuable contributions to the project and are now relied upon to both
write code directly to the repository and screen the contributions of others. In many cases they are programmers but it
is also possible that they contribute in a different role. Typically, a committer will focus on a specific aspect of the
project, and will bring a level of expertise and understanding that earns them the respect of the community and the
project lead. The role of committer is not an official one, it is simply a position that influential members of the
community will find themselves in as the project lead looks to them for guidance and support.

Committers have no authority over the overall direction of the project. However, they do have the ear of the project
lead. It is a committer’s job to ensure that the lead is aware of the community’s needs and collective objectives, and
to help develop or elicit appropriate contributions to the project. Often, committers are given informal control over
their specific areas of responsibility, and are assigned rights to directly modify certain areas of the source code.
That is, although committers do not have explicit decision-making authority, they will often find that their actions are
synonymous with the decisions made by the lead.

### Contributors

Contributors are community members who either have no desire to become committers, or have not yet been given the
opportunity by the benevolent dictator. They make valuable contributions, such as those outlined in the list below, but
generally do not have the authority to make direct changes to the project code. Contributors engage with the project
through communication tools, such as email lists, and via reports and patches attached to issues in the issue tracker,
as detailed in our community tools document.

Anyone can become a contributor. There is no expectation of commitment to the project, no specific skill requirements
and no selection process. To become a contributor, a community member simply has to perform one or more actions that are
beneficial to the project.

Some contributors will already be engaging with the project as users, but will also find themselves doing one or more of
the following:

- supporting new users (current users often provide the most effective new user support)
- reporting bugs
- identifying requirements
- supplying graphics and web design
- programming
- assisting with project infrastructure
- writing documentation
- fixing bugs
- adding features

As contributors gain experience and familiarity with the project, they may find that the project lead starts relying on
them more and more. When this begins to happen, they gradually adopt the role of committer, as described above.

### Users

Users are community members who have a need for the project. They are the most important members of the community:
without them, the project would have no purpose. Anyone can be a user; there are no specific requirements.

Users should be encouraged to participate in the life of the project and the community as much as possible. User
contributions enable the project team to ensure that they are satisfying the needs of those users. Common user
activities include (but are not limited to):

- evangelising about the project
- informing developers of project strengths and weaknesses from a new user’s perspective
- providing moral support (a ‘thank you’ goes a long way)
- providing financial support

Users who continue to engage with the project and its community will often find themselves becoming more and more
involved. Such users may then go on to become contributors, as described above.

## Support

All participants in the community are encouraged to provide support for new users within the project management
infrastructure. This support is provided as a way of growing the community. Those seeking support should recognise that
all support activity within the project is voluntary and is therefore provided as and when time allows. A user requiring
guaranteed response times or results should therefore seek to purchase a support contract from a vendor. (Of course,
that vendor should be an active member of the community.) However, for those willing to engage with the project on its
own terms, and willing to help support other users, the community support channels are ideal.

## Contribution Process

Anyone can contribute to the project, regardless of their skills, as there are many ways to contribute. For instance, a
contributor might be active on the project mailing list and issue tracker, or might supply patches. The various ways of
contributing are described in more detail in our roles in open source document.

The developer mailing list is the most appropriate place for a contributor to ask for help when making their first
contribution.

## Decision-Making Process

The benevolent dictatorship model does not need a formal conflict resolution process, since the project lead’s word is
final. If the community chooses to question the wisdom of the actions of a committer, the project lead can review their
decisions by checking the email archives, and either uphold or reverse them.

---

!!! quote "Source"

    The text was taken from http://oss-watch.ac.uk/resources/benevolentdictatorgovernancemodel.


grep-matcher
------------
This crate provides a low level interface for describing regular expression
matchers. The `grep` crate uses this interface in order to make the regex
engine it uses pluggable.

[![Build status](https://github.com/BurntSushi/ripgrep/workflows/ci/badge.svg)](https://github.com/BurntSushi/ripgrep/actions)
[![](https://img.shields.io/crates/v/grep-matcher.svg)](https://crates.io/crates/grep-matcher)

Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).

### Documentation

[https://docs.rs/grep-matcher](https://docs.rs/grep-matcher)

**NOTE:** You probably don't want to use this crate directly. Instead, you
should prefer the facade defined in the
[`grep`](https://docs.rs/grep)
crate.

### Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
grep-matcher = "0.1"
```


<!doctype html>

    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="src/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>


import { cleanUrl, isWindows, slash, unwrapId } from '../shared/utils'
import { SOURCEMAPPING_URL } from '../shared/constants'
import { decodeBase64 } from './utils'
import { DecodedMap } from './sourcemap/decoder'
import type { ResolvedResult } from './types'

const MODULE_RUNNER_SOURCEMAPPING_REGEXP = new RegExp(
  `//# ${SOURCEMAPPING_URL}=data:application/json;base64,(.+)`,
)

export class EvaluatedModuleNode {
  public importers: Set<string> = new Set()
  public imports: Set<string> = new Set()
  public evaluated = false
  public meta: ResolvedResult | undefined
  public promise: Promise<any> | undefined
  public exports: any
  public file: string
  public map: DecodedMap | undefined

  constructor(
    public id: string,
    public url: string,
  ) {
    this.file = cleanUrl(id)
  }
}

export class EvaluatedModules {
  public readonly idToModuleMap: Map<string, EvaluatedModuleNode> = new Map()
  public readonly fileToModulesMap: Map<string, Set<EvaluatedModuleNode>> =
    new Map()
  public readonly urlToIdModuleMap: Map<string, EvaluatedModuleNode> = new Map()

  /**
   * Returns the module node by the resolved module ID. Usually, module ID is
   * the file system path with query and/or hash. It can also be a virtual module.
   *
   * Module runner graph will have 1 to 1 mapping with the server module graph.
   * @param id Resolved module ID
   */
  public getModuleById(id: string): EvaluatedModuleNode | undefined {
    return this.idToModuleMap.get(id)
  }

  /**
   * Returns all modules related to the file system path. Different modules
   * might have different query parameters or hash, so it's possible to have
   * multiple modules for the same file.
   * @param file The file system path of the module
   */
  public getModulesByFile(file: string): Set<EvaluatedModuleNode> | undefined {
    return this.fileToModulesMap.get(file)
  }

  /**
   * Returns the module node by the URL that was used in the import statement.
   * Unlike module graph on the server, the URL is not resolved and is used as is.
   * @param url Server URL that was used in the import statement
   */
  public getModuleByUrl(url: string): EvaluatedModuleNode | undefined {
    return this.urlToIdModuleMap.get(unwrapId(url))
  }

  /**
   * Ensure that module is in the graph. If the module is already in the graph,
   * it will return the existing module node. Otherwise, it will create a new
   * module node and add it to the graph.
   * @param id Resolved module ID
   * @param url URL that was used in the import statement
   */
  public ensureModule(id: string, url: string): EvaluatedModuleNode {
    id = normalizeModuleId(id)
    if (this.idToModuleMap.has(id)) {
      const moduleNode = this.idToModuleMap.get(id)!
      this.urlToIdModuleMap.set(url, moduleNode)
      return moduleNode
    }
    const moduleNode = new EvaluatedModuleNode(id, url)
    this.idToModuleMap.set(id, moduleNode)
    this.urlToIdModuleMap.set(url, moduleNode)

    const fileModules = this.fileToModulesMap.get(moduleNode.file) || new Set()
    fileModules.add(moduleNode)
    this.fileToModulesMap.set(moduleNode.file, fileModules)
    return moduleNode
  }

  public invalidateModule(node: EvaluatedModuleNode): void {
    node.evaluated = false
    node.meta = undefined
    node.map = undefined
    node.promise = undefined
    node.exports = undefined
    // remove imports in case they are changed,
    // don't remove the importers because otherwise it will be empty after evaluation
    // this can create a bug when file was removed but it still triggers full-reload
    // we are fine with the bug for now because it's not a common case
    node.imports.clear()
  }

  /**
   * Extracts the inlined source map from the module code and returns the decoded
   * source map. If the source map is not inlined, it will return null.
   * @param id Resolved module ID
   */
  getModuleSourceMapById(id: string): DecodedMap | null {
    const mod = this.getModuleById(id)
    if (!mod) return null
    if (mod.map) return mod.map
    if (!mod.meta || !('code' in mod.meta)) return null

    const pattern = `//# ${SOURCEMAPPING_URL}=data:application/json;base64,`
    const lastIndex = mod.meta.code.lastIndexOf(pattern)
    if (lastIndex === -1) return null

    const mapString = MODULE_RUNNER_SOURCEMAPPING_REGEXP.exec(
      mod.meta.code.slice(lastIndex),
    )?.[1]
    if (!mapString) return null
    mod.map = new DecodedMap(JSON.parse(decodeBase64(mapString)), mod.file)
    return mod.map
  }

  public clear(): void {
    this.idToModuleMap.clear()
    this.fileToModulesMap.clear()
    this.urlToIdModuleMap.clear()
  }
}

// unique id that is not available as "$bare_import" like "test"
// https://nodejs.org/api/modules.html#built-in-modules-with-mandatory-node-prefix
const prefixedBuiltins = new Set([
  'node:sea',
  'node:sqlite',
  'node:test',
  'node:test/reporters',
])

// transform file url to id
// virtual:custom -> virtual:custom
// \0custom -> \0custom
// node:fs -> fs
// /@fs/C:/root/id.js => C:/root/id.js
// file:///C:/root/id.js -> C:/root/id.js
export function normalizeModuleId(file: string): string {
  if (prefixedBuiltins.has(file)) return file

  // unix style, but Windows path still starts with the drive letter to check the root
  const unixFile = slash(file)
    .replace(/^\/@fs\//, isWindows ? '' : '/')
    .replace(/^node:/, '')
    .replace(/^\/+/, '/')

  // if it's not in the root, keep it as a path, not a URL
  return unixFile.replace(/^file:\/+/, isWindows ? '' : '/')
}


import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: fileURLToPath(new URL('src/css-entry-1.js', import.meta.url)),
      name: 'css-single-entry',
    },
    outDir: 'dist/css-single-entry',
  },
})