From db23fcfe8d54b1b690d9101e4bf2a1058d473785 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 17 Mar 2024 19:50:10 +0000 Subject: [PATCH 01/20] initial commit --- deny.schema.json | 185 +++++++++++++++++++++++++++++++++++++ deny.schema.yml | 223 +++++++++++++++++++++++++++++++++++++++++++++ deny.template.toml | 2 + 3 files changed, 410 insertions(+) create mode 100644 deny.schema.json create mode 100644 deny.schema.yml diff --git a/deny.schema.json b/deny.schema.json new file mode 100644 index 00000000..3a4cbbdc --- /dev/null +++ b/deny.schema.json @@ -0,0 +1,185 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", + "title": "cargo-deny configuration file", + "description": "You can find the full documentation for the config file at https://embarkstudios.github.io/cargo-deny/checks/cfg.html\n", + "type": "object", + "properties": + { + "advisories": + { + "$ref": "#/definitions/advisories" + }, + "graph": + { + "$ref": "#/definitions/graph" + }, + "output": + { + "$ref": "#/definitions/output" + } + }, + "definitions": + { + "advisories": + { + "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found here:\nhttps://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html\n", + "type": "object", + "properties": + { + "db-urls": + { + "type": "array", + "items": + { + "type": "string", + "format": "uri" + }, + "description": "URLs to one or more advisory databases.\n\nDefault: [RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" + }, + "db-path": + { + "type": "string", + "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" + }, + "version": + { + "enum": + [ + 2 + ], + "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" + }, + "vulnerability": + { + "deprecated": true, + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n\n- `deny` (default) - Will emit an error with details about each vulnerability, and fail the check.\n- `warn` - Prints a warning for each vulnerability, but does not fail the check.\n- `allow` - Prints a note about the security vulnerability, but does not fail the check.\n" + }, + "unmaintained": + { + "deprecated": true, + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Will emit an error with details about the problem, and fail the check.", + "Prints a warning for each propblem, but does not fail the check.", + "Prints a note about the problem, but does not fail the check." + ] + } + }, + "description": "Determines what happens when a crate with an `unmaintained` advisory is encountered.\nDefault: warn\n" + } + } + }, + "graph": + { + "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", + "type": "object", + "properties": + { + "targets": + { + "type": "array", + "items": + { + "$ref": "#/definitions/target" + }, + "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```ini\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" + }, + "exclude": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" + }, + "all-features": + { + "type": "boolean", + "description": "If set to `true`, `--all-features` will be used when collecting metadata." + }, + "no-default-features": + { + "type": "boolean", + "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." + }, + "features": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" + }, + "exclude-dev": + { + "type": "boolean", + "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" + } + } + }, + "target": + { + "oneOf": + [ + { + "$ref": "#/definitions/target-triple" + }, + { + "$ref": "#/definitions/target-object" + } + ] + }, + "target-object": + { + "description": "Advanced configurations to apply for the target triple", + "type": "object", + "required": + [ + "triple" + ], + "properties": + { + "triple": + { + "$ref": "#/definitions/target-triple" + }, + "features": + { + "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" + } + } + }, + "target-triple": + { + "type": "string", + "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" + }, + "output": + { + "description": "The output table provides options for how/if diagnostics are outputted", + "type": "object", + "properties": + { + "feature-depth": + { + "type": "integer", + "minimum": 0, + "description": "The maximum depth that features will be displayed when inclusion graphs are included in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features. If not specified defaults to `1`.\n" + } + } + } + } +} \ No newline at end of file diff --git a/deny.schema.yml b/deny.schema.yml new file mode 100644 index 00000000..924b6461 --- /dev/null +++ b/deny.schema.yml @@ -0,0 +1,223 @@ +# yaml-language-server: $schema=https://json-schema.org/draft-07/schema# + +# Welcome to the JSON Schema for the `deny.toml` configuration file 🥰. +# This file is used to provide IDE completions and documentation for it. +# It is maintained by hand, and seves as the source of truth for the JSON schema. +# +# The schema is written in YAML since it permits comments, multi-line strings +# and generally is easier to write by humans directly. We convert it to JSON +# after edits and check the generated JSON file into the source control. +# CI validates for the freshness of the JSON version of this file. +# +# The schema uses 'draft-07' dialect of the JSON schema since this is the version +# that is supported by the YAML LSP in VSCode at least. There are newer versions +# of the JSON schema spec, and we use some of the features of the newer specs, +# but our goal is to be ultimately compatible with the 'draft-04' version of the +# spec, which is supported by "Even Better TOML" VSCode extension (taplo): +# https://taplo.tamasfe.dev/configuration/developing-schemas.html. This is likely +# the extension people use when authoring `deny.toml` config files in VSCode. +# +# For example, the `deprecated` property is available only since '2020-12' version +# of the spec. It isn't available in the 'draft-04' and 'draft-07' versions, but we +# still use it since extra properties don't break compatibility and there may +# be other TOML LSPs that support newer versions of the JSON schema spec or +# existing ones may be updated to support newer versions + +$schema: https://json-schema.org/draft-07/schema# + +$id: https://github.com/EmbarkStudios/cargo-deny/deny.schema.json + +title: cargo-deny configuration file +description: > + You can find the full documentation for the config file at + https://embarkstudios.github.io/cargo-deny/checks/cfg.html + +type: object +properties: + advisories: { $ref: '#/definitions/advisories' } + graph: { $ref: '#/definitions/graph' } + output: { $ref: '#/definitions/output' } + +definitions: + advisories: + description: | + This section is considered when running `cargo deny check advisories` + More documentation for the advisories section can be found here: + https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html + + type: object + properties: + db-urls: + type: array + items: { type: string, format: uri } + description: | + URLs to one or more advisory databases. + + Default: [RustSec Advisory DB](https://github.com/RustSec/advisory-db) + + db-path: + type: string + description: | + Path to the root directory into which one or more advisory databases are cloned into. + + This value supports basic shell expansion: + + - `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) + - `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + - `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + - `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + or the fallback value if it doesn't exist (everything between the `:-` and `}`) + - `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + if it exists, otherwise expands to `$(home::home_dir())/.cargo` + + Note that the path must be valid utf-8, after expansion. + + Default: `$CARGO_HOME/advisory-dbs` + + version: + enum: [2] + description: | + The advisories section has an upcoming breaking change, with deprecation warnings for several + fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + + The breaking change is as follows: + + - `vulnerability` - Removed, all vulnerability advisories now emit errors. + - `unmaintained` - Removed, all unmaintained advisories now emit errors. + - `unsound` - Removed, all unsound advisories now emit errors. + - `notice` - Removed, all notice advisories now emit errors. + - `severity-threshold` - Removed, all vulnerability advisories now emit errors. + + As before, if you want to ignore a specific advisory, add it to the `ignore` field. + + vulnerability: + deprecated: true + description: | + **DEPRECATED** (see `version` field) + + Determines what happens when a crate with a security vulnerability is encountered. + + - `deny` (default) - Will emit an error with details about each vulnerability, and fail the check. + - `warn` - Prints a warning for each vulnerability, but does not fail the check. + - `allow` - Prints a note about the security vulnerability, but does not fail the check. + + unmaintained: + deprecated: true + enum: [deny, warn, allow] + x-taplo: + docs: + enumValues: + - Will emit an error with details about the problem, and fail the check. + - Prints a warning for each propblem, but does not fail the check. + - Prints a note about the problem, but does not fail the check. + description: | + Determines what happens when a crate with an `unmaintained` advisory is encountered. + Default: warn + + graph: + description: | + The graph table configures how the dependency graph is constructed and thus which crates the + checks are performed against + + type: object + properties: + targets: + type: array + items: { $ref: '#/definitions/target' } + description: | + By default, cargo-deny will consider every single crate that is resolved by cargo, including + target specific dependencies e.g. + + ```ini + [target.x86_64-pc-windows-msvc.dependencies] + winapi = "0.3.8" + + [target.'cfg(target_os = "fuchsia")'.dependencies] + fuchsia-cprng = "0.1.1" + ``` + + But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is + never actually going to be compiled or linked into your project, so checking it is pointless for you. + + The `targets` field allows you to specify one or more targets which you **actually** build for. + Every dependency link to a crate is checked against this list, and if none of the listed targets + satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links + to it, it is not included into the crate graph that the checks are + executed against. + + exclude: + type: array + items: { type: string } + description: | + Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) + that will cause the crate(s) in question to be excluded from the crate graph that is used + for the operation you are performing. + + Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced + via the excluded crate, they will also be excluded from the crate graph. + + all-features: + type: boolean + description: If set to `true`, `--all-features` will be used when collecting metadata. + + no-default-features: + type: boolean + description: If set to `true`, `--no-default-features` will be used when collecting metadata. + + features: + type: array + items: { type: string } + description: | + If set, and `--features` is not specified on the cmd line, these features will be used when + collecting metadata. + + exclude-dev: + type: boolean + description: | + If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included + in the crate graph used for any of the checks. This option can also be enabled on cmd line + with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) + the `check` subcommand. + + target: + oneOf: + - $ref: '#/definitions/target-triple' + - $ref: '#/definitions/target-object' + + target-object: + description: Advanced configurations to apply for the target triple + type: object + required: [triple] + properties: + triple: { $ref: '#/definitions/target-triple' } + features: + description: | + Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) + predicate, but at the moment, the only way to actually pass them when compiling is to use + the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more + `target_feature`s you plan to build with, for a particular target triple. At the time of + this writing, cargo-deny does not attempt to validate that the features you specify are + actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). + + target-triple: + type: string + description: | + The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target + you wish to filter target specific dependencies with. If the target triple specified is **not** + one of the targets builtin to `rustc`, the configuration check for that target will be limited + to only the raw `[target..dependencies]` style of target configuration, as `cfg()` + expressions require us to know the details about the target. + + output: + description: The output table provides options for how/if diagnostics are outputted + type: object + properties: + feature-depth: + type: integer + minimum: 0 + description: | + The maximum depth that features will be displayed when inclusion graphs are included in + diagnostics, unless specified via `--feature-depth` on the command line. Only applies to + diagnostics that actually print features. If not specified defaults to `1`. diff --git a/deny.template.toml b/deny.template.toml index f38a8f23..700e4082 100644 --- a/deny.template.toml +++ b/deny.template.toml @@ -1,3 +1,5 @@ +#:schema ./deny.schema.json + # This template contains all of the possible sections and their default values # Note that all fields that take a lint level have these possible values: From cda29f70c06857d6ce4eb24c2156e9da20e03fb7 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 18 Mar 2024 21:53:42 +0000 Subject: [PATCH 02/20] Next iteratio --- deny.schema.yml | 196 ++++++++++++++++++++++--- deny.template.toml | 13 +- deny.schema.json => deny15.schema.json | 175 +++++++++++++++++++--- 3 files changed, 338 insertions(+), 46 deletions(-) rename deny.schema.json => deny15.schema.json (51%) diff --git a/deny.schema.yml b/deny.schema.yml index 924b6461..492fa06b 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -22,15 +22,16 @@ # still use it since extra properties don't break compatibility and there may # be other TOML LSPs that support newer versions of the JSON schema spec or # existing ones may be updated to support newer versions +# +# We also use some custom extensions by different TOML LSPs, such as `x-taplo` +# to provide better documentation. $schema: https://json-schema.org/draft-07/schema# $id: https://github.com/EmbarkStudios/cargo-deny/deny.schema.json title: cargo-deny configuration file -description: > - You can find the full documentation for the config file at - https://embarkstudios.github.io/cargo-deny/checks/cfg.html +description: Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html type: object properties: @@ -50,10 +51,8 @@ definitions: db-urls: type: array items: { type: string, format: uri } - description: | - URLs to one or more advisory databases. - - Default: [RustSec Advisory DB](https://github.com/RustSec/advisory-db) + default: [https://github.com/RustSec/advisory-db] + description: URLs to one or more advisory databases. db-path: type: string @@ -92,27 +91,181 @@ definitions: vulnerability: deprecated: true + oneOf: [{ $ref: '#/definitions/lint-level' }] + default: deny description: | **DEPRECATED** (see `version` field) Determines what happens when a crate with a security vulnerability is encountered. - - `deny` (default) - Will emit an error with details about each vulnerability, and fail the check. - - `warn` - Prints a warning for each vulnerability, but does not fail the check. - - `allow` - Prints a note about the security vulnerability, but does not fail the check. - unmaintained: deprecated: true - enum: [deny, warn, allow] - x-taplo: - docs: - enumValues: - - Will emit an error with details about the problem, and fail the check. - - Prints a warning for each propblem, but does not fail the check. - - Prints a note about the problem, but does not fail the check. + oneOf: [{ $ref: '#/definitions/lint-level' }] + default: warn description: | + **DEPRECATED** (see `version` field) + Determines what happens when a crate with an `unmaintained` advisory is encountered. - Default: warn + + unsound: + deprecated: true + oneOf: [{ $ref: '#/definitions/lint-level' }] + default: warn + description: | + **DEPRECATED** (see `version` field) + + Determines what happens when a crate with an `unsound` advisory is encountered. + + notice: + oneOf: [{ $ref: '#/definitions/lint-level' }] + default: warn + description: | + **DEPRECATED** (see `version` field) + + Determines what happens when a crate with a `notice` advisory is encountered. + + **NOTE**: As of 2019-12-17 there are no `notice` advisories in the + [RustSec Advisory DB](https://github.com/RustSec/advisory-db) + + yanked: + oneOf: [{ $ref: '#/definitions/lint-level' }] + default: warn + description: | + Determines what happens when a crate with a version that has been yanked from its source + registry is encountered. + + ignore: + type: array + items: { $ref: '#/definitions/advisories-ignore-item' } + + advisories-ignore-item: + oneOf: + - type: string + description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). + - { $ref: '#/definitions/ignore-advisory-object' } + - { $ref: '#/definitions/ignore-yanked-object' } + + description: | + ```toml + ignore = [ + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, + "yanked@0.1.1", + { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, + ] + ``` + + Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. + Putting an identifier in this array will cause the advisory to be treated as a note, rather + than a warning or error. + + In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + with an optional `reason`. + + ignore-advisory-object: + type: object + examples: [RUSTSEC-2019-0001] + required: [id] + properties: + id: + type: string + description: The unique identifier of the advisory to ignore + reason: { $ref: '#/definitions/ignore-reason' } + + ignore-yanked-object: + type: object + required: [crate] + properties: + crate: { $ref: '#/definitions/package-spec' } + reason: { $ref: '#/definitions/ignore-reason' } + + + ignore-reason: + type: string + description: Free-form string that can be used to describe the reason why the advisory is ignored. + + lint-level: + deprecated: true + enum: [deny, warn, allow] + x-taplo: + docs: + enumValues: + - Emit an error with details about the problem, and fail the check. + - Print a warning for each propblem, but don't fail the check. + - Print a note about the problem, but don't fail the check. + + package-spec: + type: string + description: | + Many configuration options require a package specifier at a minimum, which we'll describe here. + The options that use package specifiers will be called out in their individual documentation. + We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + + ### String format + + If the particular only requires a package spec at a minimum, then the string format can be used, + which comes in three forms. + + #### Simple + + ```toml + # Will match any version of the simple crate + deny = ["simple"] + ``` + + The simplest string is one which is just the crate name. In this case, the version requirement + used when checking will be `*` meaning it will match against all versions of that crate in the graph. + + #### With Version Requirements + + ```toml + # Will match only these versions of the simple crate that match the predicate(s) + deny = ["simple:<=0.1,>0.2"] + ``` + + If you want to apply version requirements (predicates) to the crate, simply append them following + a `:` separator. + + #### Exact + + ```toml + # Will match only this exact version of the simple crate + deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", + ] + ``` + + The exact form is a specialization of the version requirements, where the semver after the `@` + is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + + ### Table format + + #### Crate format + + ```toml + deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, + ] + ``` + + The crate format is a replacement for the old `name` and/or `version` table format. It uses + the string format described above in a single `crate` key. + + #### Old format + + ```toml + deny = [ + { name = "simple" }, + { name = "simple", version = "*" } + { name = "simple", wrappers = ["example"] } + ] + ``` + + The old format uses a required `name` key and an optional `version` key. This format is deprecated + and should not be used. graph: description: | @@ -128,7 +281,7 @@ definitions: By default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies e.g. - ```ini + ```toml [target.x86_64-pc-windows-msvc.dependencies] winapi = "0.3.8" @@ -217,7 +370,8 @@ definitions: feature-depth: type: integer minimum: 0 + default: 1 description: | The maximum depth that features will be displayed when inclusion graphs are included in diagnostics, unless specified via `--feature-depth` on the command line. Only applies to - diagnostics that actually print features. If not specified defaults to `1`. + diagnostics that actually print features. diff --git a/deny.template.toml b/deny.template.toml index 700e4082..dcaad1a8 100644 --- a/deny.template.toml +++ b/deny.template.toml @@ -1,4 +1,4 @@ -#:schema ./deny.schema.json +#:schema deny15.schema.json # This template contains all of the possible sections and their default values @@ -65,6 +65,7 @@ feature-depth = 1 # More documentation for the advisories section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html [advisories] + # The path where the advisory databases are cloned/fetched into #db-path = "$CARGO_HOME/advisory-dbs" # The url(s) of the advisory databases to use @@ -72,11 +73,13 @@ feature-depth = 1 # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - #"RUSTSEC-0000-0000", - #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, - #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish - #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, + "a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish + { crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, ] + + # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. diff --git a/deny.schema.json b/deny15.schema.json similarity index 51% rename from deny.schema.json rename to deny15.schema.json index 3a4cbbdc..c4c2eacd 100644 --- a/deny.schema.json +++ b/deny15.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft-07/schema#", "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", "title": "cargo-deny configuration file", - "description": "You can find the full documentation for the config file at https://embarkstudios.github.io/cargo-deny/checks/cfg.html\n", + "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", "type": "object", "properties": { @@ -35,7 +35,11 @@ "type": "string", "format": "uri" }, - "description": "URLs to one or more advisory databases.\n\nDefault: [RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" + "default": + [ + "https://github.com/RustSec/advisory-db" + ], + "description": "URLs to one or more advisory databases." }, "db-path": { @@ -53,33 +57,163 @@ "vulnerability": { "deprecated": true, - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n\n- `deny` (default) - Will emit an error with details about each vulnerability, and fail the check.\n- `warn` - Prints a warning for each vulnerability, but does not fail the check.\n- `allow` - Prints a note about the security vulnerability, but does not fail the check.\n" + "oneOf": + [ + { + "$ref": "#/definitions/lint-level" + } + ], + "default": "deny", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n" }, "unmaintained": { "deprecated": true, - "enum": + "oneOf": [ - "deny", - "warn", - "allow" + { + "$ref": "#/definitions/lint-level" + } ], - "x-taplo": - { - "docs": + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" + }, + "unsound": + { + "deprecated": true, + "oneOf": + [ { - "enumValues": - [ - "Will emit an error with details about the problem, and fail the check.", - "Prints a warning for each propblem, but does not fail the check.", - "Prints a note about the problem, but does not fail the check." - ] + "$ref": "#/definitions/lint-level" } - }, - "description": "Determines what happens when a crate with an `unmaintained` advisory is encountered.\nDefault: warn\n" + ], + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" + }, + "notice": + { + "oneOf": + [ + { + "$ref": "#/definitions/lint-level" + } + ], + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" + }, + "yanked": + { + "oneOf": + [ + { + "$ref": "#/definitions/lint-level" + } + ], + "default": "warn", + "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" + }, + "ignore": + { + "type": "array", + "items": + { + "$ref": "#/definitions/advisories-ignore-item" + } } } }, + "advisories-ignore-item": + { + "oneOf": + [ + { + "type": "string", + "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." + }, + { + "$ref": "#/definitions/ignore-advisory-object" + }, + { + "$ref": "#/definitions/ignore-yanked-object" + } + ], + "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" + }, + "ignore-advisory-object": + { + "type": "object", + "examples": + [ + "RUSTSEC-2019-0001" + ], + "required": + [ + "id" + ], + "properties": + { + "id": + { + "type": "string", + "description": "The unique identifier of the advisory to ignore" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "ignore-yanked-object": + { + "type": "object", + "required": + [ + "crate" + ], + "properties": + { + "crate": + { + "$ref": "#/definitions/package-spec" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "ignore-reason": + { + "type": "string", + "description": "Free-form string that can be used to describe the reason why the advisory is ignored." + }, + "lint-level": + { + "deprecated": true, + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "package-spec": + { + "type": "string", + "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" + }, "graph": { "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", @@ -93,7 +227,7 @@ { "$ref": "#/definitions/target" }, - "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```ini\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" + "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" }, "exclude": { @@ -177,7 +311,8 @@ { "type": "integer", "minimum": 0, - "description": "The maximum depth that features will be displayed when inclusion graphs are included in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features. If not specified defaults to `1`.\n" + "default": 1, + "description": "The maximum depth that features will be displayed when inclusion graphs are included in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" } } } From 6af2853ab1484622d6b62220c28824c46cd6a45b Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 23 Mar 2024 15:16:46 +0000 Subject: [PATCH 03/20] Start codegen for JSON schema --- Cargo.lock | 163 +++++++++++++- Cargo.toml | 5 + deny.schema.yml | 80 +++---- deny15.schema.json | 320 ---------------------------- xtask/Cargo.toml | 23 ++ xtask/src/cli.rs | 34 +++ xtask/src/cli/codegen.rs | 13 ++ xtask/src/cli/codegen/jsonschema.rs | 163 ++++++++++++++ xtask/src/entrypoint.rs | 28 +++ xtask/src/lib.rs | 4 + xtask/src/main.rs | 3 + 11 files changed, 472 insertions(+), 364 deletions(-) delete mode 100644 deny15.schema.json create mode 100644 xtask/Cargo.toml create mode 100644 xtask/src/cli.rs create mode 100644 xtask/src/cli/codegen.rs create mode 100644 xtask/src/cli/codegen/jsonschema.rs create mode 100644 xtask/src/entrypoint.rs create mode 100644 xtask/src/lib.rs create mode 100644 xtask/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index c302e2f3..0b019a0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata", + "regex-automata 0.4.6", "serde", ] @@ -254,7 +254,7 @@ dependencies = [ "insta", "krates", "log", - "nu-ansi-term", + "nu-ansi-term 0.50.0", "parking_lot", "rayon", "reqwest", @@ -1521,8 +1521,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", ] [[package]] @@ -1714,6 +1714,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1799,6 +1808,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "maybe-async" version = "0.2.10" @@ -1851,6 +1869,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.0" @@ -1915,6 +1943,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -2066,8 +2100,17 @@ checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -2078,9 +2121,15 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.2" @@ -2397,6 +2446,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -2414,6 +2476,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -2646,6 +2717,16 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.34" @@ -2792,9 +2873,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -2802,6 +2895,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term 0.46.0", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2859,6 +2982,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -2883,6 +3012,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.4" @@ -3196,6 +3331,20 @@ dependencies = [ "tap", ] +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "itertools", + "serde", + "serde_json", + "serde_yaml", + "tracing", + "tracing-subscriber", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 7ae4ac6c..48800ea5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ +[workspace] +members = ["xtask"] + [package] name = "cargo-deny" description = "Cargo plugin to help you manage large dependency graphs" @@ -20,10 +23,12 @@ rust-version = "1.70.0" [badges] maintenance = { status = "actively-developed" } + [[bin]] name = "cargo-deny" path = "src/cargo-deny/main.rs" + [features] default = ["reqwest/rustls-tls-webpki-roots", "tame-index/default"] # Enables the use of OS native certificate store. diff --git a/deny.schema.yml b/deny.schema.yml index 492fa06b..e84b09a8 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -43,8 +43,8 @@ definitions: advisories: description: | This section is considered when running `cargo deny check advisories` - More documentation for the advisories section can be found here: - https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html + More documentation for the advisories section can be found + [here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html) type: object properties: @@ -91,7 +91,7 @@ definitions: vulnerability: deprecated: true - oneOf: [{ $ref: '#/definitions/lint-level' }] + $ref: '#/definitions/lint-level' default: deny description: | **DEPRECATED** (see `version` field) @@ -100,7 +100,7 @@ definitions: unmaintained: deprecated: true - oneOf: [{ $ref: '#/definitions/lint-level' }] + $ref: '#/definitions/lint-level' default: warn description: | **DEPRECATED** (see `version` field) @@ -109,7 +109,7 @@ definitions: unsound: deprecated: true - oneOf: [{ $ref: '#/definitions/lint-level' }] + $ref: '#/definitions/lint-level' default: warn description: | **DEPRECATED** (see `version` field) @@ -117,7 +117,7 @@ definitions: Determines what happens when a crate with an `unsound` advisory is encountered. notice: - oneOf: [{ $ref: '#/definitions/lint-level' }] + $ref: '#/definitions/lint-level' default: warn description: | **DEPRECATED** (see `version` field) @@ -128,64 +128,70 @@ definitions: [RustSec Advisory DB](https://github.com/RustSec/advisory-db) yanked: - oneOf: [{ $ref: '#/definitions/lint-level' }] + $ref: '#/definitions/lint-level' default: warn description: | Determines what happens when a crate with a version that has been yanked from its source registry is encountered. + # x-taplo: + # docs: + # main: | + # Determines what happens when a crate with a version that has been yanked from its source + # registry is encountered. ignore: type: array items: { $ref: '#/definitions/advisories-ignore-item' } + description: | + ```toml + ignore = [ + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, + "yanked@0.1.1", + { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, + ] + ``` + + Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. + Putting an identifier in this array will cause the advisory to be treated as a note, rather + than a warning or error. + + In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + with an optional `reason`. advisories-ignore-item: oneOf: - type: string description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - - { $ref: '#/definitions/ignore-advisory-object' } - - { $ref: '#/definitions/ignore-yanked-object' } + - { $ref: '#/definitions/advisories-ignore-advisory' } + - { $ref: '#/definitions/advisories-ignore-yanked' } - description: | - ```toml - ignore = [ - "RUSTSEC-0000-0000", - { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, - "yanked@0.1.1", - { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, - ] - ``` - - Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. - Putting an identifier in this array will cause the advisory to be treated as a note, rather - than a warning or error. - - In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) - with an optional `reason`. - - ignore-advisory-object: + advisories-ignore-advisory: type: object - examples: [RUSTSEC-2019-0001] required: [id] properties: id: type: string + examples: [RUSTSEC-2019-0001] description: The unique identifier of the advisory to ignore reason: { $ref: '#/definitions/ignore-reason' } - ignore-yanked-object: + advisories-ignore-yanked: type: object required: [crate] properties: crate: { $ref: '#/definitions/package-spec' } reason: { $ref: '#/definitions/ignore-reason' } - ignore-reason: type: string description: Free-form string that can be used to describe the reason why the advisory is ignored. lint-level: - deprecated: true + # anyOf: + # - { const: deny, } # description: Emit an error with details about the problem, and fail the check. } + # - { const: warn, } # description: Print a warning for each propblem, but don't fail the check. } + # - { const: allow, } # description: Print a note about the problem, but don't fail the check. } enum: [deny, warn, allow] x-taplo: docs: @@ -336,15 +342,15 @@ definitions: target: oneOf: - - $ref: '#/definitions/target-triple' - - $ref: '#/definitions/target-object' + - $ref: '#/definitions/target-string' + - $ref: '#/definitions/target-complex' - target-object: + target-complex: description: Advanced configurations to apply for the target triple type: object required: [triple] properties: - triple: { $ref: '#/definitions/target-triple' } + triple: { $ref: '#/definitions/target-string' } features: description: | Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) @@ -354,7 +360,7 @@ definitions: this writing, cargo-deny does not attempt to validate that the features you specify are actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). - target-triple: + target-string: type: string description: | The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target @@ -372,6 +378,6 @@ definitions: minimum: 0 default: 1 description: | - The maximum depth that features will be displayed when inclusion graphs are included in + The maximum depth that features will be displayed when inclusion graphs are shown in diagnostics, unless specified via `--feature-depth` on the command line. Only applies to diagnostics that actually print features. diff --git a/deny15.schema.json b/deny15.schema.json deleted file mode 100644 index c4c2eacd..00000000 --- a/deny15.schema.json +++ /dev/null @@ -1,320 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft-07/schema#", - "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", - "title": "cargo-deny configuration file", - "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", - "type": "object", - "properties": - { - "advisories": - { - "$ref": "#/definitions/advisories" - }, - "graph": - { - "$ref": "#/definitions/graph" - }, - "output": - { - "$ref": "#/definitions/output" - } - }, - "definitions": - { - "advisories": - { - "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found here:\nhttps://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html\n", - "type": "object", - "properties": - { - "db-urls": - { - "type": "array", - "items": - { - "type": "string", - "format": "uri" - }, - "default": - [ - "https://github.com/RustSec/advisory-db" - ], - "description": "URLs to one or more advisory databases." - }, - "db-path": - { - "type": "string", - "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" - }, - "version": - { - "enum": - [ - 2 - ], - "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" - }, - "vulnerability": - { - "deprecated": true, - "oneOf": - [ - { - "$ref": "#/definitions/lint-level" - } - ], - "default": "deny", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n" - }, - "unmaintained": - { - "deprecated": true, - "oneOf": - [ - { - "$ref": "#/definitions/lint-level" - } - ], - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" - }, - "unsound": - { - "deprecated": true, - "oneOf": - [ - { - "$ref": "#/definitions/lint-level" - } - ], - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" - }, - "notice": - { - "oneOf": - [ - { - "$ref": "#/definitions/lint-level" - } - ], - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" - }, - "yanked": - { - "oneOf": - [ - { - "$ref": "#/definitions/lint-level" - } - ], - "default": "warn", - "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" - }, - "ignore": - { - "type": "array", - "items": - { - "$ref": "#/definitions/advisories-ignore-item" - } - } - } - }, - "advisories-ignore-item": - { - "oneOf": - [ - { - "type": "string", - "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." - }, - { - "$ref": "#/definitions/ignore-advisory-object" - }, - { - "$ref": "#/definitions/ignore-yanked-object" - } - ], - "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" - }, - "ignore-advisory-object": - { - "type": "object", - "examples": - [ - "RUSTSEC-2019-0001" - ], - "required": - [ - "id" - ], - "properties": - { - "id": - { - "type": "string", - "description": "The unique identifier of the advisory to ignore" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "ignore-yanked-object": - { - "type": "object", - "required": - [ - "crate" - ], - "properties": - { - "crate": - { - "$ref": "#/definitions/package-spec" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "ignore-reason": - { - "type": "string", - "description": "Free-form string that can be used to describe the reason why the advisory is ignored." - }, - "lint-level": - { - "deprecated": true, - "enum": - [ - "deny", - "warn", - "allow" - ], - "x-taplo": - { - "docs": - { - "enumValues": - [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." - ] - } - } - }, - "package-spec": - { - "type": "string", - "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" - }, - "graph": - { - "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", - "type": "object", - "properties": - { - "targets": - { - "type": "array", - "items": - { - "$ref": "#/definitions/target" - }, - "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" - }, - "exclude": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" - }, - "all-features": - { - "type": "boolean", - "description": "If set to `true`, `--all-features` will be used when collecting metadata." - }, - "no-default-features": - { - "type": "boolean", - "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." - }, - "features": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" - }, - "exclude-dev": - { - "type": "boolean", - "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" - } - } - }, - "target": - { - "oneOf": - [ - { - "$ref": "#/definitions/target-triple" - }, - { - "$ref": "#/definitions/target-object" - } - ] - }, - "target-object": - { - "description": "Advanced configurations to apply for the target triple", - "type": "object", - "required": - [ - "triple" - ], - "properties": - { - "triple": - { - "$ref": "#/definitions/target-triple" - }, - "features": - { - "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" - } - } - }, - "target-triple": - { - "type": "string", - "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" - }, - "output": - { - "description": "The output table provides options for how/if diagnostics are outputted", - "type": "object", - "properties": - { - "feature-depth": - { - "type": "integer", - "minimum": 0, - "default": 1, - "description": "The maximum depth that features will be displayed when inclusion graphs are included in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" - } - } - } - } -} \ No newline at end of file diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml new file mode 100644 index 00000000..cc423c85 --- /dev/null +++ b/xtask/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" + +[dependencies] +# Amazing CLI arg parser +clap = { version = "4.3", features = ["derive"] } + +# The coolest serialization framework in the world +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_yaml = "0.9" + +# Easy dynamic error handling +anyhow = "1.0" + +# Awesome logging tools +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +# The best iterators utilities +itertools = "0.12" diff --git a/xtask/src/cli.rs b/xtask/src/cli.rs new file mode 100644 index 00000000..bcabfcac --- /dev/null +++ b/xtask/src/cli.rs @@ -0,0 +1,34 @@ +mod codegen; + +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Subcommand, Debug)] +enum Command { + Codegen(codegen::CodegenCommand), +} + +pub(crate) fn run() -> anyhow::Result<()> { + let cli = Cli::parse(); + match cli.command { + Command::Codegen(cmd) => cmd.run(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + + fn verify_cli() { + use clap::CommandFactory; + Cli::command().debug_assert() + } +} diff --git a/xtask/src/cli/codegen.rs b/xtask/src/cli/codegen.rs new file mode 100644 index 00000000..2e6a4deb --- /dev/null +++ b/xtask/src/cli/codegen.rs @@ -0,0 +1,13 @@ +mod jsonschema; + +/// Update generated code that is checked in to source control. +#[derive(clap::Args, Debug)] +pub(crate) struct CodegenCommand {} + +impl CodegenCommand { + pub(crate) fn run(self) -> anyhow::Result<()> { + jsonschema::codegen()?; + + Ok(()) + } +} diff --git a/xtask/src/cli/codegen/jsonschema.rs b/xtask/src/cli/codegen/jsonschema.rs new file mode 100644 index 00000000..fc4bca45 --- /dev/null +++ b/xtask/src/cli/codegen/jsonschema.rs @@ -0,0 +1,163 @@ +use anyhow::Context; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::BTreeMap; +use std::fs; + +type Untyped = BTreeMap; + +#[derive(Serialize, Deserialize, Debug)] +struct RootSchema { + definitions: BTreeMap, + + #[serde(flatten)] + schema: Schema, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct Schema { + // kind: Option, + #[serde(rename = "enum", skip_serializing_if = "Option::is_none")] + enum_values: Option>, + + // #[serde(rename = "x-taplo")] + // x_taplo: Option, + #[serde(rename = "$ref", skip_serializing_if = "Option::is_none")] + reference: Option, + + #[serde(flatten)] + untyped: Untyped, +} + +// #[derive(Serialize, Deserialize, Debug, Clone)] +// #[serde(tag = "type")] +// enum SchemaKind { +// Object { +// properties: BTreeMap, +// }, +// Array { +// items: Box, +// }, +// String, +// Integer, +// Number, +// Boolean, +// Null, +// } + +// #[derive(Serialize, Deserialize, Debug, Clone)] +// struct XTaplo { +// docs: XTaploDocs, + +// #[serde(flatten)] +// untyped: Untyped, +// } + +// #[derive(Serialize, Deserialize, Debug, Clone)] +// struct XTaploDocs { +// enum_values: Vec, + +// #[serde(flatten)] +// untyped: Untyped, +// } + +// impl Schema { +// fn merge(&mut self, other: &Schema) { +// merge_serializable(self, other.clone()); +// } +// } + +// fn merge_serializable(a: &mut T, b: T) { +// let mut a_value = serde_json::to_value(&a).unwrap(); +// let b_value = serde_json::to_value(b).unwrap(); +// merge_json_values(&mut a_value, b_value); + +// *a = serde_json::from_value(a_value).unwrap(); +// } + +fn merge_json_values(a: &mut Value, b: Value) { + use serde_json::map::Entry; + + match (a, b) { + (Value::Object(a), Value::Object(b)) => { + for (key, b_value) in b { + match a.entry(key) { + Entry::Occupied(mut a_value) => merge_json_values(a_value.get_mut(), b_value), + Entry::Vacant(entry) => { + entry.insert(b_value); + } + } + } + } + (Value::Array(a), Value::Array(b)) => { + a.extend(b); + } + (a, b) => *a = b, + } +} + +fn inline_enum_refs(def: &mut Schema, enums: &BTreeMap) -> anyhow::Result<()> { + let mut def_value = serde_json::to_value(&def).unwrap(); + inline_enum_refs_imp(&mut def_value, enums)?; + *def = serde_json::from_value(def_value).unwrap(); + Ok(()) +} + +fn inline_enum_refs_imp( + def_value: &mut Value, + enums: &BTreeMap, +) -> anyhow::Result<()> { + let Some(def) = def_value.as_object_mut() else { + return Ok(()); + }; + + for property in def.values_mut() { + inline_enum_refs_imp(property, enums)?; + } + + let Some(reference) = def.get("$ref") else { + return Ok(()); + }; + + let reference = reference + .as_str() + .with_context(|| format!("Reference must be a string, but found: {reference}"))?; + + let reference = reference.strip_prefix("#/definitions/").with_context(|| { + format!("Reference not to #/definitions is not allowed, but found: {reference}") + })?; + + let Some(enum_def) = enums.get(reference) else { + return Ok(()); + }; + + def.remove("$ref"); + + let enum_def = serde_json::to_value(enum_def).unwrap(); + merge_json_values(def_value, enum_def); + + Ok(()) +} + +/// Generate the JSON schema based on the input YML schema. +pub(crate) fn codegen() -> anyhow::Result<()> { + let root_schema = fs::read_to_string("deny.schema.yml")?; + let mut root_schema: RootSchema = serde_yaml::from_str(&root_schema)?; + + let (enums, mut defs): (BTreeMap, BTreeMap<_, _>) = root_schema + .definitions + .into_iter() + .partition(|(_, val)| val.enum_values.is_some()); + + for def in defs.values_mut() { + inline_enum_refs(def, &enums)?; + } + + root_schema.definitions = itertools::concat([enums, defs]); + + let output = serde_json::to_string_pretty(&root_schema)?; + + std::fs::write("deny.schema.json", output)?; + + Ok(()) +} diff --git a/xtask/src/entrypoint.rs b/xtask/src/entrypoint.rs new file mode 100644 index 00000000..410cbe5b --- /dev/null +++ b/xtask/src/entrypoint.rs @@ -0,0 +1,28 @@ +use anyhow::Result; +use std::process::ExitCode; +use tracing_subscriber::prelude::*; + +pub fn run() -> ExitCode { + let Err(err) = try_run() else { + return ExitCode::SUCCESS; + }; + + eprintln!("Exitting with error: {err:?}"); + ExitCode::FAILURE +} + +fn try_run() -> Result<()> { + let env_filter = tracing_subscriber::EnvFilter::from_env("XTASK_LOG"); + + let fmt = tracing_subscriber::fmt::layer() + .with_target(true) + .with_ansi(std::env::var("COLORS").as_deref() != Ok("0")) + .pretty(); + + tracing_subscriber::registry() + .with(fmt) + .with(env_filter) + .init(); + + crate::cli::run() +} diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs new file mode 100644 index 00000000..86c4a19c --- /dev/null +++ b/xtask/src/lib.rs @@ -0,0 +1,4 @@ +mod cli; +mod entrypoint; + +pub use entrypoint::run; diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 00000000..91971740 --- /dev/null +++ b/xtask/src/main.rs @@ -0,0 +1,3 @@ +fn main() -> std::process::ExitCode { + xtask::run() +} From d2a08033086951362fe0d646dd42a56bfe19b0ba Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 23 Mar 2024 15:19:20 +0000 Subject: [PATCH 04/20] Fix typo --- xtask/src/entrypoint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtask/src/entrypoint.rs b/xtask/src/entrypoint.rs index 410cbe5b..f367b99b 100644 --- a/xtask/src/entrypoint.rs +++ b/xtask/src/entrypoint.rs @@ -7,7 +7,7 @@ pub fn run() -> ExitCode { return ExitCode::SUCCESS; }; - eprintln!("Exitting with error: {err:?}"); + eprintln!("Exiting with error: {err:?}"); ExitCode::FAILURE } From e49c05c2dd07777d80a0504e8d79d5d1477805c1 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 7 Apr 2024 01:36:05 +0000 Subject: [PATCH 05/20] Next iteration --- Cargo.lock | 35 +- deny.schema.json | 372 ++++++++++++++++++++ deny.schema.yml | 89 +++-- deny.template.toml | 2 +- deny16.schema.json | 326 +++++++++++++++++ deny38.schema.json | 326 +++++++++++++++++ docs/src/checks2/advisories/cfg.md | 334 ++++++++++++++++++ docs/src/checks2/cfg.md | 21 ++ docs/src/checks2/graph/cfg.md | 167 +++++++++ docs/src/checks2/output/cfg.md | 19 + xtask/Cargo.toml | 18 +- xtask/src/cli.rs | 2 +- xtask/src/cli/codegen.rs | 15 +- xtask/src/cli/codegen/input.rs | 300 ++++++++++++++++ xtask/src/cli/codegen/json_schema.rs | 86 +++++ xtask/src/cli/codegen/jsonschema.rs | 163 --------- xtask/src/cli/codegen/md_doc.rs | 500 +++++++++++++++++++++++++++ 17 files changed, 2568 insertions(+), 207 deletions(-) create mode 100644 deny.schema.json create mode 100644 deny16.schema.json create mode 100644 deny38.schema.json create mode 100644 docs/src/checks2/advisories/cfg.md create mode 100644 docs/src/checks2/cfg.md create mode 100644 docs/src/checks2/graph/cfg.md create mode 100644 docs/src/checks2/output/cfg.md create mode 100644 xtask/src/cli/codegen/input.rs create mode 100644 xtask/src/cli/codegen/json_schema.rs delete mode 100644 xtask/src/cli/codegen/jsonschema.rs create mode 100644 xtask/src/cli/codegen/md_doc.rs diff --git a/Cargo.lock b/Cargo.lock index 0b019a0a..1e60eab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,7 +283,7 @@ checksum = "e11c675378efb449ed3ce8de78d75d0d80542fc98487c26aba28eb3b82feac72" dependencies = [ "semver", "serde", - "toml", + "toml 0.7.8", "url", ] @@ -1682,6 +1682,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] @@ -2292,7 +2293,7 @@ dependencies = [ "semver", "serde", "thiserror", - "toml", + "toml 0.7.8", "url", ] @@ -2420,6 +2421,7 @@ version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ + "indexmap", "itoa", "ryu", "serde", @@ -2824,7 +2826,19 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.9", ] [[package]] @@ -2860,6 +2874,19 @@ dependencies = [ "winnow 0.5.40", ] +[[package]] +name = "toml_edit" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.5", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -3337,10 +3364,12 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "indexmap", "itertools", "serde", "serde_json", "serde_yaml", + "toml 0.8.12", "tracing", "tracing-subscriber", ] diff --git a/deny.schema.json b/deny.schema.json new file mode 100644 index 00000000..36ecd1e6 --- /dev/null +++ b/deny.schema.json @@ -0,0 +1,372 @@ +{ + "type": "object", + "properties": { + "advisories": { + "$ref": "#/definitions/advisories" + }, + "graph": { + "$ref": "#/definitions/graph" + }, + "output": { + "$ref": "#/definitions/output" + } + }, + "title": "cargo-deny configuration file", + "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", + "definitions": { + "advisories": { + "type": "object", + "examples": [ + { + "db-path": "~/.cargo/advisory-dbs", + "db-urls": [ + "https://github.com/RustSec/advisory-db" + ], + "vulnerability": "deny", + "unmaintained": "warn", + "unsound": "warn", + "yanked": "warn", + "notice": "warn", + "ignore": [ + "RUSTSEC-0000-0000", + "crate@0.1", + { + "crate": "yanked", + "reason": "a new version has not been released" + } + ], + "severity-threshold": "medium" + } + ], + "properties": { + "db-urls": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + }, + "description": "URLs to one or more advisory databases.", + "default": [ + "https://github.com/RustSec/advisory-db" + ] + }, + "db-path": { + "type": "string", + "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n", + "default": "$CARGO_HOME/advisory-dbs" + }, + "version": { + "type": "integer", + "enum": [ + 2 + ], + "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" + }, + "vulnerability": { + "deprecated": true, + "enum": [ + "deny", + "warn", + "allow" + ], + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n", + "default": "deny", + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "unmaintained": { + "deprecated": true, + "enum": [ + "deny", + "warn", + "allow" + ], + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n", + "default": "warn", + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "unsound": { + "deprecated": true, + "enum": [ + "deny", + "warn", + "allow" + ], + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n", + "default": "warn", + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "notice": { + "deprecated": true, + "enum": [ + "deny", + "warn", + "allow" + ], + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n", + "default": "warn", + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "yanked": { + "enum": [ + "deny", + "warn", + "allow" + ], + "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n", + "default": "warn", + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "ignore": { + "type": "array", + "examples": [ + [ + "RUSTSEC-0000-0000", + { + "id": "RUSTSEC-0000-0000", + "reason": "this vulnerability does not affect us as we don't use the particular code path" + }, + "yanked@0.1.1", + { + "crate": "yanked-crate@0.1.1", + "reason": "a semver compatible version hasn't been published yet" + } + ] + ], + "items": { + "$ref": "#/definitions/advisories-ignore-item" + }, + "description": "Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" + } + }, + "description": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as Unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" + }, + "advisories-ignore-advisory": { + "type": "object", + "properties": { + "id": { + "type": "string", + "examples": [ + "RUSTSEC-2019-0001" + ], + "description": "The unique identifier of the advisory to ignore" + }, + "reason": { + "$ref": "#/definitions/ignore-reason" + } + }, + "required": [ + "id" + ] + }, + "advisories-ignore-item": { + "oneOf": [ + { + "type": "string", + "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." + }, + { + "$ref": "#/definitions/advisories-ignore-advisory" + }, + { + "$ref": "#/definitions/advisories-ignore-yanked" + } + ] + }, + "advisories-ignore-yanked": { + "type": "object", + "properties": { + "crate": { + "$ref": "#/definitions/package-spec" + }, + "reason": { + "$ref": "#/definitions/ignore-reason" + } + }, + "required": [ + "crate" + ] + }, + "graph": { + "type": "object", + "properties": { + "targets": { + "type": "array", + "items": { + "$ref": "#/definitions/target" + }, + "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" + }, + "exclude": { + "type": "array", + "examples": [ + "some-crate@0.1.0" + ], + "items": { + "type": "string" + }, + "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" + }, + "all-features": { + "type": "boolean", + "description": "If set to `true`, `--all-features` will be used when collecting metadata." + }, + "no-default-features": { + "type": "boolean", + "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." + }, + "features": { + "type": "array", + "examples": [ + "some-feature" + ], + "items": { + "type": "string" + }, + "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" + }, + "exclude-dev": { + "type": "boolean", + "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" + } + }, + "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n" + }, + "ignore-reason": { + "type": "string", + "description": "Free-form string that can be used to describe the reason why the advisory is ignored." + }, + "lint-level": { + "enum": [ + "deny", + "warn", + "allow" + ], + "x-taplo": { + "docs": { + "enumValues": [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "output": { + "type": "object", + "properties": { + "feature-depth": { + "type": "integer", + "description": "The maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n", + "default": 1 + } + }, + "description": "The output table provides options for how/if diagnostics are outputted" + }, + "package-spec": { + "type": "string", + "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" + }, + "target": { + "oneOf": [ + { + "$ref": "#/definitions/target-string" + }, + { + "$ref": "#/definitions/target-complex" + } + ] + }, + "target-complex": { + "type": "object", + "examples": [ + { + "triple": "aarch64-apple-darwin" + }, + { + "triple": "x86_64-pc-windows-msvc", + "features": [ + "some-feature" + ] + } + ], + "properties": { + "triple": { + "$ref": "#/definitions/target-string" + }, + "features": { + "type": "string", + "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" + } + }, + "required": [ + "triple" + ], + "description": "Advanced configurations to apply for the target triple" + }, + "target-string": { + "type": "string", + "examples": [ + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "aarch64-apple-darwin" + ], + "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" + } + }, + "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", + "$schema": "https://json-schema.org/draft-07/schema#", + "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", + "properties": { + "advisories": { + "$ref": "#/definitions/advisories" + }, + "graph": { + "$ref": "#/definitions/graph" + }, + "output": { + "$ref": "#/definitions/output" + } + }, + "title": "cargo-deny configuration file", + "type": "object" +} \ No newline at end of file diff --git a/deny.schema.yml b/deny.schema.yml index e84b09a8..ac096d59 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -41,10 +41,28 @@ properties: definitions: advisories: + examples: + - db-path: ~/.cargo/advisory-dbs + db-urls: [https://github.com/RustSec/advisory-db] + vulnerability: deny + unmaintained: warn + unsound: warn + yanked: warn + notice: warn + ignore: + - RUSTSEC-0000-0000 + - crate@0.1 + - { crate: yanked, reason: a new version has not been released } + severity-threshold: medium + description: | - This section is considered when running `cargo deny check advisories` - More documentation for the advisories section can be found - [here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html) + Checks advisory databases for crates with security vulnerabilities, + or that have been marked as Unmaintained, or which have been yanked from + their source registry. + + This section is considered when running `cargo deny check advisories`. + # More documentation for the advisories section can be found + # [here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html) type: object properties: @@ -56,6 +74,7 @@ definitions: db-path: type: string + default: $CARGO_HOME/advisory-dbs description: | Path to the root directory into which one or more advisory databases are cloned into. @@ -71,10 +90,10 @@ definitions: Note that the path must be valid utf-8, after expansion. - Default: `$CARGO_HOME/advisory-dbs` - version: + type: integer enum: [2] + description: | The advisories section has an upcoming breaking change, with deprecation warnings for several fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. @@ -117,6 +136,7 @@ definitions: Determines what happens when a crate with an `unsound` advisory is encountered. notice: + deprecated: true $ref: '#/definitions/lint-level' default: warn description: | @@ -133,25 +153,19 @@ definitions: description: | Determines what happens when a crate with a version that has been yanked from its source registry is encountered. - # x-taplo: - # docs: - # main: | - # Determines what happens when a crate with a version that has been yanked from its source - # registry is encountered. ignore: type: array items: { $ref: '#/definitions/advisories-ignore-item' } - description: | - ```toml - ignore = [ - "RUSTSEC-0000-0000", - { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, - "yanked@0.1.1", - { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, - ] - ``` + examples: + - - RUSTSEC-0000-0000 + - id: "RUSTSEC-0000-0000" + reason: this vulnerability does not affect us as we don't use the particular code path + - yanked@0.1.1 + - crate: yanked-crate@0.1.1 + reason: a semver compatible version hasn't been published yet + description: | Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. Putting an identifier in this array will cause the advisory to be treated as a note, rather than a warning or error. @@ -188,17 +202,20 @@ definitions: description: Free-form string that can be used to describe the reason why the advisory is ignored. lint-level: - # anyOf: - # - { const: deny, } # description: Emit an error with details about the problem, and fail the check. } - # - { const: warn, } # description: Print a warning for each propblem, but don't fail the check. } - # - { const: allow, } # description: Print a note about the problem, but don't fail the check. } - enum: [deny, warn, allow] - x-taplo: - docs: - enumValues: - - Emit an error with details about the problem, and fail the check. - - Print a warning for each propblem, but don't fail the check. - - Print a note about the problem, but don't fail the check. + enum: + - value: deny + description: Emit an error with details about the problem, and fail the check. + - value: warn + description: Print a warning for each propblem, but don't fail the check. + - value: allow + description: Print a note about the problem, but don't fail the check. + + # x-taplo: + # docs: + # enumValues: + # - + # - + # - package-spec: type: string @@ -315,6 +332,7 @@ definitions: Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced via the excluded crate, they will also be excluded from the crate graph. + examples: [some-crate@0.1.0] all-features: type: boolean @@ -330,6 +348,7 @@ definitions: description: | If set, and `--features` is not specified on the cmd line, these features will be used when collecting metadata. + examples: [some-feature] exclude-dev: type: boolean @@ -352,6 +371,7 @@ definitions: properties: triple: { $ref: '#/definitions/target-string' } features: + type: string description: | Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) predicate, but at the moment, the only way to actually pass them when compiling is to use @@ -360,8 +380,17 @@ definitions: this writing, cargo-deny does not attempt to validate that the features you specify are actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). + examples: + - { triple: aarch64-apple-darwin } + - { triple: x86_64-pc-windows-msvc, features: [some-feature] } + target-string: type: string + examples: + - x86_64-unknown-linux-gnu + - x86_64-pc-windows-msvc + - aarch64-apple-darwin + description: | The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target you wish to filter target specific dependencies with. If the target triple specified is **not** diff --git a/deny.template.toml b/deny.template.toml index dcaad1a8..43bdcb5d 100644 --- a/deny.template.toml +++ b/deny.template.toml @@ -1,4 +1,4 @@ -#:schema deny15.schema.json +#:schema deny16.schema.json # This template contains all of the possible sections and their default values diff --git a/deny16.schema.json b/deny16.schema.json new file mode 100644 index 00000000..817e42b5 --- /dev/null +++ b/deny16.schema.json @@ -0,0 +1,326 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", + "title": "cargo-deny configuration file", + "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", + "type": "object", + "properties": + { + "advisories": + { + "$ref": "#/definitions/advisories" + }, + "graph": + { + "$ref": "#/definitions/graph" + }, + "output": + { + "$ref": "#/definitions/output" + } + }, + "definitions": + { + "advisories": + { + "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found\n[here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html)\n", + "type": "object", + "properties": + { + "db-urls": + { + "type": "array", + "items": + { + "type": "string", + "format": "uri" + }, + "default": + [ + "https://github.com/RustSec/advisory-db" + ], + "description": "URLs to one or more advisory databases." + }, + "db-path": + { + "type": "string", + "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" + }, + "version": + { + "enum": + [ + 2 + ], + "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" + }, + "vulnerability": + { + "anyOf": + [ + { + "const": "deny", + "description": "Emit an error with details about the problem", + "and fail the check.": null + }, + { + "const": "warn", + "description": "Print a warning for each propblem", + "but don't fail the check.": null + }, + { + "const": "allow", + "description": "Print a note about the problem", + "but don't fail the check.": null + } + ], + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "unmaintained": + { + "deprecated": true, + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" + }, + "unsound": + { + "deprecated": true, + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" + }, + "notice": + { + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" + }, + "yanked": + { + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" + }, + "ignore": + { + "type": "array", + "items": + { + "$ref": "#/definitions/advisories-ignore-item" + }, + "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" + } + } + }, + "advisories-ignore-item": + { + "oneOf": + [ + { + "type": "string", + "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." + }, + { + "$ref": "#/definitions/advisories-ignore-advisory" + }, + { + "$ref": "#/definitions/advisories-ignore-yanked" + } + ] + }, + "advisories-ignore-advisory": + { + "type": "object", + "required": + [ + "id" + ], + "properties": + { + "id": + { + "type": "string", + "examples": + [ + "RUSTSEC-2019-0001" + ], + "description": "The unique identifier of the advisory to ignore" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "advisories-ignore-yanked": + { + "type": "object", + "required": + [ + "crate" + ], + "properties": + { + "crate": + { + "$ref": "#/definitions/package-spec" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "ignore-reason": + { + "type": "string", + "description": "Free-form string that can be used to describe the reason why the advisory is ignored." + }, + "lint-level": + { + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "package-spec": + { + "type": "string", + "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" + }, + "graph": + { + "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", + "type": "object", + "properties": + { + "targets": + { + "type": "array", + "items": + { + "$ref": "#/definitions/target" + }, + "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" + }, + "exclude": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" + }, + "all-features": + { + "type": "boolean", + "description": "If set to `true`, `--all-features` will be used when collecting metadata." + }, + "no-default-features": + { + "type": "boolean", + "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." + }, + "features": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" + }, + "exclude-dev": + { + "type": "boolean", + "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" + } + } + }, + "target": + { + "oneOf": + [ + { + "$ref": "#/definitions/target-string" + }, + { + "$ref": "#/definitions/target-complex" + } + ] + }, + "target-complex": + { + "description": "Advanced configurations to apply for the target triple", + "type": "object", + "required": + [ + "triple" + ], + "properties": + { + "triple": + { + "$ref": "#/definitions/target-string" + }, + "features": + { + "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" + } + } + }, + "target-string": + { + "type": "string", + "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" + }, + "output": + { + "description": "The output table provides options for how/if diagnostics are outputted", + "type": "object", + "properties": + { + "feature-depth": + { + "type": "integer", + "minimum": 0, + "default": 1, + "description": "The maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" + } + } + } + } +} \ No newline at end of file diff --git a/deny38.schema.json b/deny38.schema.json new file mode 100644 index 00000000..817e42b5 --- /dev/null +++ b/deny38.schema.json @@ -0,0 +1,326 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", + "title": "cargo-deny configuration file", + "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", + "type": "object", + "properties": + { + "advisories": + { + "$ref": "#/definitions/advisories" + }, + "graph": + { + "$ref": "#/definitions/graph" + }, + "output": + { + "$ref": "#/definitions/output" + } + }, + "definitions": + { + "advisories": + { + "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found\n[here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html)\n", + "type": "object", + "properties": + { + "db-urls": + { + "type": "array", + "items": + { + "type": "string", + "format": "uri" + }, + "default": + [ + "https://github.com/RustSec/advisory-db" + ], + "description": "URLs to one or more advisory databases." + }, + "db-path": + { + "type": "string", + "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" + }, + "version": + { + "enum": + [ + 2 + ], + "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" + }, + "vulnerability": + { + "anyOf": + [ + { + "const": "deny", + "description": "Emit an error with details about the problem", + "and fail the check.": null + }, + { + "const": "warn", + "description": "Print a warning for each propblem", + "but don't fail the check.": null + }, + { + "const": "allow", + "description": "Print a note about the problem", + "but don't fail the check.": null + } + ], + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "unmaintained": + { + "deprecated": true, + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" + }, + "unsound": + { + "deprecated": true, + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" + }, + "notice": + { + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" + }, + "yanked": + { + "$ref": "#/definitions/lint-level", + "default": "warn", + "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" + }, + "ignore": + { + "type": "array", + "items": + { + "$ref": "#/definitions/advisories-ignore-item" + }, + "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" + } + } + }, + "advisories-ignore-item": + { + "oneOf": + [ + { + "type": "string", + "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." + }, + { + "$ref": "#/definitions/advisories-ignore-advisory" + }, + { + "$ref": "#/definitions/advisories-ignore-yanked" + } + ] + }, + "advisories-ignore-advisory": + { + "type": "object", + "required": + [ + "id" + ], + "properties": + { + "id": + { + "type": "string", + "examples": + [ + "RUSTSEC-2019-0001" + ], + "description": "The unique identifier of the advisory to ignore" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "advisories-ignore-yanked": + { + "type": "object", + "required": + [ + "crate" + ], + "properties": + { + "crate": + { + "$ref": "#/definitions/package-spec" + }, + "reason": + { + "$ref": "#/definitions/ignore-reason" + } + } + }, + "ignore-reason": + { + "type": "string", + "description": "Free-form string that can be used to describe the reason why the advisory is ignored." + }, + "lint-level": + { + "enum": + [ + "deny", + "warn", + "allow" + ], + "x-taplo": + { + "docs": + { + "enumValues": + [ + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." + ] + } + } + }, + "package-spec": + { + "type": "string", + "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" + }, + "graph": + { + "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", + "type": "object", + "properties": + { + "targets": + { + "type": "array", + "items": + { + "$ref": "#/definitions/target" + }, + "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" + }, + "exclude": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" + }, + "all-features": + { + "type": "boolean", + "description": "If set to `true`, `--all-features` will be used when collecting metadata." + }, + "no-default-features": + { + "type": "boolean", + "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." + }, + "features": + { + "type": "array", + "items": + { + "type": "string" + }, + "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" + }, + "exclude-dev": + { + "type": "boolean", + "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" + } + } + }, + "target": + { + "oneOf": + [ + { + "$ref": "#/definitions/target-string" + }, + { + "$ref": "#/definitions/target-complex" + } + ] + }, + "target-complex": + { + "description": "Advanced configurations to apply for the target triple", + "type": "object", + "required": + [ + "triple" + ], + "properties": + { + "triple": + { + "$ref": "#/definitions/target-string" + }, + "features": + { + "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" + } + } + }, + "target-string": + { + "type": "string", + "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" + }, + "output": + { + "description": "The output table provides options for how/if diagnostics are outputted", + "type": "object", + "properties": + { + "feature-depth": + { + "type": "integer", + "minimum": 0, + "default": 1, + "description": "The maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" + } + } + } + } +} \ No newline at end of file diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md new file mode 100644 index 00000000..bbbaf6f4 --- /dev/null +++ b/docs/src/checks2/advisories/cfg.md @@ -0,0 +1,334 @@ +# The `[advisories]` section + +Checks advisory databases for crates with security vulnerabilities, +or that have been marked as Unmaintained, or which have been yanked from +their source registry. + +This section is considered when running `cargo deny check advisories`. + + +## Example + +```toml +[advisories] +db-path = "~/.cargo/advisory-dbs" +db-urls = ["https://github.com/RustSec/advisory-db"] +vulnerability = "deny" +unmaintained = "warn" +unsound = "warn" +yanked = "warn" +notice = "warn" +ignore = [ + "RUSTSEC-0000-0000", + "crate@0.1", + { crate = "yanked", reason = "a new version has not been released" }, +] +severity-threshold = "medium" +``` + +## `advisories.db-urls` (optional) + +`array of string (uri)` + +#### Default + +```toml +[advisories] +db-urls = ["https://github.com/RustSec/advisory-db"] +``` + +URLs to one or more advisory databases. + +## `advisories.db-path` (optional) + +`string` + +### Default + +```toml +[advisories] +db-path = "$CARGO_HOME/advisory-dbs" +``` + +Path to the root directory into which one or more advisory databases are cloned into. + +This value supports basic shell expansion: + +- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) +- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + or the fallback value if it doesn't exist (everything between the `:-` and `}`) +- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + if it exists, otherwise expands to `$(home::home_dir())/.cargo` + +Note that the path must be valid utf-8, after expansion. + + +## `advisories.version` (optional) + + + +### Possible values + +* `2` +--- +The advisories section has an upcoming breaking change, with deprecation warnings for several +fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + +The breaking change is as follows: + +- `vulnerability` - Removed, all vulnerability advisories now emit errors. +- `unmaintained` - Removed, all unmaintained advisories now emit errors. +- `unsound` - Removed, all unsound advisories now emit errors. +- `notice` - Removed, all notice advisories now emit errors. +- `severity-threshold` - Removed, all vulnerability advisories now emit errors. + +As before, if you want to ignore a specific advisory, add it to the `ignore` field. + + +## `advisories.vulnerability` (optional) + + + +### Possible values + +* `"deny"` - Emit an error with details about the problem, and fail the check. +* `"warn"` - Print a warning for each propblem, but don't fail the check. +* `"allow"` - Print a note about the problem, but don't fail the check. +--- +#### Default + +```toml +[advisories] +vulnerability = "deny" +``` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with a security vulnerability is encountered. + + +## `advisories.unmaintained` (optional) + + + +### Possible values + +* `"deny"` - Emit an error with details about the problem, and fail the check. +* `"warn"` - Print a warning for each propblem, but don't fail the check. +* `"allow"` - Print a note about the problem, but don't fail the check. +--- +#### Default + +```toml +[advisories] +unmaintained = "warn" +``` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with an `unmaintained` advisory is encountered. + + +## `advisories.unsound` (optional) + + + +### Possible values + +* `"deny"` - Emit an error with details about the problem, and fail the check. +* `"warn"` - Print a warning for each propblem, but don't fail the check. +* `"allow"` - Print a note about the problem, but don't fail the check. +--- +#### Default + +```toml +[advisories] +unsound = "warn" +``` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with an `unsound` advisory is encountered. + + +## `advisories.notice` (optional) + + + +### Possible values + +* `"deny"` - Emit an error with details about the problem, and fail the check. +* `"warn"` - Print a warning for each propblem, but don't fail the check. +* `"allow"` - Print a note about the problem, but don't fail the check. +--- +#### Default + +```toml +[advisories] +notice = "warn" +``` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with a `notice` advisory is encountered. + +**NOTE**: As of 2019-12-17 there are no `notice` advisories in the +[RustSec Advisory DB](https://github.com/RustSec/advisory-db) + + +## `advisories.yanked` (optional) + + + +### Possible values + +* `"deny"` - Emit an error with details about the problem, and fail the check. +* `"warn"` - Print a warning for each propblem, but don't fail the check. +* `"allow"` - Print a note about the problem, but don't fail the check. +--- +#### Default + +```toml +[advisories] +yanked = "warn" +``` + +Determines what happens when a crate with a version that has been yanked from its source +registry is encountered. + + +## `advisories.ignore` (optional) + +`array` + +Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. +Putting an identifier in this array will cause the advisory to be treated as a note, rather +than a warning or error. + +In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +with an optional `reason`. + + +#### Example + +```toml +[advisories] +ignore = [ + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, + "yanked@0.1.1", + { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, +] +``` + +### Items + +**One of the following:** + +`string` + +Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). + + +##### `advisories.ignore[N].id` (required) + +`string` + +The unique identifier of the advisory to ignore + +###### Example + +```toml +[[advisories.ignore]] +id = "RUSTSEC-2019-0001" +``` + +##### `advisories.ignore[N].reason` (optional) + +`string` + +Free-form string that can be used to describe the reason why the advisory is ignored. + + +##### `advisories.ignore[N].crate` (required) + +`string` + +Many configuration options require a package specifier at a minimum, which we'll describe here. +The options that use package specifiers will be called out in their individual documentation. +We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + +### String format + +If the particular only requires a package spec at a minimum, then the string format can be used, +which comes in three forms. + +#### Simple + +```toml +# Will match any version of the simple crate +deny = ["simple"] +``` + +The simplest string is one which is just the crate name. In this case, the version requirement +used when checking will be `*` meaning it will match against all versions of that crate in the graph. + +#### With Version Requirements + +```toml +# Will match only these versions of the simple crate that match the predicate(s) +deny = ["simple:<=0.1,>0.2"] +``` + +If you want to apply version requirements (predicates) to the crate, simply append them following +a `:` separator. + +#### Exact + +```toml +# Will match only this exact version of the simple crate +deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", +] +``` + +The exact form is a specialization of the version requirements, where the semver after the `@` +is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + +### Table format + +#### Crate format + +```toml +deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, +] +``` + +The crate format is a replacement for the old `name` and/or `version` table format. It uses +the string format described above in a single `crate` key. + +#### Old format + +```toml +deny = [ + { name = "simple" }, + { name = "simple", version = "*" } + { name = "simple", wrappers = ["example"] } +] +``` + +The old format uses a required `name` key and an optional `version` key. This format is deprecated +and should not be used. + + +##### `advisories.ignore[N].reason` (optional) + +`string` + +Free-form string that can be used to describe the reason why the advisory is ignored. diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md new file mode 100644 index 00000000..6606eefa --- /dev/null +++ b/docs/src/checks2/cfg.md @@ -0,0 +1,21 @@ +# config + +The top level config for cargo-deny, by default called `deny.toml`. + +## Example - cargo-deny's own configuration + +```ini +{{#include ../../../deny.toml}} +``` + +## The `[advisories]` section + +See [advisories config](advisories/cfg.html) for more info. + +## The `[graph]` section + +See [graph config](graph/cfg.html) for more info. + +## The `[output]` section + +See [output config](output/cfg.html) for more info. \ No newline at end of file diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md new file mode 100644 index 00000000..a4c39cb8 --- /dev/null +++ b/docs/src/checks2/graph/cfg.md @@ -0,0 +1,167 @@ +# The `[graph]` section + +The graph table configures how the dependency graph is constructed and thus which crates the +checks are performed against + + +## `graph.targets` (optional) + +`array` + +By default, cargo-deny will consider every single crate that is resolved by cargo, including +target specific dependencies e.g. + +```toml +[target.x86_64-pc-windows-msvc.dependencies] +winapi = "0.3.8" + +[target.'cfg(target_os = "fuchsia")'.dependencies] +fuchsia-cprng = "0.1.1" +``` + +But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is +never actually going to be compiled or linked into your project, so checking it is pointless for you. + +The `targets` field allows you to specify one or more targets which you **actually** build for. +Every dependency link to a crate is checked against this list, and if none of the listed targets +satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links +to it, it is not included into the crate graph that the checks are +executed against. + + +### Items + +**One of the following:** + +`string` + +The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target +you wish to filter target specific dependencies with. If the target triple specified is **not** +one of the targets builtin to `rustc`, the configuration check for that target will be limited +to only the raw `[target..dependencies]` style of target configuration, as `cfg()` +expressions require us to know the details about the target. + + +#### Examples + +- ```toml + [graph] + targets = ["x86_64-unknown-linux-gnu"] + ``` +- ```toml + [graph] + targets = ["x86_64-pc-windows-msvc"] + ``` +- ```toml + [graph] + targets = ["aarch64-apple-darwin"] + ``` +Advanced configurations to apply for the target triple + +##### Examples + +- ```toml + [[graph.targets]] + triple = "aarch64-apple-darwin" + ``` +- ```toml + [[graph.targets]] + triple = "x86_64-pc-windows-msvc" + features = ["some-feature"] + ``` + +##### `graph.targets[N].triple` (required) + +`string` + +The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target +you wish to filter target specific dependencies with. If the target triple specified is **not** +one of the targets builtin to `rustc`, the configuration check for that target will be limited +to only the raw `[target..dependencies]` style of target configuration, as `cfg()` +expressions require us to know the details about the target. + + +###### Examples + +- ```toml + [[graph.targets]] + triple = "x86_64-unknown-linux-gnu" + ``` +- ```toml + [[graph.targets]] + triple = "x86_64-pc-windows-msvc" + ``` +- ```toml + [[graph.targets]] + triple = "aarch64-apple-darwin" + ``` + +##### `graph.targets[N].features` (optional) + +`string` + +Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) +predicate, but at the moment, the only way to actually pass them when compiling is to use +the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more +`target_feature`s you plan to build with, for a particular target triple. At the time of +this writing, cargo-deny does not attempt to validate that the features you specify are +actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). + + +## `graph.exclude` (optional) + +`array of string` + +Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) +that will cause the crate(s) in question to be excluded from the crate graph that is used +for the operation you are performing. + +Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced +via the excluded crate, they will also be excluded from the crate graph. + + +#### Example + +```toml +[graph] +exclude = "some-crate@0.1.0" +``` + +## `graph.all-features` (optional) + +`boolean` + +If set to `true`, `--all-features` will be used when collecting metadata. + +## `graph.no-default-features` (optional) + +`boolean` + +If set to `true`, `--no-default-features` will be used when collecting metadata. + +## `graph.features` (optional) + +`array of string` + +If set, and `--features` is not specified on the cmd line, these features will be used when +collecting metadata. + + +#### Example + +```toml +[graph] +features = "some-feature" +``` + +## `graph.exclude-dev` (optional) + +`boolean` + +If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included +in the crate graph used for any of the checks. This option can also be enabled on cmd line +with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) +the `check` subcommand. + diff --git a/docs/src/checks2/output/cfg.md b/docs/src/checks2/output/cfg.md new file mode 100644 index 00000000..275993a9 --- /dev/null +++ b/docs/src/checks2/output/cfg.md @@ -0,0 +1,19 @@ +# The `[output]` section + +The output table provides options for how/if diagnostics are outputted + +## `output.feature-depth` (optional) + +`integer` + +### Default + +```toml +[output] +feature-depth = 1 +``` + +The maximum depth that features will be displayed when inclusion graphs are shown in +diagnostics, unless specified via `--feature-depth` on the command line. Only applies to +diagnostics that actually print features. + diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index cc423c85..146a0cb0 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -4,20 +4,24 @@ version = "0.1.0" edition = "2021" [dependencies] +# Easy dynamic error handling +anyhow = "1.0" + # Amazing CLI arg parser clap = { version = "4.3", features = ["derive"] } +# The best iterators utilities +itertools = "0.12" + +# Map that preserves the order of fields +indexmap = { version = "2.0", features = ["serde"] } + # The coolest serialization framework in the world serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde_json = { version = "1.0", features = ["preserve_order"] } serde_yaml = "0.9" - -# Easy dynamic error handling -anyhow = "1.0" +toml = "0.8" # Awesome logging tools tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } - -# The best iterators utilities -itertools = "0.12" diff --git a/xtask/src/cli.rs b/xtask/src/cli.rs index bcabfcac..330305bc 100644 --- a/xtask/src/cli.rs +++ b/xtask/src/cli.rs @@ -29,6 +29,6 @@ mod tests { fn verify_cli() { use clap::CommandFactory; - Cli::command().debug_assert() + Cli::command().debug_assert(); } } diff --git a/xtask/src/cli/codegen.rs b/xtask/src/cli/codegen.rs index 2e6a4deb..25f3df18 100644 --- a/xtask/src/cli/codegen.rs +++ b/xtask/src/cli/codegen.rs @@ -1,4 +1,8 @@ -mod jsonschema; +mod input; +mod json_schema; +mod md_doc; + +use std::fs; /// Update generated code that is checked in to source control. #[derive(clap::Args, Debug)] @@ -6,7 +10,14 @@ pub(crate) struct CodegenCommand {} impl CodegenCommand { pub(crate) fn run(self) -> anyhow::Result<()> { - jsonschema::codegen()?; + // Maybe we'll need CLI params here in the future + let Self {} = self; + + let input = fs::read_to_string("deny.schema.yml")?; + let input: input::RootSchema = serde_yaml::from_str(&input)?; + + md_doc::gen(&input)?; + json_schema::gen(&input)?; Ok(()) } diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/input.rs new file mode 100644 index 00000000..de962ef7 --- /dev/null +++ b/xtask/src/cli/codegen/input.rs @@ -0,0 +1,300 @@ +use anyhow::{Context, Result}; +use indexmap::IndexMap; +use itertools::Either; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::{BTreeMap, BTreeSet}; + +type Object = BTreeMap; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct RootSchema { + #[serde(flatten)] + pub(crate) schema: Schema, + + pub(crate) definitions: BTreeMap, + + // Keep the rest of the fields in the schema so they are not lost during + // the deserialize -> serialize roundtrip. + #[serde(flatten)] + pub(crate) other: Object, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] + +pub(crate) struct Schema { + #[serde(skip_serializing_if = "Option::is_none", rename = "type")] + pub(crate) ty: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) format: Option, + + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub(crate) deprecated: bool, + + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub(crate) examples: Vec, + + #[serde(flatten)] + pub(crate) object_schema: Option, + + #[serde(flatten)] + pub(crate) array_schema: Option, + + #[serde(skip_serializing_if = "Option::is_none", rename = "enum")] + pub(crate) enum_schema: Option, + + #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] + pub(crate) one_of: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) title: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) description: Option, + + #[serde(skip_serializing_if = "Option::is_none", rename = "$ref")] + pub(crate) reference: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) default: Option, + + /// Extensions for taplo TOML language server + #[serde(skip_serializing_if = "Option::is_none", rename = "x-taplo")] + pub(crate) x_taplo: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub(crate) enum EnumSchema { + Custom(Vec), + Standard(Vec), +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct CustomEnumSchema { + pub(crate) value: String, + + pub(crate) description: String, +} + +pub(crate) struct OneOfSchema {} + +// /// Unfortunately we can't use an internally-tagged enum here with associated data +// /// because when flattening such enum with `#[serde(flatten)]` we end up with +// /// duplicate data in `other: Object` field as well, which then results in broken +// /// serialization that outputs duplicate keys in JSON objects. This is a bug in +// /// serde: +// #[derive(Serialize, Deserialize, Debug, Clone)] +// #[serde(tag = "type", rename_all = "lowercase")] +// pub(crate) enum SchemaType { +// Object, +// Array, +// String, +// Integer, +// Number, +// Boolean, +// Null, +// } + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct ObjectSchema { + /// Properties are defined via an [`IndexMap`] to preserve the order as they + /// are defined in the schema. This way we can put more important properties + /// at the top of the generated documentation by defining them first in the + /// schema. + pub(crate) properties: IndexMap, + + #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] + pub(crate) required: BTreeSet, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct ArraySchema { + pub(crate) items: Box, +} + +impl Schema { + pub(crate) fn is_primitive(&self) -> bool { + self.object_schema.is_none() + && self.array_schema.is_none() + && self.enum_schema.is_none() + && self.one_of.is_none() + } + + /// Returns all schemas stored inside of this one. It doesn't resolve + /// references. + pub(crate) fn inner_schemas(&self) -> impl Iterator { + let mut stack = vec![self]; + std::iter::from_fn(move || { + let schema = stack.pop()?; + + let properties = schema + .object_schema + .iter() + .flat_map(|object| object.properties.values()); + + stack.extend(properties); + stack.extend(schema.array_schema.iter().map(|array| array.items.as_ref())); + stack.extend(schema.one_of.iter().flatten()); + Some(schema) + }) + } + + pub(crate) fn traverse_mut(&mut self, visit: impl Fn(&mut Schema) -> Result<()>) -> Result<()> { + visit(self)?; + + if let Some(object) = &mut self.object_schema { + object.properties.values_mut().try_for_each(&visit)?; + } + + if let Some(array) = &mut self.array_schema { + visit(&mut array.items)?; + } + + if let Some(one_of) = &mut self.one_of { + one_of.iter_mut().try_for_each(&visit)?; + } + + Ok(()) + } + + pub(crate) fn try_as_object(&self) -> Result<&ObjectSchema> { + self.object_schema + .as_ref() + .with_context(|| format!("Expected object schema, but got {self:#?}")) + } + + pub(crate) fn try_description(&self) -> Result<&str> { + self.description + .as_deref() + .with_context(|| format!("Expected description for schema, but found none: {self:#?}")) + } + + pub(crate) fn referenced_definition(&self) -> Result> { + let Some(reference) = &self.reference else { + return Ok(None); + }; + + let reference = reference.strip_prefix("#/definitions/").with_context(|| { + format!("Reference to anything but `#/definitions` is disallowed: {reference}") + })?; + + Ok(Some(reference)) + } +} + +impl RootSchema { + pub(crate) fn find_definition(&self, def_name: &str) -> Result<&Schema> { + self.definitions + .get(def_name) + .with_context(|| format!("Reference to unknown definition: `{def_name}`")) + } + + fn find_reference(&self, schema: &Schema) -> Result> { + let Some(def_name) = schema.referenced_definition()? else { + return Ok(None); + }; + + let definition = self + .find_definition(def_name) + .with_context(|| format!("inside of schema: {schema:#?}"))?; + + Ok(Some(definition)) + } + + pub(crate) fn inline_referenced_definition(&self, schema: &Schema) -> Result { + let Some(definition) = self.find_reference(schema)? else { + return Ok(schema.clone()); + }; + + let mut schema = schema.clone(); + schema.reference = None; + + let mut schema_value = serde_json::to_value(schema).unwrap(); + let definition_value = serde_json::to_value(definition).unwrap(); + + merge_json_values_mut(&mut schema_value, definition_value); + + let schema = serde_json::from_value(schema_value).unwrap(); + + Ok(schema) + } +} + +impl EnumSchema { + pub(crate) fn values_and_descriptions(&self) -> impl Iterator)> { + match self { + EnumSchema::Custom(custom) => { + let iter = custom.iter().map(|custom| { + let value = custom.value.clone().into(); + let description = custom.description.as_str(); + (value, Some(description)) + }); + Either::Left(iter) + } + EnumSchema::Standard(values) => { + let iter = values.iter().map(|value| (value.clone(), None)); + Either::Right(iter) + } + } + } +} + +pub(crate) fn merge_json_values(mut a: Value, b: Value) -> Value { + merge_json_values_mut(&mut a, b); + a +} + +pub(crate) fn merge_json_values_mut(a: &mut Value, b: Value) { + use serde_json::map::Entry; + + match (a, b) { + (Value::Object(a), Value::Object(b)) => { + for (key, b_value) in b { + match a.entry(key) { + Entry::Occupied(mut a_value) => { + merge_json_values_mut(a_value.get_mut(), b_value); + } + Entry::Vacant(entry) => { + entry.insert(b_value); + } + } + } + } + (Value::Array(a), Value::Array(b)) => { + a.extend(b); + } + (a, b) => *a = b, + } +} + +// fn merge_serializable(a: &mut T, b: T) { +// let mut a_value = serde_json::to_value(&a).unwrap(); +// let b_value = serde_json::to_value(b).unwrap(); +// merge_json_values(&mut a_value, b_value); + +// *a = serde_json::from_value(a_value).unwrap(); +// } + +// #[derive(Serialize, Deserialize, Debug, Clone)] +// struct XTaplo { +// docs: XTaploDocs, + +// #[serde(flatten)] +// untyped: Object, +// } + +// #[derive(Serialize, Deserialize, Debug, Clone)] +// struct XTaploDocs { +// enum_values: Vec, + +// #[serde(flatten)] +// untyped: Object, +// } + +// impl Schema { +// fn merge(&mut self, other: &Schema) { +// merge_serializable(self, other.clone()); +// } +// } diff --git a/xtask/src/cli/codegen/json_schema.rs b/xtask/src/cli/codegen/json_schema.rs new file mode 100644 index 00000000..b2faed5d --- /dev/null +++ b/xtask/src/cli/codegen/json_schema.rs @@ -0,0 +1,86 @@ +use super::input::{EnumSchema, RootSchema, Schema}; +use anyhow::Result; +use std::mem; + +/// Generate the JSON schema based on the input YML schema. +pub(crate) fn gen(root: &RootSchema) -> Result<()> { + let ctx = GenContext::new(root); + let root = ctx.gen()?; + + let output = serde_json::to_string_pretty(&root)?; + + std::fs::write("deny.schema.json", output)?; + + Ok(()) +} + +struct GenContext<'a> { + root: &'a RootSchema, +} + +impl<'a> GenContext<'a> { + fn new(root: &'a RootSchema) -> Self { + Self { root } + } + + fn gen(self) -> Result { + let schema = self.gen_schema(&self.root.schema)?; + let definitions = self + .root + .definitions + .iter() + .map(|(name, def)| { + let def = self.gen_schema(def)?; + Ok((name.clone(), def)) + }) + .collect::>()?; + + Ok(RootSchema { + definitions, + schema, + other: self.root.other.clone(), + }) + } + + fn gen_schema(&self, schema: &Schema) -> Result { + let mut schema = schema.clone(); + + schema.traverse_mut(|schema| self.normalize_enum(schema))?; + + Ok(schema) + } + + /// Normalize the [`EnumSchema::Custom`] to [`EnumSchema::Standard`] format + /// plus generate some extensions for specific TOML language servers + fn normalize_enum(&self, schema: &mut Schema) -> Result<()> { + let mut inlined = self.root.inline_referenced_definition(schema)?; + + let Some(enum_schema) = &mut inlined.enum_schema else { + return Ok(()); + }; + + let EnumSchema::Custom(custom) = enum_schema else { + return Ok(()); + }; + + let (values, descriptions): (Vec<_>, Vec<_>) = custom + .iter_mut() + .map(|custom| { + ( + mem::take(&mut custom.value).into(), + mem::take(&mut custom.description), + ) + }) + .unzip(); + + inlined.x_taplo = Some(serde_json::json!({ + "docs": { "enumValues": descriptions } + })); + + *enum_schema = EnumSchema::Standard(values); + + *schema = inlined; + + Ok(()) + } +} diff --git a/xtask/src/cli/codegen/jsonschema.rs b/xtask/src/cli/codegen/jsonschema.rs deleted file mode 100644 index fc4bca45..00000000 --- a/xtask/src/cli/codegen/jsonschema.rs +++ /dev/null @@ -1,163 +0,0 @@ -use anyhow::Context; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use std::collections::BTreeMap; -use std::fs; - -type Untyped = BTreeMap; - -#[derive(Serialize, Deserialize, Debug)] -struct RootSchema { - definitions: BTreeMap, - - #[serde(flatten)] - schema: Schema, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -struct Schema { - // kind: Option, - #[serde(rename = "enum", skip_serializing_if = "Option::is_none")] - enum_values: Option>, - - // #[serde(rename = "x-taplo")] - // x_taplo: Option, - #[serde(rename = "$ref", skip_serializing_if = "Option::is_none")] - reference: Option, - - #[serde(flatten)] - untyped: Untyped, -} - -// #[derive(Serialize, Deserialize, Debug, Clone)] -// #[serde(tag = "type")] -// enum SchemaKind { -// Object { -// properties: BTreeMap, -// }, -// Array { -// items: Box, -// }, -// String, -// Integer, -// Number, -// Boolean, -// Null, -// } - -// #[derive(Serialize, Deserialize, Debug, Clone)] -// struct XTaplo { -// docs: XTaploDocs, - -// #[serde(flatten)] -// untyped: Untyped, -// } - -// #[derive(Serialize, Deserialize, Debug, Clone)] -// struct XTaploDocs { -// enum_values: Vec, - -// #[serde(flatten)] -// untyped: Untyped, -// } - -// impl Schema { -// fn merge(&mut self, other: &Schema) { -// merge_serializable(self, other.clone()); -// } -// } - -// fn merge_serializable(a: &mut T, b: T) { -// let mut a_value = serde_json::to_value(&a).unwrap(); -// let b_value = serde_json::to_value(b).unwrap(); -// merge_json_values(&mut a_value, b_value); - -// *a = serde_json::from_value(a_value).unwrap(); -// } - -fn merge_json_values(a: &mut Value, b: Value) { - use serde_json::map::Entry; - - match (a, b) { - (Value::Object(a), Value::Object(b)) => { - for (key, b_value) in b { - match a.entry(key) { - Entry::Occupied(mut a_value) => merge_json_values(a_value.get_mut(), b_value), - Entry::Vacant(entry) => { - entry.insert(b_value); - } - } - } - } - (Value::Array(a), Value::Array(b)) => { - a.extend(b); - } - (a, b) => *a = b, - } -} - -fn inline_enum_refs(def: &mut Schema, enums: &BTreeMap) -> anyhow::Result<()> { - let mut def_value = serde_json::to_value(&def).unwrap(); - inline_enum_refs_imp(&mut def_value, enums)?; - *def = serde_json::from_value(def_value).unwrap(); - Ok(()) -} - -fn inline_enum_refs_imp( - def_value: &mut Value, - enums: &BTreeMap, -) -> anyhow::Result<()> { - let Some(def) = def_value.as_object_mut() else { - return Ok(()); - }; - - for property in def.values_mut() { - inline_enum_refs_imp(property, enums)?; - } - - let Some(reference) = def.get("$ref") else { - return Ok(()); - }; - - let reference = reference - .as_str() - .with_context(|| format!("Reference must be a string, but found: {reference}"))?; - - let reference = reference.strip_prefix("#/definitions/").with_context(|| { - format!("Reference not to #/definitions is not allowed, but found: {reference}") - })?; - - let Some(enum_def) = enums.get(reference) else { - return Ok(()); - }; - - def.remove("$ref"); - - let enum_def = serde_json::to_value(enum_def).unwrap(); - merge_json_values(def_value, enum_def); - - Ok(()) -} - -/// Generate the JSON schema based on the input YML schema. -pub(crate) fn codegen() -> anyhow::Result<()> { - let root_schema = fs::read_to_string("deny.schema.yml")?; - let mut root_schema: RootSchema = serde_yaml::from_str(&root_schema)?; - - let (enums, mut defs): (BTreeMap, BTreeMap<_, _>) = root_schema - .definitions - .into_iter() - .partition(|(_, val)| val.enum_values.is_some()); - - for def in defs.values_mut() { - inline_enum_refs(def, &enums)?; - } - - root_schema.definitions = itertools::concat([enums, defs]); - - let output = serde_json::to_string_pretty(&root_schema)?; - - std::fs::write("deny.schema.json", output)?; - - Ok(()) -} diff --git a/xtask/src/cli/codegen/md_doc.rs b/xtask/src/cli/codegen/md_doc.rs new file mode 100644 index 00000000..6205c6df --- /dev/null +++ b/xtask/src/cli/codegen/md_doc.rs @@ -0,0 +1,500 @@ +use super::input::{ArraySchema, EnumSchema, ObjectSchema, RootSchema, Schema}; +use anyhow::{Context, Result}; +use itertools::Itertools; +use serde_json::Value; +use std::collections::BTreeMap; +use std::fmt; +use std::path::Path; + +struct MdDoc { + sections: Vec, + type_index: BTreeMap, +} + +enum SchemaDoc { + /// Stores the documentation directly + Inline(SchemaDocInline), + + /// Refers to a type from the type index + Ref(String), +} + +struct SchemaDocInline { + header: String, + title: Option, + description: Option, + required: bool, + default: Option, + examples: Option>, +} + +impl MdDoc { + fn from_root_schema(root: &RootSchema) -> Result { + let mut sections = vec![]; + + let schemas_in_root = root.schema.inner_schemas(); + + let schemas_in_defs = root + .definitions + .values() + .flat_map(|schema| schema.inner_schemas()); + + let definition_ref_counts = itertools::chain(schemas_in_root, schemas_in_defs) + .map(Schema::referenced_definition) + .flatten_ok() + .process_results(Itertools::counts)?; + + let unused_defs: Vec<_> = root + .definitions + .iter() + .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) + .collect(); + + anyhow::ensure!( + unused_defs.is_empty(), + "Found unused definitions: {unused_defs:#?}", + ); + + let type_index: BTreeMap<_, _> = definition_ref_counts + .into_iter() + // For schemas that are repeatedly referenced, we want to include them in the + // "Type Index". This is separate page where common types are defined such + // that we don't duplicate their docs all over the place. + .filter(|(def_name, count)| *count > 1) + .map(|(def_name, _)| { + let schema = root.find_definition(def_name)?; + Ok((def_name.to_owned(), schema)) + }) + .try_collect()?; + + for (key, schema) in &root.schema.try_as_object()?.properties { + let schema = KeyedSchema::resolve(root, vec![], KeySegment::Field(key), schema)?; + + let section = SchemaSection::from_keyed_schema(&schema)?; + + sections.push(section); + } + + Ok(Self { + sections, + type_index, + }) + } +} + +pub(crate) fn gen(root: &RootSchema) -> Result<()> { + gen_root_doc(root)?; + + for (key, schema) in &root.schema.try_as_object()?.properties { + let schema = KeyedSchema::resolve(root, vec![], KeySegment::Field(key), schema)?; + + gen_section_doc(root, &schema)?; + } + + Ok(()) +} + +fn gen_section_doc(root: &RootSchema, section: &KeyedSchema<'_>) -> Result<()> { + let properties = gen_object_doc(root, 1, section, section.schema.try_as_object()?)?; + + let section_key = §ion.key.last().unwrap(); + + let content = format!( + "\ +# The `[{section_key}]` section + +{properties} +", + ); + + write_file(format!("{section_key}/cfg.md"), &content) +} + +#[derive(Clone, Debug)] +struct KeyedSchema<'a> { + key: Vec>, + schema: Schema, +} + +#[derive(Clone, Debug)] +enum KeySegment<'a> { + Field(&'a str), + Index, +} + +impl fmt::Display for KeySegment<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + KeySegment::Field(key) => write!(f, "{key}"), + KeySegment::Index => write!(f, "N"), + } + } +} + +impl KeySegment<'_> { + fn unwrap_field(&self) -> &str { + match self { + KeySegment::Field(key) => key, + KeySegment::Index => panic!("Expected field, found index"), + } + } +} + +impl<'a> KeyedSchema<'a> { + fn resolve( + root: &RootSchema, + parent_key: Vec>, + key: KeySegment<'a>, + schema: &Schema, + ) -> Result { + let mut new_key = parent_key; + new_key.push(key); + Ok(Self { + key: new_key, + schema: root.inline_referenced_definition(schema)?, + }) + } + + fn full_key(&self) -> String { + self.key + .iter() + .enumerate() + .map(|(i, key)| { + if let &KeySegment::Field(key) = key { + if i == 0 { + return key.to_owned(); + } + } + match key { + KeySegment::Field(_) => format!(".{key}"), + KeySegment::Index => format!("[{key}]"), + } + }) + .collect() + } +} + +fn gen_detailed_schema_doc( + root: &RootSchema, + paragraph_level: usize, + schema: &KeyedSchema<'_>, +) -> Result { + if let Some(array_schema) = &schema.schema.array_schema { + return gen_array_doc(root, paragraph_level + 1, schema, array_schema); + } + + if let Some(object) = &schema.schema.object_schema { + return gen_object_doc(root, paragraph_level + 1, schema, object); + } + + if let Some(enum_schema) = &schema.schema.enum_schema { + return gen_enum_doc(schema, enum_schema, paragraph_level + 1); + } + + if let Some(variants) = &schema.schema.one_of { + return gen_one_of_doc(root, schema, variants, paragraph_level); + } + + gen_primitive_type_doc(schema, paragraph_level) +} + +fn primitive_type_label(schema: &KeyedSchema<'_>) -> Result { + let ty = schema.schema.ty.as_deref().with_context(|| { + format!( + "Expected type for schema, but found none: `{}`.\nSchema: {:#?}", + schema.full_key(), + schema.schema + ) + })?; + + let format = schema + .schema + .format + .as_deref() + .map(|format| format!("({format})")); + + let doc = itertools::chain!([ty], format.as_deref()).join(" "); + + Ok(doc) +} + +fn gen_primitive_type_doc(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result { + let ty = primitive_type_label(schema)?; + let description = gen_generic_details(schema, paragraph_level)?; + + Ok(format!("`{ty}`\n\n{description}")) +} + +fn value_to_toml(schema: &KeyedSchema<'_>, value: &Value) -> Result { + fn wrap(key: &[KeySegment<'_>], value: &Value) -> Value { + let Some((first, rest)) = key.split_first() else { + return value.clone(); + }; + + match first { + KeySegment::Field(_) => { + serde_json::json!({ first.to_string(): wrap(rest, value) }) + } + KeySegment::Index => { + serde_json::json!([wrap(rest, value)]) + } + } + } + + let value = wrap(&schema.key, value); + + let toml = toml::to_string_pretty(&value) + .with_context(|| format!("Serialized value: {:#?}", value))?; + + Ok(format!( + "```toml\n\ + {toml}\ + ```", + )) +} + +fn gen_examples(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result> { + let examples = match schema.schema.examples.as_slice() { + [] => return Ok(None), + [example] => gen_value_showcase("Example", example, schema, paragraph_level)?, + examples => { + let examples = examples + .iter() + .map(|value| value_to_toml(schema, value)) + .collect::>>()? + .into_iter() + .format_with("\n", |example, f| { + let example = example + .lines() + .enumerate() + .format_with("\n", |(i, line), f| { + if i == 0 { + f(&line) + } else { + f(&format_args!(" {}", line)) + } + }); + + f(&format_args!("- {example}")) + }); + let paragraph = "#".repeat(paragraph_level + 1); + + format!("{paragraph} Examples\n\n{examples}") + } + }; + + Ok(Some(examples)) +} + +fn gen_default(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result> { + schema + .schema + .default + .as_ref() + .map(|value| gen_value_showcase("Default", value, schema, paragraph_level)) + .transpose() +} + +fn gen_value_showcase( + label: &str, + value: &Value, + schema: &KeyedSchema<'_>, + paragraph_level: usize, +) -> Result { + let toml = value_to_toml(schema, value)?; + let paragraph = "#".repeat(paragraph_level + 1); + let showcase = format!("{paragraph} {label}\n\n{toml}"); + Ok(showcase) +} + +fn gen_generic_details(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result { + let default = gen_default(schema, paragraph_level)?; + let examples = gen_examples(schema, paragraph_level)?; + + let details = [ + &default, + &schema.schema.title, + &schema.schema.description, + &examples, + ] + .into_iter() + .flatten() + .join("\n\n"); + + Ok(details) +} + +fn gen_one_of_doc( + root: &RootSchema, + schema: &KeyedSchema<'_>, + variants: &[Schema], + paragraph_level: usize, +) -> Result { + let variants = variants + .iter() + .map(|variant| { + let variant = KeyedSchema { + schema: root.inline_referenced_definition(variant)?, + key: schema.key.clone(), + }; + + let doc = gen_detailed_schema_doc(root, paragraph_level, &variant)?; + + Ok(doc) + }) + .collect::>>()? + .join("\n"); + + Ok(format!("**One of the following:**\n\n{variants}")) +} + +fn gen_enum_doc( + schema: &KeyedSchema<'_>, + enum_schema: &EnumSchema, + paragraph_level: usize, +) -> Result { + let doc = enum_schema + .values_and_descriptions() + .map(|(value, description)| { + let value = value.to_string(); + let description = description + .map(|description| format!(" - {}", description)) + .unwrap_or_default(); + + Ok(format!("* `{value}`{description}")) + }) + .collect::>>()? + .join("\n"); + + let paragraph = "#".repeat(paragraph_level); + + let details = gen_generic_details(schema, paragraph_level)?; + + let doc = format!("\n\n{paragraph} Possible values\n\n{doc}\n---\n{details}"); + + Ok(doc) +} + +fn gen_object_doc( + root: &RootSchema, + paragraph_level: usize, + schema: &KeyedSchema<'_>, + object: &ObjectSchema, +) -> Result { + let object_details = gen_generic_details(schema, paragraph_level)?; + + let properties = object + .properties + .iter() + .map(|(key, value)| { + let field = + KeyedSchema::resolve(root, schema.key.clone(), KeySegment::Field(key), value)?; + + gen_object_property_doc(root, paragraph_level + 1, object, &field) + }) + .collect::>>()? + .join("\n\n"); + + Ok([object_details, properties].join("\n\n")) +} + +fn gen_array_doc( + root: &RootSchema, + paragraph_level: usize, + schema: &KeyedSchema<'_>, + array: &ArraySchema, +) -> Result { + let array_details = gen_generic_details(schema, paragraph_level)?; + + let items = KeyedSchema::resolve(root, schema.key.clone(), KeySegment::Index, &array.items)?; + + if items.schema.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { + let ty = primitive_type_label(&items)?; + return Ok(format!( + "`array of {ty}`\n\n\ + {array_details}" + )); + } + + let paragraph = "#".repeat(paragraph_level); + + let details = gen_detailed_schema_doc(root, paragraph_level, &items)?; + + let doc = format!( + "`array`\n\n\ + {array_details}\n\n\ + {paragraph} Items\n\n\ + {details}" + ); + + Ok(doc) +} + +fn gen_object_property_doc( + root: &RootSchema, + paragraph_level: usize, + object: &ObjectSchema, + property: &KeyedSchema<'_>, +) -> Result { + let full_key = property.full_key(); + + let property_key = property.key.last().unwrap().unwrap_field(); + + let requirement = if object.required.contains(property_key) { + "required" + } else { + "optional" + }; + + let paragraph = "#".repeat(paragraph_level); + + let details = gen_detailed_schema_doc(root, paragraph_level, property)?; + + let doc = format!( + "{paragraph} `{full_key}` ({requirement})\n\n\ + {details}" + ); + + Ok(doc) +} + +fn gen_root_doc(root: &RootSchema) -> Result<()> { + let sections = root + .schema + .try_as_object()? + .properties + .keys() + .map(|section| { + format!( + "## The `[{section}]` section\n\n\ + See [{section} config]({section}/cfg.html) for more info." + ) + }) + .join("\n\n"); + + let content = format!( + "\ +# config + +The top level config for cargo-deny, by default called `deny.toml`. + +## Example - cargo-deny's own configuration + +```ini +{{{{#include ../../../deny.toml}}}} +``` + +{sections}" + ); + + write_file("cfg.md", &content) +} + +fn write_file(path: impl AsRef, content: &str) -> Result<()> { + let path = std::path::Path::new("docs/src/checks2").join(path); + + std::fs::create_dir_all(&path.parent().unwrap())?; + + std::fs::write(&path, content) + .with_context(|| format!("Failed to write to file: {}", path.display())) +} From 484e1fe1e9160a56371a73a81a538b148225e96d Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 7 Apr 2024 16:22:44 +0000 Subject: [PATCH 06/20] Next iteration --- deny.schema.yml | 48 ++- xtask/src/cli/codegen/input.rs | 80 +++- .../cli/codegen/{md_doc.rs => md_doc/mod.rs} | 394 ++++++++++++------ 3 files changed, 362 insertions(+), 160 deletions(-) rename xtask/src/cli/codegen/{md_doc.rs => md_doc/mod.rs} (53%) diff --git a/deny.schema.yml b/deny.schema.yml index ac096d59..39559cdb 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -35,9 +35,9 @@ description: Full documentation is at https://embarkstudios.github.io/cargo-deny type: object properties: - advisories: { $ref: '#/definitions/advisories' } - graph: { $ref: '#/definitions/graph' } - output: { $ref: '#/definitions/output' } + advisories: { $ref: "#/definitions/advisories" } + graph: { $ref: "#/definitions/graph" } + output: { $ref: "#/definitions/output" } definitions: advisories: @@ -110,7 +110,7 @@ definitions: vulnerability: deprecated: true - $ref: '#/definitions/lint-level' + $ref: "#/definitions/lint-level" default: deny description: | **DEPRECATED** (see `version` field) @@ -119,7 +119,7 @@ definitions: unmaintained: deprecated: true - $ref: '#/definitions/lint-level' + $ref: "#/definitions/lint-level" default: warn description: | **DEPRECATED** (see `version` field) @@ -128,7 +128,7 @@ definitions: unsound: deprecated: true - $ref: '#/definitions/lint-level' + $ref: "#/definitions/lint-level" default: warn description: | **DEPRECATED** (see `version` field) @@ -137,7 +137,7 @@ definitions: notice: deprecated: true - $ref: '#/definitions/lint-level' + $ref: "#/definitions/lint-level" default: warn description: | **DEPRECATED** (see `version` field) @@ -148,7 +148,7 @@ definitions: [RustSec Advisory DB](https://github.com/RustSec/advisory-db) yanked: - $ref: '#/definitions/lint-level' + $ref: "#/definitions/lint-level" default: warn description: | Determines what happens when a crate with a version that has been yanked from its source @@ -156,7 +156,7 @@ definitions: ignore: type: array - items: { $ref: '#/definitions/advisories-ignore-item' } + items: { $ref: "#/definitions/advisories-ignore-item" } examples: - - RUSTSEC-0000-0000 - id: "RUSTSEC-0000-0000" @@ -175,10 +175,15 @@ definitions: advisories-ignore-item: oneOf: - - type: string + - variant: String + type: string description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - - { $ref: '#/definitions/advisories-ignore-advisory' } - - { $ref: '#/definitions/advisories-ignore-yanked' } + + - variant: Advisory + $ref: "#/definitions/advisories-ignore-advisory" + + - variant: Yanked + $ref: "#/definitions/advisories-ignore-yanked" advisories-ignore-advisory: type: object @@ -188,14 +193,14 @@ definitions: type: string examples: [RUSTSEC-2019-0001] description: The unique identifier of the advisory to ignore - reason: { $ref: '#/definitions/ignore-reason' } + reason: { $ref: "#/definitions/ignore-reason" } advisories-ignore-yanked: type: object required: [crate] properties: - crate: { $ref: '#/definitions/package-spec' } - reason: { $ref: '#/definitions/ignore-reason' } + crate: { $ref: "#/definitions/package-spec" } + reason: { $ref: "#/definitions/ignore-reason" } ignore-reason: type: string @@ -299,7 +304,7 @@ definitions: properties: targets: type: array - items: { $ref: '#/definitions/target' } + items: { $ref: "#/definitions/target" } description: | By default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies e.g. @@ -361,15 +366,18 @@ definitions: target: oneOf: - - $ref: '#/definitions/target-string' - - $ref: '#/definitions/target-complex' + - variant: String + $ref: "#/definitions/target-string" + + - variant: Advanced + $ref: "#/definitions/target-advanced" - target-complex: + target-advanced: description: Advanced configurations to apply for the target triple type: object required: [triple] properties: - triple: { $ref: '#/definitions/target-string' } + triple: { $ref: "#/definitions/target-string" } features: type: string description: | diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/input.rs index de962ef7..97cc194d 100644 --- a/xtask/src/cli/codegen/input.rs +++ b/xtask/src/cli/codegen/input.rs @@ -45,7 +45,7 @@ pub(crate) struct Schema { pub(crate) enum_schema: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] - pub(crate) one_of: Option>, + pub(crate) one_of: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) title: Option, @@ -78,7 +78,16 @@ pub(crate) struct CustomEnumSchema { pub(crate) description: String, } -pub(crate) struct OneOfSchema {} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct VariantSchema { + /// Name of the variant. It's main use case is when generating a Rust enum, + /// which requires a name for each variant. However, it's also useful for + /// documentation purposes as a succinct display name for the variant. + pub(crate) name: String, + + #[serde(flatten)] + pub(crate) schema: Schema, +} // /// Unfortunately we can't use an internally-tagged enum here with associated data // /// because when flattening such enum with `#[serde(flatten)]` we end up with @@ -129,14 +138,25 @@ impl Schema { std::iter::from_fn(move || { let schema = stack.pop()?; - let properties = schema + let object_properties = schema .object_schema .iter() .flat_map(|object| object.properties.values()); - stack.extend(properties); - stack.extend(schema.array_schema.iter().map(|array| array.items.as_ref())); - stack.extend(schema.one_of.iter().flatten()); + let one_of_variants = schema + .one_of + .iter() + .flatten() + .map(|variant| &variant.schema); + + let array_items = schema.array_schema.iter().map(|array| array.items.as_ref()); + + stack.extend(itertools::chain!( + object_properties, + one_of_variants, + array_items + )); + Some(schema) }) } @@ -153,16 +173,56 @@ impl Schema { } if let Some(one_of) = &mut self.one_of { - one_of.iter_mut().try_for_each(&visit)?; + one_of + .iter_mut() + .map(|variant| &mut variant.schema) + .try_for_each(&visit)?; } Ok(()) } - pub(crate) fn try_as_object(&self) -> Result<&ObjectSchema> { - self.object_schema + fn try_downcast_as(&self, schema: &Option, label: &str) -> Result<&T> { + schema .as_ref() - .with_context(|| format!("Expected object schema, but got {self:#?}")) + .with_context(|| format!("Expected {label} schema, but got {self:#?}")) + } + + fn try_downcast_into(self, schema: Option, label: &str) -> Result { + schema.with_context(|| format!("Expected {label} schema, but got {self:#?}")) + } + + pub(crate) fn try_as_array(&self) -> Result<&ArraySchema> { + self.try_downcast_as(&self.array_schema, "array") + } + + pub(crate) fn try_into_array(self) -> Result { + self.try_downcast_into(self.array_schema, "array") + } + + pub(crate) fn try_as_object(&self) -> Result<&ObjectSchema> { + self.try_downcast_as(&self.object_schema, "object") + } + + pub(crate) fn try_into_object(self) -> Result { + self.try_downcast_into(self.object_schema, "object") + } + + pub(crate) fn try_as_enum(&self) -> Result<&EnumSchema> { + self.try_downcast_as(&self.enum_schema, "enum") + } + + pub(crate) fn try_into_enum(self) -> Result { + self.try_downcast_into(self.enum_schema, "enum") + } + + pub(crate) fn try_as_one_of(&self) -> Result<&[VariantSchema]> { + self.try_downcast_as(&self.one_of, "one-of") + .map(Vec::as_slice) + } + + pub(crate) fn try_into_one_of(self) -> Result> { + self.try_downcast_into(self.one_of, "one-of") } pub(crate) fn try_description(&self) -> Result<&str> { diff --git a/xtask/src/cli/codegen/md_doc.rs b/xtask/src/cli/codegen/md_doc/mod.rs similarity index 53% rename from xtask/src/cli/codegen/md_doc.rs rename to xtask/src/cli/codegen/md_doc/mod.rs index 6205c6df..c2664425 100644 --- a/xtask/src/cli/codegen/md_doc.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -4,40 +4,33 @@ use itertools::Itertools; use serde_json::Value; use std::collections::BTreeMap; use std::fmt; -use std::path::Path; -struct MdDoc { - sections: Vec, - type_index: BTreeMap, +struct Doc { + root: Section, + type_index: BTreeMap, } -enum SchemaDoc { - /// Stores the documentation directly - Inline(SchemaDocInline), - - /// Refers to a type from the type index - Ref(String), -} - -struct SchemaDocInline { - header: String, +struct SectionData { + key: SchemaKey, title: Option, description: Option, - required: bool, default: Option, - examples: Option>, + examples: Vec, + format: Option, + ty: Option, + enum_schema: Option, + type_index_ref: Option, } -impl MdDoc { - fn from_root_schema(root: &RootSchema) -> Result { - let mut sections = vec![]; +struct Section { + data: SectionData, + children: Vec
, +} +impl Doc { + fn from_root_schema(root: &RootSchema) -> Result { let schemas_in_root = root.schema.inner_schemas(); - - let schemas_in_defs = root - .definitions - .values() - .flat_map(|schema| schema.inner_schemas()); + let schemas_in_defs = root.definitions.values().flat_map(Schema::inner_schemas); let definition_ref_counts = itertools::chain(schemas_in_root, schemas_in_defs) .map(Schema::referenced_definition) @@ -63,30 +56,179 @@ impl MdDoc { .filter(|(def_name, count)| *count > 1) .map(|(def_name, _)| { let schema = root.find_definition(def_name)?; - Ok((def_name.to_owned(), schema)) + anyhow::Ok((def_name.to_owned(), schema)) }) .try_collect()?; - for (key, schema) in &root.schema.try_as_object()?.properties { - let schema = KeyedSchema::resolve(root, vec![], KeySegment::Field(key), schema)?; + let ctx = RootContext { + root, + type_index: &type_index, + }; + + Ok(Self { + root: ctx.root_section()?, + type_index: ctx.type_index_sections()?, + }) + } +} + +struct RootContext<'a> { + root: &'a RootSchema, + type_index: &'a BTreeMap, +} + +impl RootContext<'_> { + fn root_section(&self) -> Result
{ + let key = SchemaKey { + root: SchemaRoot::Root, + segments: vec![], + }; + let root_schema = KeyedSchema::new(key, self.root.schema.clone()); + self.section(root_schema) + } + + fn type_index_sections(&self) -> Result> { + self.type_index + .iter() + .map(|(def_name, &schema)| { + let key = SchemaKey { + root: SchemaRoot::Definition(def_name.clone()), + segments: vec![], + }; + let schema = KeyedSchema::new(key, schema.clone()); + + anyhow::Ok((def_name.clone(), self.section(schema)?)) + }) + .collect() + } - let section = SchemaSection::from_keyed_schema(&schema)?; + fn section(&self, schema: KeyedSchema) -> Result
{ + let section_data = self.section_data(schema.clone())?; - sections.push(section); + let referenced_def = schema.inner.referenced_definition()?; + + // If this schema references a type from the type index, then avoid + // inlining the schema and finish the section early. + if referenced_def.is_some_and(|def| self.type_index.contains_key(def)) { + return Ok(Section::leaf(section_data)); } - Ok(Self { - sections, - type_index, + let schema = schema.inline_referenced_definition(&self.root)?; + + let children = if schema.inner.array_schema.is_some() { + self.array_children(schema)? + } else if schema.inner.object_schema.is_some() { + self.object_children(schema)? + } else if schema.inner.one_of.is_some() { + self.one_of_children(schema)? + } else { + vec![] + }; + + let children = children + .into_iter() + .map(|child| self.section(child)) + .try_collect()?; + + Ok(Section { + data: section_data, + children, }) } + + fn array_children(&self, schema: KeyedSchema) -> Result> { + let array = schema.inner.try_into_array()?; + let key = schema.key.next_level(SchemaKeySegment::Index); + let items = KeyedSchema::new(key, *array.items); + Ok(vec![items]) + } + + fn object_children(&self, schema: KeyedSchema) -> Result> { + let object = schema.inner.try_into_object()?; + let properties = object + .properties + .into_iter() + .map(|(key, value)| { + let key = SchemaKeySegmentField { + name: key.clone(), + required: object.required.contains(&key), + }; + + let key = schema.key.next_level(SchemaKeySegment::Field(key)); + KeyedSchema::new(key, value) + }) + .collect(); + + Ok(properties) + } + + fn one_of_children(&self, schema: KeyedSchema) -> Result> { + let variants = schema.inner.try_into_one_of()?; + + let duplicates: Vec<_> = variants + .iter() + .map(|variant| &variant.name) + .duplicates() + .collect(); + + anyhow::ensure!( + duplicates.is_empty(), + "Duplicate variant names found in one_of schema.\n\ + Duplicates: {duplicates:?}\n\ + Variants: {variants:#?}", + ); + + let variants = variants + .into_iter() + .map(|variant| { + let key = schema + .key + .next_level(SchemaKeySegment::Variant(variant.name.clone())); + + KeyedSchema::new(key, variant.schema) + }) + .collect(); + + Ok(variants) + } + + fn section_data(&self, schema: KeyedSchema) -> Result { + let type_index_ref = schema + .inner + .referenced_definition()? + .filter(|&def_name| self.type_index.contains_key(def_name)) + .map(ToOwned::to_owned); + + let base = SectionData { + key: schema.key, + title: schema.inner.title, + description: schema.inner.description, + default: schema.inner.default, + examples: schema.inner.examples, + format: schema.inner.format, + ty: schema.inner.ty, + enum_schema: schema.inner.enum_schema, + type_index_ref, + }; + + Ok(base) + } +} + +impl Section { + fn leaf(data: SectionData) -> Self { + Self { + data, + children: vec![], + } + } } pub(crate) fn gen(root: &RootSchema) -> Result<()> { gen_root_doc(root)?; for (key, schema) in &root.schema.try_as_object()?.properties { - let schema = KeyedSchema::resolve(root, vec![], KeySegment::Field(key), schema)?; + let schema = KeyedSchema::inlined(root, vec![], SchemaKeySegment::Field(key), schema)?; gen_section_doc(root, &schema)?; } @@ -95,7 +237,7 @@ pub(crate) fn gen(root: &RootSchema) -> Result<()> { } fn gen_section_doc(root: &RootSchema, section: &KeyedSchema<'_>) -> Result<()> { - let properties = gen_object_doc(root, 1, section, section.schema.try_as_object()?)?; + let properties = gen_object_doc(root, 1, section, section.inner.try_as_object()?)?; let section_key = §ion.key.last().unwrap(); @@ -111,66 +253,93 @@ fn gen_section_doc(root: &RootSchema, section: &KeyedSchema<'_>) -> Result<()> { } #[derive(Clone, Debug)] -struct KeyedSchema<'a> { - key: Vec>, - schema: Schema, +struct KeyedSchema { + key: SchemaKey, + inner: Schema, +} + +#[derive(Clone, Debug)] +struct SchemaKey { + root: SchemaRoot, + segments: Vec, +} + +#[derive(Clone, Debug)] +enum SchemaRoot { + Root, + Definition(String), } #[derive(Clone, Debug)] -enum KeySegment<'a> { - Field(&'a str), +enum SchemaKeySegment { + Field(SchemaKeySegmentField), Index, + Variant(String), } -impl fmt::Display for KeySegment<'_> { +#[derive(Clone, Debug)] +struct SchemaKeySegmentField { + name: String, + required: bool, +} + +impl fmt::Display for SchemaKeySegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - KeySegment::Field(key) => write!(f, "{key}"), - KeySegment::Index => write!(f, "N"), + SchemaKeySegment::Field(field) => f.write_str(&field.name), + SchemaKeySegment::Index => f.write_str("N"), + SchemaKeySegment::Variant(name) => f.write_str(name), } } } -impl KeySegment<'_> { - fn unwrap_field(&self) -> &str { +impl SchemaKeySegment { + fn unwrap_field(&self) -> &SchemaKeySegmentField { match self { - KeySegment::Field(key) => key, - KeySegment::Index => panic!("Expected field, found index"), + SchemaKeySegment::Field(field) => field, + _ => panic!("Expected field, found: {self:#?}"), } } } -impl<'a> KeyedSchema<'a> { - fn resolve( - root: &RootSchema, - parent_key: Vec>, - key: KeySegment<'a>, - schema: &Schema, - ) -> Result { - let mut new_key = parent_key; - new_key.push(key); - Ok(Self { - key: new_key, - schema: root.inline_referenced_definition(schema)?, +impl SchemaKey { + fn next_level(&self, new_segment: SchemaKeySegment) -> Self { + let mut segments = self.segments.clone(); + segments.push(new_segment); + Self { segments } + } + + fn last_segment(&self) -> &SchemaKeySegment { + self.segments.last().unwrap() + } +} + +impl fmt::Display for SchemaKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut segments = self.segments.iter(); + + if let Some(segment) = segments.next() { + write!(f, "{segment}")?; + } + + segments.try_for_each(|segment| match segment { + SchemaKeySegment::Field(_) => write!(f, ".{segment}"), + SchemaKeySegment::Index => write!(f, "[{segment}]"), + SchemaKeySegment::Variant(_) => write!(f, " (as {segment})"), }) } +} - fn full_key(&self) -> String { - self.key - .iter() - .enumerate() - .map(|(i, key)| { - if let &KeySegment::Field(key) = key { - if i == 0 { - return key.to_owned(); - } - } - match key { - KeySegment::Field(_) => format!(".{key}"), - KeySegment::Index => format!("[{key}]"), - } - }) - .collect() +impl KeyedSchema { + fn new(key: SchemaKey, inner: Schema) -> Self { + Self { key, inner } + } + + fn inline_referenced_definition(self, root: &RootSchema) -> Result { + Ok(Self::new( + self.key, + root.inline_referenced_definition(&self.inner)?, + )) } } @@ -179,19 +348,19 @@ fn gen_detailed_schema_doc( paragraph_level: usize, schema: &KeyedSchema<'_>, ) -> Result { - if let Some(array_schema) = &schema.schema.array_schema { + if let Some(array_schema) = &schema.inner.array_schema { return gen_array_doc(root, paragraph_level + 1, schema, array_schema); } - if let Some(object) = &schema.schema.object_schema { + if let Some(object) = &schema.inner.object_schema { return gen_object_doc(root, paragraph_level + 1, schema, object); } - if let Some(enum_schema) = &schema.schema.enum_schema { + if let Some(enum_schema) = &schema.inner.enum_schema { return gen_enum_doc(schema, enum_schema, paragraph_level + 1); } - if let Some(variants) = &schema.schema.one_of { + if let Some(variants) = &schema.inner.one_of { return gen_one_of_doc(root, schema, variants, paragraph_level); } @@ -199,16 +368,16 @@ fn gen_detailed_schema_doc( } fn primitive_type_label(schema: &KeyedSchema<'_>) -> Result { - let ty = schema.schema.ty.as_deref().with_context(|| { + let ty = schema.inner.ty.as_deref().with_context(|| { format!( "Expected type for schema, but found none: `{}`.\nSchema: {:#?}", schema.full_key(), - schema.schema + schema.inner ) })?; let format = schema - .schema + .inner .format .as_deref() .map(|format| format!("({format})")); @@ -226,16 +395,16 @@ fn gen_primitive_type_doc(schema: &KeyedSchema<'_>, paragraph_level: usize) -> R } fn value_to_toml(schema: &KeyedSchema<'_>, value: &Value) -> Result { - fn wrap(key: &[KeySegment<'_>], value: &Value) -> Value { + fn wrap(key: &[SchemaKeySegment], value: &Value) -> Value { let Some((first, rest)) = key.split_first() else { return value.clone(); }; match first { - KeySegment::Field(_) => { + SchemaKeySegment::Field(_) => { serde_json::json!({ first.to_string(): wrap(rest, value) }) } - KeySegment::Index => { + SchemaKeySegment::Index => { serde_json::json!([wrap(rest, value)]) } } @@ -254,7 +423,7 @@ fn value_to_toml(schema: &KeyedSchema<'_>, value: &Value) -> Result { } fn gen_examples(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result> { - let examples = match schema.schema.examples.as_slice() { + let examples = match schema.inner.examples.as_slice() { [] => return Ok(None), [example] => gen_value_showcase("Example", example, schema, paragraph_level)?, examples => { @@ -288,7 +457,7 @@ fn gen_examples(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result, paragraph_level: usize) -> Result> { schema - .schema + .inner .default .as_ref() .map(|value| gen_value_showcase("Default", value, schema, paragraph_level)) @@ -307,23 +476,6 @@ fn gen_value_showcase( Ok(showcase) } -fn gen_generic_details(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result { - let default = gen_default(schema, paragraph_level)?; - let examples = gen_examples(schema, paragraph_level)?; - - let details = [ - &default, - &schema.schema.title, - &schema.schema.description, - &examples, - ] - .into_iter() - .flatten() - .join("\n\n"); - - Ok(details) -} - fn gen_one_of_doc( root: &RootSchema, schema: &KeyedSchema<'_>, @@ -334,7 +486,7 @@ fn gen_one_of_doc( .iter() .map(|variant| { let variant = KeyedSchema { - schema: root.inline_referenced_definition(variant)?, + inner: root.inline_referenced_definition(variant)?, key: schema.key.clone(), }; @@ -375,29 +527,6 @@ fn gen_enum_doc( Ok(doc) } -fn gen_object_doc( - root: &RootSchema, - paragraph_level: usize, - schema: &KeyedSchema<'_>, - object: &ObjectSchema, -) -> Result { - let object_details = gen_generic_details(schema, paragraph_level)?; - - let properties = object - .properties - .iter() - .map(|(key, value)| { - let field = - KeyedSchema::resolve(root, schema.key.clone(), KeySegment::Field(key), value)?; - - gen_object_property_doc(root, paragraph_level + 1, object, &field) - }) - .collect::>>()? - .join("\n\n"); - - Ok([object_details, properties].join("\n\n")) -} - fn gen_array_doc( root: &RootSchema, paragraph_level: usize, @@ -406,9 +535,14 @@ fn gen_array_doc( ) -> Result { let array_details = gen_generic_details(schema, paragraph_level)?; - let items = KeyedSchema::resolve(root, schema.key.clone(), KeySegment::Index, &array.items)?; + let items = KeyedSchema::inlined( + root, + schema.key.clone(), + SchemaKeySegment::Index, + &array.items, + )?; - if items.schema.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { + if items.inner.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { let ty = primitive_type_label(&items)?; return Ok(format!( "`array of {ty}`\n\n\ @@ -490,7 +624,7 @@ The top level config for cargo-deny, by default called `deny.toml`. write_file("cfg.md", &content) } -fn write_file(path: impl AsRef, content: &str) -> Result<()> { +fn write_file(path: impl AsRef, content: &str) -> Result<()> { let path = std::path::Path::new("docs/src/checks2").join(path); std::fs::create_dir_all(&path.parent().unwrap())?; From 3a4487f7707605aacd2e6f4b8e384be2d9b6381d Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 7 Apr 2024 18:27:36 +0000 Subject: [PATCH 07/20] Next iteration --- Cargo.lock | 1 + deny.schema.json | 148 +++++-- deny.schema.yml | 12 +- docs/src/checks2/advisories/cfg.md | 141 +++---- docs/src/checks2/cfg.md | 2 +- docs/src/checks2/graph/cfg.md | 73 ++-- docs/src/checks2/output/cfg.md | 16 +- xtask/Cargo.toml | 3 + xtask/src/cli/codegen/input.rs | 76 ++-- xtask/src/cli/codegen/json_schema.rs | 24 +- xtask/src/cli/codegen/md_doc/mod.rs | 446 ++++------------------ xtask/src/cli/codegen/md_doc/rendering.rs | 275 +++++++++++++ 12 files changed, 613 insertions(+), 604 deletions(-) create mode 100644 xtask/src/cli/codegen/md_doc/rendering.rs diff --git a/Cargo.lock b/Cargo.lock index 1e60eab8..5042ca47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3363,6 +3363,7 @@ name = "xtask" version = "0.1.0" dependencies = [ "anyhow", + "camino", "clap", "indexmap", "itertools", diff --git a/deny.schema.json b/deny.schema.json index 36ecd1e6..ee17dadc 100644 --- a/deny.schema.json +++ b/deny.schema.json @@ -11,7 +11,7 @@ "$ref": "#/definitions/output" } }, - "title": "cargo-deny configuration file", + "title": "Configuration file for cargo-deny, by default called `deny.toml`.", "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", "definitions": { "advisories": { @@ -60,23 +60,39 @@ "enum": [ 2 ], - "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" + "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n", + "x-taplo": { + "docs": { + "enumValues": [ + "" + ] + } + } }, "vulnerability": { "deprecated": true, "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n", "default": "deny", "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } @@ -84,18 +100,27 @@ "unmaintained": { "deprecated": true, "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } @@ -103,18 +128,27 @@ "unsound": { "deprecated": true, "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } @@ -122,36 +156,54 @@ "notice": { "deprecated": true, "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } }, "yanked": { "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } @@ -201,13 +253,16 @@ "advisories-ignore-item": { "oneOf": [ { + "name": "String", "type": "string", "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." }, { + "name": "Advisory", "$ref": "#/definitions/advisories-ignore-advisory" }, { + "name": "Yanked", "$ref": "#/definitions/advisories-ignore-yanked" } ] @@ -277,16 +332,25 @@ }, "lint-level": { "enum": [ - "deny", - "warn", - "allow" + { + "value": "deny", + "description": "Emit an error with details about the problem, and fail the check." + }, + { + "value": "warn", + "description": "Print a warning for each propblem, but don't fail the check." + }, + { + "value": "allow", + "description": "Print a note about the problem, but don't fail the check." + } ], "x-taplo": { "docs": { "enumValues": [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." + "", + "", + "" ] } } @@ -309,14 +373,16 @@ "target": { "oneOf": [ { + "name": "String", "$ref": "#/definitions/target-string" }, { - "$ref": "#/definitions/target-complex" + "name": "Advanced", + "$ref": "#/definitions/target-advanced" } ] }, - "target-complex": { + "target-advanced": { "type": "object", "examples": [ { @@ -367,6 +433,6 @@ "$ref": "#/definitions/output" } }, - "title": "cargo-deny configuration file", + "title": "Configuration file for cargo-deny, by default called `deny.toml`.", "type": "object" } \ No newline at end of file diff --git a/deny.schema.yml b/deny.schema.yml index 39559cdb..ba03b148 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -30,7 +30,7 @@ $schema: https://json-schema.org/draft-07/schema# $id: https://github.com/EmbarkStudios/cargo-deny/deny.schema.json -title: cargo-deny configuration file +title: Configuration file for cargo-deny, by default called `deny.toml`. description: Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html type: object @@ -175,14 +175,14 @@ definitions: advisories-ignore-item: oneOf: - - variant: String + - name: String type: string description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - - variant: Advisory + - name: Advisory $ref: "#/definitions/advisories-ignore-advisory" - - variant: Yanked + - name: Yanked $ref: "#/definitions/advisories-ignore-yanked" advisories-ignore-advisory: @@ -366,10 +366,10 @@ definitions: target: oneOf: - - variant: String + - name: String $ref: "#/definitions/target-string" - - variant: Advanced + - name: Advanced $ref: "#/definitions/target-advanced" target-advanced: diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md index bbbaf6f4..682bfe77 100644 --- a/docs/src/checks2/advisories/cfg.md +++ b/docs/src/checks2/advisories/cfg.md @@ -1,4 +1,6 @@ -# The `[advisories]` section +# `advisories` (optional) + +`object` Checks advisory databases for crates with security vulnerabilities, or that have been marked as Unmaintained, or which have been yanked from @@ -28,28 +30,25 @@ severity-threshold = "medium" ## `advisories.db-urls` (optional) -`array of string (uri)` +`array` + +URLs to one or more advisory databases. -#### Default +### Default ```toml [advisories] db-urls = ["https://github.com/RustSec/advisory-db"] ``` -URLs to one or more advisory databases. +### Items + +`string (uri)` ## `advisories.db-path` (optional) `string` -### Default - -```toml -[advisories] -db-path = "$CARGO_HOME/advisory-dbs" -``` - Path to the root directory into which one or more advisory databases are cloned into. This value supports basic shell expansion: @@ -65,14 +64,17 @@ This value supports basic shell expansion: Note that the path must be valid utf-8, after expansion. -## `advisories.version` (optional) +### Default +```toml +[advisories] +db-path = "$CARGO_HOME/advisory-dbs" +``` +## `advisories.version` (optional) -### Possible values +`integer` -* `2` ---- The advisories section has an upcoming breaking change, with deprecation warnings for several fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. @@ -87,118 +89,82 @@ The breaking change is as follows: As before, if you want to ignore a specific advisory, add it to the `ignore` field. +### Possible values + +2 + ## `advisories.vulnerability` (optional) +**DEPRECATED** (see `version` field) +Determines what happens when a crate with a security vulnerability is encountered. -### Possible values -* `"deny"` - Emit an error with details about the problem, and fail the check. -* `"warn"` - Print a warning for each propblem, but don't fail the check. -* `"allow"` - Print a note about the problem, but don't fail the check. ---- -#### Default +### Default ```toml [advisories] vulnerability = "deny" ``` -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a security vulnerability is encountered. - - ## `advisories.unmaintained` (optional) +**DEPRECATED** (see `version` field) +Determines what happens when a crate with an `unmaintained` advisory is encountered. -### Possible values -* `"deny"` - Emit an error with details about the problem, and fail the check. -* `"warn"` - Print a warning for each propblem, but don't fail the check. -* `"allow"` - Print a note about the problem, but don't fail the check. ---- -#### Default +### Default ```toml [advisories] unmaintained = "warn" ``` -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unmaintained` advisory is encountered. - - ## `advisories.unsound` (optional) +**DEPRECATED** (see `version` field) +Determines what happens when a crate with an `unsound` advisory is encountered. -### Possible values -* `"deny"` - Emit an error with details about the problem, and fail the check. -* `"warn"` - Print a warning for each propblem, but don't fail the check. -* `"allow"` - Print a note about the problem, but don't fail the check. ---- -#### Default +### Default ```toml [advisories] unsound = "warn" ``` -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unsound` advisory is encountered. - - ## `advisories.notice` (optional) +**DEPRECATED** (see `version` field) +Determines what happens when a crate with a `notice` advisory is encountered. + +**NOTE**: As of 2019-12-17 there are no `notice` advisories in the +[RustSec Advisory DB](https://github.com/RustSec/advisory-db) -### Possible values -* `"deny"` - Emit an error with details about the problem, and fail the check. -* `"warn"` - Print a warning for each propblem, but don't fail the check. -* `"allow"` - Print a note about the problem, but don't fail the check. ---- -#### Default +### Default ```toml [advisories] notice = "warn" ``` -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a `notice` advisory is encountered. - -**NOTE**: As of 2019-12-17 there are no `notice` advisories in the -[RustSec Advisory DB](https://github.com/RustSec/advisory-db) - - ## `advisories.yanked` (optional) +Determines what happens when a crate with a version that has been yanked from its source +registry is encountered. -### Possible values - -* `"deny"` - Emit an error with details about the problem, and fail the check. -* `"warn"` - Print a warning for each propblem, but don't fail the check. -* `"allow"` - Print a note about the problem, but don't fail the check. ---- -#### Default +### Default ```toml [advisories] yanked = "warn" ``` -Determines what happens when a crate with a version that has been yanked from its source -registry is encountered. - - ## `advisories.ignore` (optional) `array` @@ -211,7 +177,7 @@ In addition, yanked crate versions can be ignored by specifying a [PackageSpec]( with an optional `reason`. -#### Example +### Example ```toml [advisories] @@ -225,14 +191,19 @@ ignore = [ ### Items -**One of the following:** + + +#### `advisories.ignore[N] (as String)` (as String) `string` Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). +#### `advisories.ignore[N] (as Advisory)` (as Advisory) + +`object` -##### `advisories.ignore[N].id` (required) +##### `advisories.ignore[N] (as Advisory).id` (required) `string` @@ -241,18 +212,19 @@ The unique identifier of the advisory to ignore ###### Example ```toml -[[advisories.ignore]] -id = "RUSTSEC-2019-0001" +[advisories] +ignore = ["RUSTSEC-2019-0001"] ``` -##### `advisories.ignore[N].reason` (optional) +##### `advisories.ignore[N] (as Advisory).reason` (optional) + -`string` -Free-form string that can be used to describe the reason why the advisory is ignored. +#### `advisories.ignore[N] (as Yanked)` (as Yanked) +`object` -##### `advisories.ignore[N].crate` (required) +##### `advisories.ignore[N] (as Yanked).crate` (required) `string` @@ -327,8 +299,5 @@ The old format uses a required `name` key and an optional `version` key. This fo and should not be used. -##### `advisories.ignore[N].reason` (optional) - -`string` +##### `advisories.ignore[N] (as Yanked).reason` (optional) -Free-form string that can be used to describe the reason why the advisory is ignored. diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md index 6606eefa..3bcfb05f 100644 --- a/docs/src/checks2/cfg.md +++ b/docs/src/checks2/cfg.md @@ -5,7 +5,7 @@ The top level config for cargo-deny, by default called `deny.toml`. ## Example - cargo-deny's own configuration ```ini -{{#include ../../../deny.toml}} +{{{{#include ../../../deny.toml}}}} ``` ## The `[advisories]` section diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md index a4c39cb8..b2faf310 100644 --- a/docs/src/checks2/graph/cfg.md +++ b/docs/src/checks2/graph/cfg.md @@ -1,4 +1,6 @@ -# The `[graph]` section +# `graph` (optional) + +`object` The graph table configures how the dependency graph is constructed and thus which crates the checks are performed against @@ -31,31 +33,16 @@ executed against. ### Items -**One of the following:** -`string` -The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target -you wish to filter target specific dependencies with. If the target triple specified is **not** -one of the targets builtin to `rustc`, the configuration check for that target will be limited -to only the raw `[target..dependencies]` style of target configuration, as `cfg()` -expressions require us to know the details about the target. +#### `graph.targets[N] (as String)` (as String) -#### Examples -- ```toml - [graph] - targets = ["x86_64-unknown-linux-gnu"] - ``` -- ```toml - [graph] - targets = ["x86_64-pc-windows-msvc"] - ``` -- ```toml - [graph] - targets = ["aarch64-apple-darwin"] - ``` +#### `graph.targets[N] (as Advanced)` (as Advanced) + +`object` + Advanced configurations to apply for the target triple ##### Examples @@ -64,39 +51,18 @@ Advanced configurations to apply for the target triple [[graph.targets]] triple = "aarch64-apple-darwin" ``` + - ```toml [[graph.targets]] triple = "x86_64-pc-windows-msvc" features = ["some-feature"] ``` -##### `graph.targets[N].triple` (required) - -`string` +##### `graph.targets[N] (as Advanced).triple` (required) -The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target -you wish to filter target specific dependencies with. If the target triple specified is **not** -one of the targets builtin to `rustc`, the configuration check for that target will be limited -to only the raw `[target..dependencies]` style of target configuration, as `cfg()` -expressions require us to know the details about the target. -###### Examples - -- ```toml - [[graph.targets]] - triple = "x86_64-unknown-linux-gnu" - ``` -- ```toml - [[graph.targets]] - triple = "x86_64-pc-windows-msvc" - ``` -- ```toml - [[graph.targets]] - triple = "aarch64-apple-darwin" - ``` - -##### `graph.targets[N].features` (optional) +##### `graph.targets[N] (as Advanced).features` (optional) `string` @@ -110,7 +76,7 @@ actually valid for the target triple, but this is [planned](https://github.com/E ## `graph.exclude` (optional) -`array of string` +`array` Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) @@ -121,13 +87,17 @@ Note that excluding a crate is recursive, if any of its transitive dependencies via the excluded crate, they will also be excluded from the crate graph. -#### Example +### Example ```toml [graph] exclude = "some-crate@0.1.0" ``` +### Items + +`string` + ## `graph.all-features` (optional) `boolean` @@ -142,19 +112,23 @@ If set to `true`, `--no-default-features` will be used when collecting metadata. ## `graph.features` (optional) -`array of string` +`array` If set, and `--features` is not specified on the cmd line, these features will be used when collecting metadata. -#### Example +### Example ```toml [graph] features = "some-feature" ``` +### Items + +`string` + ## `graph.exclude-dev` (optional) `boolean` @@ -164,4 +138,3 @@ in the crate graph used for any of the checks. This option can also be enabled o with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) the `check` subcommand. - diff --git a/docs/src/checks2/output/cfg.md b/docs/src/checks2/output/cfg.md index 275993a9..e2e58329 100644 --- a/docs/src/checks2/output/cfg.md +++ b/docs/src/checks2/output/cfg.md @@ -1,4 +1,6 @@ -# The `[output]` section +# `output` (optional) + +`object` The output table provides options for how/if diagnostics are outputted @@ -6,14 +8,14 @@ The output table provides options for how/if diagnostics are outputted `integer` +The maximum depth that features will be displayed when inclusion graphs are shown in +diagnostics, unless specified via `--feature-depth` on the command line. Only applies to +diagnostics that actually print features. + + ### Default ```toml [output] feature-depth = 1 -``` - -The maximum depth that features will be displayed when inclusion graphs are shown in -diagnostics, unless specified via `--feature-depth` on the command line. Only applies to -diagnostics that actually print features. - +``` \ No newline at end of file diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 146a0cb0..910c62f8 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,6 +7,9 @@ edition = "2021" # Easy dynamic error handling anyhow = "1.0" +# Much nicer paths +camino = "1.1" + # Amazing CLI arg parser clap = { version = "4.3", features = ["derive"] } diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/input.rs index 97cc194d..714dba0f 100644 --- a/xtask/src/cli/codegen/input.rs +++ b/xtask/src/cli/codegen/input.rs @@ -1,6 +1,5 @@ use anyhow::{Context, Result}; use indexmap::IndexMap; -use itertools::Either; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::{BTreeMap, BTreeSet}; @@ -42,10 +41,10 @@ pub(crate) struct Schema { pub(crate) array_schema: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "enum")] - pub(crate) enum_schema: Option, + pub(crate) enum_schema: Option>, #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] - pub(crate) one_of: Option>, + pub(crate) one_of: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) title: Option, @@ -66,20 +65,27 @@ pub(crate) struct Schema { #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] -pub(crate) enum EnumSchema { - Custom(Vec), - Standard(Vec), +pub(crate) enum EnumVariantSchema { + Undocumented(Value), + Documented(DocumentedEnumSchema), } #[derive(Serialize, Deserialize, Debug, Clone)] -pub(crate) struct CustomEnumSchema { - pub(crate) value: String, +pub(crate) struct DocumentedEnumSchema { + #[serde(flatten)] + pub(crate) value: CustomEnumValue, pub(crate) description: String, } #[derive(Serialize, Deserialize, Debug, Clone)] -pub(crate) struct VariantSchema { +enum CustomEnumValue { + Named { value: Value, name: String }, + Inferred { value: String }, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct OneOfVariantSchema { /// Name of the variant. It's main use case is when generating a Rust enum, /// which requires a name for each variant. However, it's also useful for /// documentation purposes as a succinct display name for the variant. @@ -182,7 +188,7 @@ impl Schema { Ok(()) } - fn try_downcast_as(&self, schema: &Option, label: &str) -> Result<&T> { + fn try_downcast_as<'a, T>(&'a self, schema: &'a Option, label: &str) -> Result<&'a T> { schema .as_ref() .with_context(|| format!("Expected {label} schema, but got {self:#?}")) @@ -197,7 +203,8 @@ impl Schema { } pub(crate) fn try_into_array(self) -> Result { - self.try_downcast_into(self.array_schema, "array") + let array_schema = self.array_schema.clone(); + self.try_downcast_into(array_schema, "array") } pub(crate) fn try_as_object(&self) -> Result<&ObjectSchema> { @@ -205,24 +212,28 @@ impl Schema { } pub(crate) fn try_into_object(self) -> Result { - self.try_downcast_into(self.object_schema, "object") + let object_schema = self.object_schema.clone(); + self.try_downcast_into(object_schema, "object") } - pub(crate) fn try_as_enum(&self) -> Result<&EnumSchema> { + pub(crate) fn try_as_enum(&self) -> Result<&[EnumVariantSchema]> { self.try_downcast_as(&self.enum_schema, "enum") + .map(Vec::as_slice) } - pub(crate) fn try_into_enum(self) -> Result { - self.try_downcast_into(self.enum_schema, "enum") + pub(crate) fn try_into_enum(self) -> Result> { + let enum_schema = self.enum_schema.clone(); + self.try_downcast_into(enum_schema, "enum") } - pub(crate) fn try_as_one_of(&self) -> Result<&[VariantSchema]> { + pub(crate) fn try_as_one_of(&self) -> Result<&[OneOfVariantSchema]> { self.try_downcast_as(&self.one_of, "one-of") .map(Vec::as_slice) } - pub(crate) fn try_into_one_of(self) -> Result> { - self.try_downcast_into(self.one_of, "one-of") + pub(crate) fn try_into_one_of(self) -> Result> { + let one_of_schema = self.one_of.clone(); + self.try_downcast_into(one_of_schema, "one-of") } pub(crate) fn try_description(&self) -> Result<&str> { @@ -282,21 +293,24 @@ impl RootSchema { } } -impl EnumSchema { - pub(crate) fn values_and_descriptions(&self) -> impl Iterator)> { +impl CustomEnumValue { + fn to_json_value(&self) -> Value { match self { - EnumSchema::Custom(custom) => { - let iter = custom.iter().map(|custom| { - let value = custom.value.clone().into(); - let description = custom.description.as_str(); - (value, Some(description)) - }); - Either::Left(iter) - } - EnumSchema::Standard(values) => { - let iter = values.iter().map(|value| (value.clone(), None)); - Either::Right(iter) + CustomEnumValue::Named { value, name: _ } => value.clone(), + CustomEnumValue::Inferred { value } => value.clone().into(), + } + } +} + +impl EnumVariantSchema { + pub(crate) fn value_and_description(&self) -> (Value, Option<&str>) { + match self { + EnumVariantSchema::Documented(schema) => { + let value = schema.value.to_json_value(); + let description = schema.description.as_str(); + (value, Some(description)) } + EnumVariantSchema::Undocumented(value) => (value.clone().into(), None), } } } diff --git a/xtask/src/cli/codegen/json_schema.rs b/xtask/src/cli/codegen/json_schema.rs index b2faed5d..c6b05a27 100644 --- a/xtask/src/cli/codegen/json_schema.rs +++ b/xtask/src/cli/codegen/json_schema.rs @@ -1,6 +1,5 @@ -use super::input::{EnumSchema, RootSchema, Schema}; +use super::input::{EnumVariantSchema, RootSchema, Schema}; use anyhow::Result; -use std::mem; /// Generate the JSON schema based on the input YML schema. pub(crate) fn gen(root: &RootSchema) -> Result<()> { @@ -55,21 +54,18 @@ impl<'a> GenContext<'a> { fn normalize_enum(&self, schema: &mut Schema) -> Result<()> { let mut inlined = self.root.inline_referenced_definition(schema)?; - let Some(enum_schema) = &mut inlined.enum_schema else { + let Some(enum_variants) = &mut inlined.enum_schema else { return Ok(()); }; - let EnumSchema::Custom(custom) = enum_schema else { - return Ok(()); - }; - - let (values, descriptions): (Vec<_>, Vec<_>) = custom + let (values, descriptions): (Vec<_>, Vec<_>) = enum_variants .iter_mut() - .map(|custom| { - ( - mem::take(&mut custom.value).into(), - mem::take(&mut custom.description), - ) + .map(|variant| { + let (value, description) = variant.value_and_description(); + + let description = description.unwrap_or_default(); + + (EnumVariantSchema::Undocumented(value), description) }) .unzip(); @@ -77,7 +73,7 @@ impl<'a> GenContext<'a> { "docs": { "enumValues": descriptions } })); - *enum_schema = EnumSchema::Standard(values); + *enum_variants = values; *schema = inlined; diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/xtask/src/cli/codegen/md_doc/mod.rs index c2664425..8374c48f 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -1,15 +1,19 @@ -use super::input::{ArraySchema, EnumSchema, ObjectSchema, RootSchema, Schema}; -use anyhow::{Context, Result}; +mod rendering; + +use self::rendering::{RenderedSection, RenderingConfig}; +use crate::cli::codegen::input::{EnumVariantSchema, RootSchema, Schema}; +use anyhow::Result; use itertools::Itertools; use serde_json::Value; use std::collections::BTreeMap; use std::fmt; -struct Doc { +pub(crate) struct Doc { root: Section, type_index: BTreeMap, } +#[derive(Debug)] struct SectionData { key: SchemaKey, title: Option, @@ -18,15 +22,52 @@ struct SectionData { examples: Vec, format: Option, ty: Option, - enum_schema: Option, + enum_schema: Option>, type_index_ref: Option, } +#[derive(Debug)] struct Section { data: SectionData, children: Vec
, } +struct RootContext<'a> { + root: &'a RootSchema, + type_index: &'a BTreeMap, +} + +#[derive(Clone, Debug)] +struct KeyedSchema { + key: SchemaKey, + inner: Schema, +} + +#[derive(Clone, Debug)] +struct SchemaKey { + root: SchemaRoot, + segments: Vec, +} + +#[derive(Clone, Debug)] +enum SchemaRoot { + Root, + Definition(String), +} + +#[derive(Clone, Debug)] +enum SchemaKeySegment { + Field(SchemaKeySegmentField), + Index, + Variant(String), +} + +#[derive(Clone, Debug)] +struct SchemaKeySegmentField { + name: String, + required: bool, +} + impl Doc { fn from_root_schema(root: &RootSchema) -> Result { let schemas_in_root = root.schema.inner_schemas(); @@ -35,7 +76,7 @@ impl Doc { let definition_ref_counts = itertools::chain(schemas_in_root, schemas_in_defs) .map(Schema::referenced_definition) .flatten_ok() - .process_results(Itertools::counts)?; + .process_results(|iter| iter.counts())?; let unused_defs: Vec<_> = root .definitions @@ -53,7 +94,7 @@ impl Doc { // For schemas that are repeatedly referenced, we want to include them in the // "Type Index". This is separate page where common types are defined such // that we don't duplicate their docs all over the place. - .filter(|(def_name, count)| *count > 1) + .filter(|(_, count)| *count > 1) .map(|(def_name, _)| { let schema = root.find_definition(def_name)?; anyhow::Ok((def_name.to_owned(), schema)) @@ -72,11 +113,6 @@ impl Doc { } } -struct RootContext<'a> { - root: &'a RootSchema, - type_index: &'a BTreeMap, -} - impl RootContext<'_> { fn root_section(&self) -> Result
{ let key = SchemaKey { @@ -84,7 +120,10 @@ impl RootContext<'_> { segments: vec![], }; let root_schema = KeyedSchema::new(key, self.root.schema.clone()); - self.section(root_schema) + + let section = self.section(root_schema)?; + + Ok(section) } fn type_index_sections(&self) -> Result> { @@ -103,24 +142,24 @@ impl RootContext<'_> { } fn section(&self, schema: KeyedSchema) -> Result
{ - let section_data = self.section_data(schema.clone())?; - let referenced_def = schema.inner.referenced_definition()?; // If this schema references a type from the type index, then avoid // inlining the schema and finish the section early. if referenced_def.is_some_and(|def| self.type_index.contains_key(def)) { - return Ok(Section::leaf(section_data)); + return Ok(Section::leaf(self.section_data(schema.clone())?)); } - let schema = schema.inline_referenced_definition(&self.root)?; + let schema = schema.inline_referenced_definition(self.root)?; + + let section_data = self.section_data(schema.clone())?; let children = if schema.inner.array_schema.is_some() { - self.array_children(schema)? + Self::array_children(schema)? } else if schema.inner.object_schema.is_some() { - self.object_children(schema)? + Self::object_children(schema)? } else if schema.inner.one_of.is_some() { - self.one_of_children(schema)? + Self::one_of_children(schema)? } else { vec![] }; @@ -136,14 +175,14 @@ impl RootContext<'_> { }) } - fn array_children(&self, schema: KeyedSchema) -> Result> { + fn array_children(schema: KeyedSchema) -> Result> { let array = schema.inner.try_into_array()?; let key = schema.key.next_level(SchemaKeySegment::Index); let items = KeyedSchema::new(key, *array.items); Ok(vec![items]) } - fn object_children(&self, schema: KeyedSchema) -> Result> { + fn object_children(schema: KeyedSchema) -> Result> { let object = schema.inner.try_into_object()?; let properties = object .properties @@ -162,7 +201,7 @@ impl RootContext<'_> { Ok(properties) } - fn one_of_children(&self, schema: KeyedSchema) -> Result> { + fn one_of_children(schema: KeyedSchema) -> Result> { let variants = schema.inner.try_into_one_of()?; let duplicates: Vec<_> = variants @@ -224,65 +263,6 @@ impl Section { } } -pub(crate) fn gen(root: &RootSchema) -> Result<()> { - gen_root_doc(root)?; - - for (key, schema) in &root.schema.try_as_object()?.properties { - let schema = KeyedSchema::inlined(root, vec![], SchemaKeySegment::Field(key), schema)?; - - gen_section_doc(root, &schema)?; - } - - Ok(()) -} - -fn gen_section_doc(root: &RootSchema, section: &KeyedSchema<'_>) -> Result<()> { - let properties = gen_object_doc(root, 1, section, section.inner.try_as_object()?)?; - - let section_key = §ion.key.last().unwrap(); - - let content = format!( - "\ -# The `[{section_key}]` section - -{properties} -", - ); - - write_file(format!("{section_key}/cfg.md"), &content) -} - -#[derive(Clone, Debug)] -struct KeyedSchema { - key: SchemaKey, - inner: Schema, -} - -#[derive(Clone, Debug)] -struct SchemaKey { - root: SchemaRoot, - segments: Vec, -} - -#[derive(Clone, Debug)] -enum SchemaRoot { - Root, - Definition(String), -} - -#[derive(Clone, Debug)] -enum SchemaKeySegment { - Field(SchemaKeySegmentField), - Index, - Variant(String), -} - -#[derive(Clone, Debug)] -struct SchemaKeySegmentField { - name: String, - required: bool, -} - impl fmt::Display for SchemaKeySegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -293,20 +273,14 @@ impl fmt::Display for SchemaKeySegment { } } -impl SchemaKeySegment { - fn unwrap_field(&self) -> &SchemaKeySegmentField { - match self { - SchemaKeySegment::Field(field) => field, - _ => panic!("Expected field, found: {self:#?}"), - } - } -} - impl SchemaKey { fn next_level(&self, new_segment: SchemaKeySegment) -> Self { let mut segments = self.segments.clone(); segments.push(new_segment); - Self { segments } + Self { + root: self.root.clone(), + segments, + } } fn last_segment(&self) -> &SchemaKeySegment { @@ -343,292 +317,28 @@ impl KeyedSchema { } } -fn gen_detailed_schema_doc( - root: &RootSchema, - paragraph_level: usize, - schema: &KeyedSchema<'_>, -) -> Result { - if let Some(array_schema) = &schema.inner.array_schema { - return gen_array_doc(root, paragraph_level + 1, schema, array_schema); - } - - if let Some(object) = &schema.inner.object_schema { - return gen_object_doc(root, paragraph_level + 1, schema, object); - } - - if let Some(enum_schema) = &schema.inner.enum_schema { - return gen_enum_doc(schema, enum_schema, paragraph_level + 1); - } - - if let Some(variants) = &schema.inner.one_of { - return gen_one_of_doc(root, schema, variants, paragraph_level); - } - - gen_primitive_type_doc(schema, paragraph_level) -} - -fn primitive_type_label(schema: &KeyedSchema<'_>) -> Result { - let ty = schema.inner.ty.as_deref().with_context(|| { - format!( - "Expected type for schema, but found none: `{}`.\nSchema: {:#?}", - schema.full_key(), - schema.inner - ) - })?; - - let format = schema - .inner - .format - .as_deref() - .map(|format| format!("({format})")); - - let doc = itertools::chain!([ty], format.as_deref()).join(" "); - - Ok(doc) -} - -fn gen_primitive_type_doc(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result { - let ty = primitive_type_label(schema)?; - let description = gen_generic_details(schema, paragraph_level)?; - - Ok(format!("`{ty}`\n\n{description}")) -} - -fn value_to_toml(schema: &KeyedSchema<'_>, value: &Value) -> Result { - fn wrap(key: &[SchemaKeySegment], value: &Value) -> Value { - let Some((first, rest)) = key.split_first() else { - return value.clone(); - }; - - match first { - SchemaKeySegment::Field(_) => { - serde_json::json!({ first.to_string(): wrap(rest, value) }) - } - SchemaKeySegment::Index => { - serde_json::json!([wrap(rest, value)]) - } - } - } - - let value = wrap(&schema.key, value); - - let toml = toml::to_string_pretty(&value) - .with_context(|| format!("Serialized value: {:#?}", value))?; - - Ok(format!( - "```toml\n\ - {toml}\ - ```", - )) -} - -fn gen_examples(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result> { - let examples = match schema.inner.examples.as_slice() { - [] => return Ok(None), - [example] => gen_value_showcase("Example", example, schema, paragraph_level)?, - examples => { - let examples = examples - .iter() - .map(|value| value_to_toml(schema, value)) - .collect::>>()? - .into_iter() - .format_with("\n", |example, f| { - let example = example - .lines() - .enumerate() - .format_with("\n", |(i, line), f| { - if i == 0 { - f(&line) - } else { - f(&format_args!(" {}", line)) - } - }); - - f(&format_args!("- {example}")) - }); - let paragraph = "#".repeat(paragraph_level + 1); - - format!("{paragraph} Examples\n\n{examples}") - } - }; - - Ok(Some(examples)) -} - -fn gen_default(schema: &KeyedSchema<'_>, paragraph_level: usize) -> Result> { - schema - .inner - .default - .as_ref() - .map(|value| gen_value_showcase("Default", value, schema, paragraph_level)) - .transpose() -} - -fn gen_value_showcase( - label: &str, - value: &Value, - schema: &KeyedSchema<'_>, - paragraph_level: usize, -) -> Result { - let toml = value_to_toml(schema, value)?; - let paragraph = "#".repeat(paragraph_level + 1); - let showcase = format!("{paragraph} {label}\n\n{toml}"); - Ok(showcase) -} - -fn gen_one_of_doc( - root: &RootSchema, - schema: &KeyedSchema<'_>, - variants: &[Schema], - paragraph_level: usize, -) -> Result { - let variants = variants - .iter() - .map(|variant| { - let variant = KeyedSchema { - inner: root.inline_referenced_definition(variant)?, - key: schema.key.clone(), - }; - - let doc = gen_detailed_schema_doc(root, paragraph_level, &variant)?; - - Ok(doc) - }) - .collect::>>()? - .join("\n"); - - Ok(format!("**One of the following:**\n\n{variants}")) -} - -fn gen_enum_doc( - schema: &KeyedSchema<'_>, - enum_schema: &EnumSchema, - paragraph_level: usize, -) -> Result { - let doc = enum_schema - .values_and_descriptions() - .map(|(value, description)| { - let value = value.to_string(); - let description = description - .map(|description| format!(" - {}", description)) - .unwrap_or_default(); - - Ok(format!("* `{value}`{description}")) - }) - .collect::>>()? - .join("\n"); - - let paragraph = "#".repeat(paragraph_level); - - let details = gen_generic_details(schema, paragraph_level)?; - - let doc = format!("\n\n{paragraph} Possible values\n\n{doc}\n---\n{details}"); - - Ok(doc) -} - -fn gen_array_doc( - root: &RootSchema, - paragraph_level: usize, - schema: &KeyedSchema<'_>, - array: &ArraySchema, -) -> Result { - let array_details = gen_generic_details(schema, paragraph_level)?; - - let items = KeyedSchema::inlined( - root, - schema.key.clone(), - SchemaKeySegment::Index, - &array.items, - )?; - - if items.inner.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { - let ty = primitive_type_label(&items)?; - return Ok(format!( - "`array of {ty}`\n\n\ - {array_details}" - )); - } - - let paragraph = "#".repeat(paragraph_level); - - let details = gen_detailed_schema_doc(root, paragraph_level, &items)?; - - let doc = format!( - "`array`\n\n\ - {array_details}\n\n\ - {paragraph} Items\n\n\ - {details}" - ); - - Ok(doc) -} - -fn gen_object_property_doc( - root: &RootSchema, - paragraph_level: usize, - object: &ObjectSchema, - property: &KeyedSchema<'_>, -) -> Result { - let full_key = property.full_key(); - - let property_key = property.key.last().unwrap().unwrap_field(); - - let requirement = if object.required.contains(property_key) { - "required" - } else { - "optional" - }; - - let paragraph = "#".repeat(paragraph_level); - - let details = gen_detailed_schema_doc(root, paragraph_level, property)?; - - let doc = format!( - "{paragraph} `{full_key}` ({requirement})\n\n\ - {details}" - ); - - Ok(doc) -} - -fn gen_root_doc(root: &RootSchema) -> Result<()> { - let sections = root - .schema - .try_as_object()? - .properties - .keys() - .map(|section| { - format!( - "## The `[{section}]` section\n\n\ - See [{section} config]({section}/cfg.html) for more info." - ) - }) - .join("\n\n"); - - let content = format!( - "\ -# config +pub(crate) fn gen(root: &RootSchema) -> Result<()> { + let out_dir = "docs/src/checks2"; + let header = "config"; + let body = "\ The top level config for cargo-deny, by default called `deny.toml`. ## Example - cargo-deny's own configuration ```ini {{{{#include ../../../deny.toml}}}} -``` +```"; -{sections}" - ); - - write_file("cfg.md", &content) -} + let cfg = RenderingConfig { + root_file_base: RenderedSection::leaf(header, body), + }; -fn write_file(path: impl AsRef, content: &str) -> Result<()> { - let path = std::path::Path::new("docs/src/checks2").join(path); + let files = Doc::from_root_schema(root)?.render(&cfg); - std::fs::create_dir_all(&path.parent().unwrap())?; + for file in files { + file.write(out_dir)?; + } - std::fs::write(&path, content) - .with_context(|| format!("Failed to write to file: {}", path.display())) + Ok(()) } diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs new file mode 100644 index 00000000..de908d83 --- /dev/null +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -0,0 +1,275 @@ +use super::{SchemaKey, Section, SectionData}; +use crate::cli::codegen::md_doc::SchemaKeySegment; +use anyhow::{Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use itertools::Itertools; +use serde_json::{json, Value}; + +pub(crate) struct RenderingConfig { + pub(crate) root_file_base: RenderedSection, +} + +pub(crate) struct File { + path: Utf8PathBuf, + rendered: RenderedSection, +} + +#[derive(Clone, Debug)] +pub(crate) struct RenderedSection { + header: String, + body: String, + children: Vec, +} + +impl RenderedSection { + pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { + Self { + header: header.into(), + body: body.into(), + children: vec![], + } + } + + /// Render the section as markdown with the headers starting at the given level + fn to_markdown(&self, level: usize) -> String { + let header = self.header.clone(); + let sharps = "#".repeat(level); + let header = format!("{sharps} {header}"); + let body = self.body.clone(); + + let children = self + .children + .iter() + .map(|child| child.to_markdown(level + 1)); + + itertools::chain([header, body], children).join("\n\n") + } +} + +impl super::Doc { + pub(crate) fn render(&self, cfg: &RenderingConfig) -> Vec { + let root_sections = self.root.children.iter().map(|section| { + let key = §ion.data.key; + let header = format!("The `[{key}]` section"); + let body = format!("See [{key} config]({key}/cfg.html) for more info."); + RenderedSection::leaf(header, body) + }); + + let mut rendered = cfg.root_file_base.clone(); + rendered.children.extend(root_sections); + + let root = File::new("cfg.md", rendered); + + let child_files = self.root.children.iter().map(|section| { + let rendered = section.render(); + + let key = §ion.data.key; + + File::new(format!("{key}/cfg.md"), rendered) + }); + + itertools::chain([root], child_files).collect() + } +} + +impl Section { + fn render(&self) -> RenderedSection { + // let properties = gen_object_doc(root, 1, section, section.inner.try_as_object()?)?; + + // let section_key = §ion.key.last().unwrap(); + + // let content = format!( + // "\ + // # The `[{section_key}]` section + + // {properties} + // ", + // ); + + // write_file(format!("{section_key}/cfg.md"), &content) + + let children = [ + self.data.enum_doc(), + self.data.default(), + self.data.examples(), + ]; + + let child_schemas = self.children.iter().map(Section::render); + + let children = children + .into_iter() + .flatten() + .chain(child_schemas) + .collect(); + + let header = self.data.header(); + + // if items.inner.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { + // let ty = primitive_type_label(&items)?; + // return Ok(format!( + // "`array of {ty}`\n\n\ + // {array_details}" + // )); + // } + + RenderedSection { + header, + body: self.data.render_body(), + children, + } + } +} + +impl SectionData { + fn header(&self) -> String { + let suffix = match self.key.last_segment() { + SchemaKeySegment::Field(field) => { + let requirement = match field.required { + true => "required", + false => "optional", + }; + format!("({requirement})") + } + SchemaKeySegment::Index => return "Items".to_owned(), + SchemaKeySegment::Variant(variant_name) => format!("(as {variant_name})"), + }; + + let prefix = &self.key; + + format!("`{prefix}` {suffix}") + } + + fn render_body(&self) -> String { + let type_label = self.type_label().map(|label| format!("`{label}`")); + + let parts = [&type_label, &self.title, &self.description]; + + let body = parts.into_iter().flatten().join("\n\n"); + + body + } + + fn default(&self) -> Option { + self.default + .as_ref() + .map(|value| self.value_showcase("Default", value)) + } + + fn value_showcase(&self, header: &str, value: &Value) -> RenderedSection { + let toml = self.key.render_value(value); + RenderedSection::leaf(header, toml) + } + + fn type_label(&self) -> Option { + let ty = self.ty.as_deref()?; + + let format = self.format.as_deref().map(|format| format!("({format})")); + + let label = itertools::chain([ty], format.as_deref()).join(" "); + + Some(label) + } + + fn examples(&self) -> Option { + match self.examples.as_slice() { + [] => return None, + [example] => return Some(self.value_showcase("Example", example)), + _ => {} + }; + + let examples = self + .examples + .iter() + .map(|value| { + // Properly indent the example to fit into the markdown + // list syntax + let example = self.key.render_value(value); + let example = example + .lines() + .enumerate() + .format_with("\n", |(i, line), f| { + if i == 0 { + f(&line) + } else { + f(&format_args!(" {}", line)) + } + }); + + format!("- {example}") + }) + .join("\n\n"); + + Some(RenderedSection::leaf("Examples", examples)) + } + + fn enum_doc(&self) -> Option { + let doc = self + .enum_schema + .as_ref()? + .iter() + .map(|enum_variant| { + let (value, description) = enum_variant.value_and_description(); + let value = value.to_string(); + let doc = itertools::chain([value.as_str()], description).join("-"); + doc + }) + .join("\n\n"); + + Some(RenderedSection::leaf("Possible values", doc)) + } +} + +impl SchemaKey { + fn render_value(&self, value: &Value) -> String { + fn wrap(key: &[SchemaKeySegment], value: Value) -> Value { + let Some((first, rest)) = key.split_first() else { + return value; + }; + + match first { + SchemaKeySegment::Field(_) => { + json!({ first.to_string(): wrap(rest, value) }) + } + SchemaKeySegment::Index => { + json!([wrap(rest, value)]) + } + // We use untagged one-of representations, so there is nothing + // to wrap here + SchemaKeySegment::Variant(_) => value, + } + } + + let value = wrap(&self.segments, value.clone()); + + let toml = toml::to_string_pretty(&value).unwrap_or_else(|err| { + panic!( + "Failed to serialize value to TOML: {err:#?}\n\ + Value: {value:#?}", + ) + }); + + format!( + "```toml\n\ + {toml}\ + ```", + ) + } +} + +impl File { + fn new(path: impl Into, rendered: RenderedSection) -> Self { + Self { + path: path.into(), + rendered, + } + } + + pub(crate) fn write(&self, prefix: impl AsRef) -> Result<()> { + let path = prefix.as_ref().join(&self.path); + + std::fs::create_dir_all(&path.parent().unwrap())?; + + std::fs::write(&path, &self.rendered.to_markdown(1)) + .with_context(|| format!("Failed to write to file: {path}")) + } +} From f6dd18f08410edbe38c1b67481b3db26da0e712d Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 8 Apr 2024 02:42:33 +0000 Subject: [PATCH 08/20] Next iteration --- deny.schema.json | 188 ++++++++------------ deny.schema.yml | 68 ++++---- docs/src/SUMMARY.md | 17 ++ docs/src/checks2/advisories/README.md | 1 + docs/src/checks2/advisories/cfg.md | 86 +++++---- docs/src/checks2/advisories/diags.md | 1 + docs/src/checks2/bans/README.md | 1 + docs/src/checks2/bans/cfg.md | 1 + docs/src/checks2/bans/diags.md | 1 + docs/src/checks2/cfg.md | 2 +- docs/src/checks2/graph/cfg.md | 76 ++++---- docs/src/checks2/licenses/README.md | 1 + docs/src/checks2/licenses/cfg.md | 1 + docs/src/checks2/licenses/diags.md | 1 + docs/src/checks2/output/cfg.md | 10 +- docs/src/checks2/sources/README.md | 1 + docs/src/checks2/sources/cfg.md | 1 + docs/src/checks2/sources/diags.md | 1 + docs/src/checks2/type-index.md | 44 +++++ docs/src/checs2/graph/README.md | 1 + docs/src/checs2/output/README.md | 1 + xtask/src/cli/codegen/input.rs | 31 +++- xtask/src/cli/codegen/md_doc/mod.rs | 75 ++++++-- xtask/src/cli/codegen/md_doc/rendering.rs | 204 +++++++++++++--------- 24 files changed, 480 insertions(+), 334 deletions(-) create mode 100644 docs/src/checks2/advisories/README.md create mode 100644 docs/src/checks2/advisories/diags.md create mode 100644 docs/src/checks2/bans/README.md create mode 100644 docs/src/checks2/bans/cfg.md create mode 100644 docs/src/checks2/bans/diags.md create mode 100644 docs/src/checks2/licenses/README.md create mode 100644 docs/src/checks2/licenses/cfg.md create mode 100644 docs/src/checks2/licenses/diags.md create mode 100644 docs/src/checks2/sources/README.md create mode 100644 docs/src/checks2/sources/cfg.md create mode 100644 docs/src/checks2/sources/diags.md create mode 100644 docs/src/checks2/type-index.md create mode 100644 docs/src/checs2/graph/README.md create mode 100644 docs/src/checs2/output/README.md diff --git a/deny.schema.json b/deny.schema.json index ee17dadc..11905b1f 100644 --- a/deny.schema.json +++ b/deny.schema.json @@ -2,19 +2,19 @@ "type": "object", "properties": { "advisories": { - "$ref": "#/definitions/advisories" + "$ref": "#/definitions/Advisories" }, "graph": { - "$ref": "#/definitions/graph" + "$ref": "#/definitions/Graph" }, "output": { - "$ref": "#/definitions/output" + "$ref": "#/definitions/Output" } }, "title": "Configuration file for cargo-deny, by default called `deny.toml`.", "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", "definitions": { - "advisories": { + "Advisories": { "type": "object", "examples": [ { @@ -70,140 +70,100 @@ } }, "vulnerability": { + "type": "string", "deprecated": true, "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n", "default": "deny", "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } }, "unmaintained": { + "type": "string", "deprecated": true, "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } }, "unsound": { + "type": "string", "deprecated": true, "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } }, "notice": { + "type": "string", "deprecated": true, "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } }, "yanked": { + "type": "string", "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n", "default": "warn", "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } @@ -225,14 +185,14 @@ ] ], "items": { - "$ref": "#/definitions/advisories-ignore-item" + "$ref": "#/definitions/AdvisoriesIgnoreItem" }, "description": "Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" } }, "description": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as Unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" }, - "advisories-ignore-advisory": { + "AdvisoriesIgnoreAdvisory": { "type": "object", "properties": { "id": { @@ -243,14 +203,14 @@ "description": "The unique identifier of the advisory to ignore" }, "reason": { - "$ref": "#/definitions/ignore-reason" + "$ref": "#/definitions/IgnoreReason" } }, "required": [ "id" ] }, - "advisories-ignore-item": { + "AdvisoriesIgnoreItem": { "oneOf": [ { "name": "String", @@ -259,35 +219,35 @@ }, { "name": "Advisory", - "$ref": "#/definitions/advisories-ignore-advisory" + "$ref": "#/definitions/AdvisoriesIgnoreAdvisory" }, { "name": "Yanked", - "$ref": "#/definitions/advisories-ignore-yanked" + "$ref": "#/definitions/AdvisoriesIgnoreYanked" } ] }, - "advisories-ignore-yanked": { + "AdvisoriesIgnoreYanked": { "type": "object", "properties": { "crate": { - "$ref": "#/definitions/package-spec" + "$ref": "#/definitions/PackageSpec" }, "reason": { - "$ref": "#/definitions/ignore-reason" + "$ref": "#/definitions/IgnoreReason" } }, "required": [ "crate" ] }, - "graph": { + "Graph": { "type": "object", "properties": { "targets": { "type": "array", "items": { - "$ref": "#/definitions/target" + "$ref": "#/definitions/Target" }, "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" }, @@ -326,36 +286,28 @@ }, "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n" }, - "ignore-reason": { + "IgnoreReason": { "type": "string", "description": "Free-form string that can be used to describe the reason why the advisory is ignored." }, - "lint-level": { + "LintLevel": { + "type": "string", "enum": [ - { - "value": "deny", - "description": "Emit an error with details about the problem, and fail the check." - }, - { - "value": "warn", - "description": "Print a warning for each propblem, but don't fail the check." - }, - { - "value": "allow", - "description": "Print a note about the problem, but don't fail the check." - } + "deny", + "warn", + "allow" ], "x-taplo": { "docs": { "enumValues": [ - "", - "", - "" + "Emit an error with details about the problem, and fail the check.", + "Print a warning for each propblem, but don't fail the check.", + "Print a note about the problem, but don't fail the check." ] } } }, - "output": { + "Output": { "type": "object", "properties": { "feature-depth": { @@ -366,23 +318,23 @@ }, "description": "The output table provides options for how/if diagnostics are outputted" }, - "package-spec": { + "PackageSpec": { "type": "string", "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" }, - "target": { + "Target": { "oneOf": [ { "name": "String", - "$ref": "#/definitions/target-string" + "$ref": "#/definitions/TargetString" }, { "name": "Advanced", - "$ref": "#/definitions/target-advanced" + "$ref": "#/definitions/TargetAdvanced" } ] }, - "target-advanced": { + "TargetAdvanced": { "type": "object", "examples": [ { @@ -397,7 +349,7 @@ ], "properties": { "triple": { - "$ref": "#/definitions/target-string" + "$ref": "#/definitions/TargetString" }, "features": { "type": "string", @@ -409,7 +361,7 @@ ], "description": "Advanced configurations to apply for the target triple" }, - "target-string": { + "TargetString": { "type": "string", "examples": [ "x86_64-unknown-linux-gnu", @@ -424,13 +376,13 @@ "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", "properties": { "advisories": { - "$ref": "#/definitions/advisories" + "$ref": "#/definitions/Advisories" }, "graph": { - "$ref": "#/definitions/graph" + "$ref": "#/definitions/Graph" }, "output": { - "$ref": "#/definitions/output" + "$ref": "#/definitions/Output" } }, "title": "Configuration file for cargo-deny, by default called `deny.toml`.", diff --git a/deny.schema.yml b/deny.schema.yml index ba03b148..debe8cd1 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -35,12 +35,12 @@ description: Full documentation is at https://embarkstudios.github.io/cargo-deny type: object properties: - advisories: { $ref: "#/definitions/advisories" } - graph: { $ref: "#/definitions/graph" } - output: { $ref: "#/definitions/output" } + advisories: { $ref: "#/definitions/Advisories" } + graph: { $ref: "#/definitions/Graph" } + output: { $ref: "#/definitions/Output" } definitions: - advisories: + Advisories: examples: - db-path: ~/.cargo/advisory-dbs db-urls: [https://github.com/RustSec/advisory-db] @@ -110,7 +110,7 @@ definitions: vulnerability: deprecated: true - $ref: "#/definitions/lint-level" + $ref: "#/definitions/LintLevel" default: deny description: | **DEPRECATED** (see `version` field) @@ -119,7 +119,7 @@ definitions: unmaintained: deprecated: true - $ref: "#/definitions/lint-level" + $ref: "#/definitions/LintLevel" default: warn description: | **DEPRECATED** (see `version` field) @@ -128,7 +128,7 @@ definitions: unsound: deprecated: true - $ref: "#/definitions/lint-level" + $ref: "#/definitions/LintLevel" default: warn description: | **DEPRECATED** (see `version` field) @@ -137,7 +137,7 @@ definitions: notice: deprecated: true - $ref: "#/definitions/lint-level" + $ref: "#/definitions/LintLevel" default: warn description: | **DEPRECATED** (see `version` field) @@ -148,7 +148,7 @@ definitions: [RustSec Advisory DB](https://github.com/RustSec/advisory-db) yanked: - $ref: "#/definitions/lint-level" + $ref: "#/definitions/LintLevel" default: warn description: | Determines what happens when a crate with a version that has been yanked from its source @@ -156,7 +156,7 @@ definitions: ignore: type: array - items: { $ref: "#/definitions/advisories-ignore-item" } + items: { $ref: "#/definitions/AdvisoriesIgnoreItem" } examples: - - RUSTSEC-0000-0000 - id: "RUSTSEC-0000-0000" @@ -173,19 +173,19 @@ definitions: In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) with an optional `reason`. - advisories-ignore-item: + AdvisoriesIgnoreItem: oneOf: - name: String type: string description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - name: Advisory - $ref: "#/definitions/advisories-ignore-advisory" + $ref: "#/definitions/AdvisoriesIgnoreAdvisory" - name: Yanked - $ref: "#/definitions/advisories-ignore-yanked" + $ref: "#/definitions/AdvisoriesIgnoreYanked" - advisories-ignore-advisory: + AdvisoriesIgnoreAdvisory: type: object required: [id] properties: @@ -193,20 +193,21 @@ definitions: type: string examples: [RUSTSEC-2019-0001] description: The unique identifier of the advisory to ignore - reason: { $ref: "#/definitions/ignore-reason" } + reason: { $ref: "#/definitions/IgnoreReason" } - advisories-ignore-yanked: + AdvisoriesIgnoreYanked: type: object required: [crate] properties: - crate: { $ref: "#/definitions/package-spec" } - reason: { $ref: "#/definitions/ignore-reason" } + crate: { $ref: "#/definitions/PackageSpec" } + reason: { $ref: "#/definitions/IgnoreReason" } - ignore-reason: + IgnoreReason: type: string description: Free-form string that can be used to describe the reason why the advisory is ignored. - lint-level: + LintLevel: + type: string enum: - value: deny description: Emit an error with details about the problem, and fail the check. @@ -215,14 +216,7 @@ definitions: - value: allow description: Print a note about the problem, but don't fail the check. - # x-taplo: - # docs: - # enumValues: - # - - # - - # - - - package-spec: + PackageSpec: type: string description: | Many configuration options require a package specifier at a minimum, which we'll describe here. @@ -295,7 +289,7 @@ definitions: The old format uses a required `name` key and an optional `version` key. This format is deprecated and should not be used. - graph: + Graph: description: | The graph table configures how the dependency graph is constructed and thus which crates the checks are performed against @@ -304,7 +298,7 @@ definitions: properties: targets: type: array - items: { $ref: "#/definitions/target" } + items: { $ref: "#/definitions/Target" } description: | By default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies e.g. @@ -364,20 +358,20 @@ definitions: or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) the `check` subcommand. - target: + Target: oneOf: - name: String - $ref: "#/definitions/target-string" + $ref: "#/definitions/TargetString" - name: Advanced - $ref: "#/definitions/target-advanced" + $ref: "#/definitions/TargetAdvanced" - target-advanced: + TargetAdvanced: description: Advanced configurations to apply for the target triple type: object required: [triple] properties: - triple: { $ref: "#/definitions/target-string" } + triple: { $ref: "#/definitions/TargetString" } features: type: string description: | @@ -392,7 +386,7 @@ definitions: - { triple: aarch64-apple-darwin } - { triple: x86_64-pc-windows-msvc, features: [some-feature] } - target-string: + TargetString: type: string examples: - x86_64-unknown-linux-gnu @@ -406,7 +400,7 @@ definitions: to only the raw `[target..dependencies]` style of target configuration, as `cfg()` expressions require us to know the details about the target. - output: + Output: description: The output table provides options for how/if diagnostics are outputted type: object properties: diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index c8720625..d2b5fd42 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -20,3 +20,20 @@ - [sources](checks/sources/README.md) - [config](checks/sources/cfg.md) - [diagnostics](checks/sources/diags.md) +- [Type Index](checks2/type-index.md) +- [Checks2](checks/README.md) + - [config](checks2/cfg.md) + - [advisories](checks2/advisories/README.md) + - [config](checks2/advisories/cfg.md) + - [diagnostics](checks2/advisories/diags.md) + - [bans](checks2/bans/README.md) + - [config](checks2/bans/cfg.md) + - [diagnostics](checks2/bans/diags.md) + - [graph](checks2/graph/cfg.md) + - [licenses](checks2/licenses/README.md) + - [config](checks2/licenses/cfg.md) + - [diagnostics](checks2/licenses/diags.md) + - [output](checks2/output/cfg.md) + - [sources](checks2/sources/README.md) + - [config](checks2/sources/cfg.md) + - [diagnostics](checks2/sources/diags.md) diff --git a/docs/src/checks2/advisories/README.md b/docs/src/checks2/advisories/README.md new file mode 100644 index 00000000..dd95b93f --- /dev/null +++ b/docs/src/checks2/advisories/README.md @@ -0,0 +1 @@ +# advisories diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md index 682bfe77..171a767b 100644 --- a/docs/src/checks2/advisories/cfg.md +++ b/docs/src/checks2/advisories/cfg.md @@ -1,6 +1,7 @@ -# `advisories` (optional) +# `advisories` -`object` +**Type:** `object`
+**Required:** `no` Checks advisory databases for crates with security vulnerabilities, or that have been marked as Unmaintained, or which have been yanked from @@ -28,9 +29,10 @@ ignore = [ severity-threshold = "medium" ``` -## `advisories.db-urls` (optional) +## `advisories.db-urls` -`array` +**Type:** `array`
+**Required:** `no` URLs to one or more advisory databases. @@ -43,11 +45,13 @@ db-urls = ["https://github.com/RustSec/advisory-db"] ### Items -`string (uri)` +**Type:** `string`
+**Format:** `uri` -## `advisories.db-path` (optional) +## `advisories.db-path` -`string` +**Type:** `string`
+**Required:** `no` Path to the root directory into which one or more advisory databases are cloned into. @@ -71,9 +75,10 @@ Note that the path must be valid utf-8, after expansion. db-path = "$CARGO_HOME/advisory-dbs" ``` -## `advisories.version` (optional) +## `advisories.version` -`integer` +**Type:** `integer`
+**Required:** `no` The advisories section has an upcoming breaking change, with deprecation warnings for several fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. @@ -91,9 +96,12 @@ As before, if you want to ignore a specific advisory, add it to the `ignore` fie ### Possible values -2 +- `2` -## `advisories.vulnerability` (optional) +## `advisories.vulnerability` + +**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Required:** `no` **DEPRECATED** (see `version` field) @@ -107,7 +115,10 @@ Determines what happens when a crate with a security vulnerability is encountere vulnerability = "deny" ``` -## `advisories.unmaintained` (optional) +## `advisories.unmaintained` + +**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Required:** `no` **DEPRECATED** (see `version` field) @@ -121,7 +132,10 @@ Determines what happens when a crate with an `unmaintained` advisory is encounte unmaintained = "warn" ``` -## `advisories.unsound` (optional) +## `advisories.unsound` + +**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Required:** `no` **DEPRECATED** (see `version` field) @@ -135,7 +149,10 @@ Determines what happens when a crate with an `unsound` advisory is encountered. unsound = "warn" ``` -## `advisories.notice` (optional) +## `advisories.notice` + +**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Required:** `no` **DEPRECATED** (see `version` field) @@ -152,7 +169,10 @@ Determines what happens when a crate with a `notice` advisory is encountered. notice = "warn" ``` -## `advisories.yanked` (optional) +## `advisories.yanked` + +**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Required:** `no` Determines what happens when a crate with a version that has been yanked from its source registry is encountered. @@ -165,9 +185,10 @@ registry is encountered. yanked = "warn" ``` -## `advisories.ignore` (optional) +## `advisories.ignore` -`array` +**Type:** `array`
+**Required:** `no` Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. Putting an identifier in this array will cause the advisory to be treated as a note, rather @@ -193,19 +214,20 @@ ignore = [ -#### `advisories.ignore[N] (as String)` (as String) +#### Variant: `String` -`string` +**Type:** `string` Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). -#### `advisories.ignore[N] (as Advisory)` (as Advisory) +#### Variant: `Advisory` -`object` +**Type:** `object` -##### `advisories.ignore[N] (as Advisory).id` (required) +##### `advisories.ignore[N] (as Advisory).id` -`string` +**Type:** `string`
+**Required:** `yes` The unique identifier of the advisory to ignore @@ -216,17 +238,19 @@ The unique identifier of the advisory to ignore ignore = ["RUSTSEC-2019-0001"] ``` -##### `advisories.ignore[N] (as Advisory).reason` (optional) - +##### `advisories.ignore[N] (as Advisory).reason` +**Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
+**Required:** `no` -#### `advisories.ignore[N] (as Yanked)` (as Yanked) +#### Variant: `Yanked` -`object` +**Type:** `object` -##### `advisories.ignore[N] (as Yanked).crate` (required) +##### `advisories.ignore[N] (as Yanked).crate` -`string` +**Type:** `string`
+**Required:** `yes` Many configuration options require a package specifier at a minimum, which we'll describe here. The options that use package specifiers will be called out in their individual documentation. @@ -299,5 +323,7 @@ The old format uses a required `name` key and an optional `version` key. This fo and should not be used. -##### `advisories.ignore[N] (as Yanked).reason` (optional) +##### `advisories.ignore[N] (as Yanked).reason` +**Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
+**Required:** `no` \ No newline at end of file diff --git a/docs/src/checks2/advisories/diags.md b/docs/src/checks2/advisories/diags.md new file mode 100644 index 00000000..c5f98215 --- /dev/null +++ b/docs/src/checks2/advisories/diags.md @@ -0,0 +1 @@ +# diagnostics diff --git a/docs/src/checks2/bans/README.md b/docs/src/checks2/bans/README.md new file mode 100644 index 00000000..27c9f3ef --- /dev/null +++ b/docs/src/checks2/bans/README.md @@ -0,0 +1 @@ +# bans diff --git a/docs/src/checks2/bans/cfg.md b/docs/src/checks2/bans/cfg.md new file mode 100644 index 00000000..1417945b --- /dev/null +++ b/docs/src/checks2/bans/cfg.md @@ -0,0 +1 @@ +# config diff --git a/docs/src/checks2/bans/diags.md b/docs/src/checks2/bans/diags.md new file mode 100644 index 00000000..c5f98215 --- /dev/null +++ b/docs/src/checks2/bans/diags.md @@ -0,0 +1 @@ +# diagnostics diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md index 3bcfb05f..6606eefa 100644 --- a/docs/src/checks2/cfg.md +++ b/docs/src/checks2/cfg.md @@ -5,7 +5,7 @@ The top level config for cargo-deny, by default called `deny.toml`. ## Example - cargo-deny's own configuration ```ini -{{{{#include ../../../deny.toml}}}} +{{#include ../../../deny.toml}} ``` ## The `[advisories]` section diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md index b2faf310..2be7ab24 100644 --- a/docs/src/checks2/graph/cfg.md +++ b/docs/src/checks2/graph/cfg.md @@ -1,14 +1,16 @@ -# `graph` (optional) +# `graph` -`object` +**Type:** `object`
+**Required:** `no` The graph table configures how the dependency graph is constructed and thus which crates the checks are performed against -## `graph.targets` (optional) +## `graph.targets` -`array` +**Type:** `array`
+**Required:** `no` By default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies e.g. @@ -35,36 +37,37 @@ executed against. -#### `graph.targets[N] (as String)` (as String) +#### Variant: `String` +**Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)` +#### Variant: `Advanced` -#### `graph.targets[N] (as Advanced)` (as Advanced) - -`object` +**Type:** `object` Advanced configurations to apply for the target triple ##### Examples - ```toml - [[graph.targets]] - triple = "aarch64-apple-darwin" - ``` - + [[graph.targets]] + triple = "aarch64-apple-darwin" + ``` - ```toml - [[graph.targets]] - triple = "x86_64-pc-windows-msvc" - features = ["some-feature"] - ``` - -##### `graph.targets[N] (as Advanced).triple` (required) + [[graph.targets]] + triple = "x86_64-pc-windows-msvc" + features = ["some-feature"] + ``` +##### `graph.targets[N] (as Advanced).triple` +**Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)`
+**Required:** `yes` -##### `graph.targets[N] (as Advanced).features` (optional) +##### `graph.targets[N] (as Advanced).features` -`string` +**Type:** `string`
+**Required:** `no` Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) predicate, but at the moment, the only way to actually pass them when compiling is to use @@ -74,9 +77,10 @@ this writing, cargo-deny does not attempt to validate that the features you spec actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). -## `graph.exclude` (optional) +## `graph.exclude` -`array` +**Type:** `array`
+**Required:** `no` Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) @@ -94,25 +98,24 @@ via the excluded crate, they will also be excluded from the crate graph. exclude = "some-crate@0.1.0" ``` -### Items - -`string` +## `graph.all-features` -## `graph.all-features` (optional) - -`boolean` +**Type:** `boolean`
+**Required:** `no` If set to `true`, `--all-features` will be used when collecting metadata. -## `graph.no-default-features` (optional) +## `graph.no-default-features` -`boolean` +**Type:** `boolean`
+**Required:** `no` If set to `true`, `--no-default-features` will be used when collecting metadata. -## `graph.features` (optional) +## `graph.features` -`array` +**Type:** `array`
+**Required:** `no` If set, and `--features` is not specified on the cmd line, these features will be used when collecting metadata. @@ -125,13 +128,10 @@ collecting metadata. features = "some-feature" ``` -### Items - -`string` - -## `graph.exclude-dev` (optional) +## `graph.exclude-dev` -`boolean` +**Type:** `boolean`
+**Required:** `no` If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included in the crate graph used for any of the checks. This option can also be enabled on cmd line diff --git a/docs/src/checks2/licenses/README.md b/docs/src/checks2/licenses/README.md new file mode 100644 index 00000000..d40246d5 --- /dev/null +++ b/docs/src/checks2/licenses/README.md @@ -0,0 +1 @@ +# licenses diff --git a/docs/src/checks2/licenses/cfg.md b/docs/src/checks2/licenses/cfg.md new file mode 100644 index 00000000..1417945b --- /dev/null +++ b/docs/src/checks2/licenses/cfg.md @@ -0,0 +1 @@ +# config diff --git a/docs/src/checks2/licenses/diags.md b/docs/src/checks2/licenses/diags.md new file mode 100644 index 00000000..c5f98215 --- /dev/null +++ b/docs/src/checks2/licenses/diags.md @@ -0,0 +1 @@ +# diagnostics diff --git a/docs/src/checks2/output/cfg.md b/docs/src/checks2/output/cfg.md index e2e58329..07286ccd 100644 --- a/docs/src/checks2/output/cfg.md +++ b/docs/src/checks2/output/cfg.md @@ -1,12 +1,14 @@ -# `output` (optional) +# `output` -`object` +**Type:** `object`
+**Required:** `no` The output table provides options for how/if diagnostics are outputted -## `output.feature-depth` (optional) +## `output.feature-depth` -`integer` +**Type:** `integer`
+**Required:** `no` The maximum depth that features will be displayed when inclusion graphs are shown in diagnostics, unless specified via `--feature-depth` on the command line. Only applies to diff --git a/docs/src/checks2/sources/README.md b/docs/src/checks2/sources/README.md new file mode 100644 index 00000000..e916e46e --- /dev/null +++ b/docs/src/checks2/sources/README.md @@ -0,0 +1 @@ +# sources diff --git a/docs/src/checks2/sources/cfg.md b/docs/src/checks2/sources/cfg.md new file mode 100644 index 00000000..1417945b --- /dev/null +++ b/docs/src/checks2/sources/cfg.md @@ -0,0 +1 @@ +# config diff --git a/docs/src/checks2/sources/diags.md b/docs/src/checks2/sources/diags.md new file mode 100644 index 00000000..c5f98215 --- /dev/null +++ b/docs/src/checks2/sources/diags.md @@ -0,0 +1 @@ +# diagnostics diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md new file mode 100644 index 00000000..06ff0fb9 --- /dev/null +++ b/docs/src/checks2/type-index.md @@ -0,0 +1,44 @@ +# Type Index + +This is an index of common types used across the schema. + +## `IgnoreReason` + +**Type:** `string` + +Free-form string that can be used to describe the reason why the advisory is ignored. + +## `LintLevel` + +**Type:** `string` + +### Possible values + +- `"deny"` - Emit an error with details about the problem, and fail the check. + +- `"warn"` - Print a warning for each propblem, but don't fail the check. + +- `"allow"` - Print a note about the problem, but don't fail the check. + +## `TargetString` + +**Type:** `string` + +The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target +you wish to filter target specific dependencies with. If the target triple specified is **not** +one of the targets builtin to `rustc`, the configuration check for that target will be limited +to only the raw `[target..dependencies]` style of target configuration, as `cfg()` +expressions require us to know the details about the target. + + +### Examples + +- ```toml + value = "x86_64-unknown-linux-gnu" + ``` +- ```toml + value = "x86_64-pc-windows-msvc" + ``` +- ```toml + value = "aarch64-apple-darwin" + ``` \ No newline at end of file diff --git a/docs/src/checs2/graph/README.md b/docs/src/checs2/graph/README.md new file mode 100644 index 00000000..8dc858c5 --- /dev/null +++ b/docs/src/checs2/graph/README.md @@ -0,0 +1 @@ +# graph diff --git a/docs/src/checs2/output/README.md b/docs/src/checs2/output/README.md new file mode 100644 index 00000000..2580f631 --- /dev/null +++ b/docs/src/checs2/output/README.md @@ -0,0 +1 @@ +# output diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/input.rs index 714dba0f..0099ecf7 100644 --- a/xtask/src/cli/codegen/input.rs +++ b/xtask/src/cli/codegen/input.rs @@ -66,19 +66,20 @@ pub(crate) struct Schema { #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub(crate) enum EnumVariantSchema { - Undocumented(Value), Documented(DocumentedEnumSchema), + Undocumented(Value), } #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct DocumentedEnumSchema { - #[serde(flatten)] - pub(crate) value: CustomEnumValue, - pub(crate) description: String, + + #[serde(flatten)] + value: CustomEnumValue, } #[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] enum CustomEnumValue { Named { value: Value, name: String }, Inferred { value: String }, @@ -253,6 +254,28 @@ impl Schema { Ok(Some(reference)) } + + pub(crate) fn is_undocumented_primitive(&self) -> bool { + matches!( + self, + Self { + ty: _, + format: None, + deprecated: false, + examples, + object_schema: None, + array_schema: None, + enum_schema: None, + one_of: None, + title: None, + description: None, + reference: None, + default: None, + x_taplo: None, + } + if examples.is_empty() + ) + } } impl RootSchema { diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/xtask/src/cli/codegen/md_doc/mod.rs index 8374c48f..246d8f89 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -20,10 +20,23 @@ struct SectionData { description: Option, default: Option, examples: Vec, + enum_schema: Option>, + ty: Option, format: Option, + type_index_ref: Option, +} + +#[derive(Debug)] +struct TypeIndexRef { + definition: String, ty: Option, - enum_schema: Option>, - type_index_ref: Option, + format: Option, +} + +#[derive(Debug)] +struct TypeInfo { + inner: Option, + format: Option, } #[derive(Debug)] @@ -45,12 +58,12 @@ struct KeyedSchema { #[derive(Clone, Debug)] struct SchemaKey { - root: SchemaRoot, + root: SchemaKeyOrigin, segments: Vec, } #[derive(Clone, Debug)] -enum SchemaRoot { +enum SchemaKeyOrigin { Root, Definition(String), } @@ -116,7 +129,7 @@ impl Doc { impl RootContext<'_> { fn root_section(&self) -> Result
{ let key = SchemaKey { - root: SchemaRoot::Root, + root: SchemaKeyOrigin::Root, segments: vec![], }; let root_schema = KeyedSchema::new(key, self.root.schema.clone()); @@ -131,7 +144,7 @@ impl RootContext<'_> { .iter() .map(|(def_name, &schema)| { let key = SchemaKey { - root: SchemaRoot::Definition(def_name.clone()), + root: SchemaKeyOrigin::Definition(def_name.clone()), segments: vec![], }; let schema = KeyedSchema::new(key, schema.clone()); @@ -177,6 +190,12 @@ impl RootContext<'_> { fn array_children(schema: KeyedSchema) -> Result> { let array = schema.inner.try_into_array()?; + + // Avoid adding useless documentation for item + if array.items.is_undocumented_primitive() { + return Ok(vec![]); + } + let key = schema.key.next_level(SchemaKeySegment::Index); let items = KeyedSchema::new(key, *array.items); Ok(vec![items]) @@ -232,11 +251,35 @@ impl RootContext<'_> { } fn section_data(&self, schema: KeyedSchema) -> Result { - let type_index_ref = schema + let type_index_ref = schema.inner.referenced_definition()?.and_then(|def_name| { + let schema = self.type_index.get(def_name)?; + Some(TypeIndexRef { + definition: def_name.to_owned(), + ty: schema.ty.clone(), + format: schema.format.clone(), + }) + }); + + let ty = schema .inner - .referenced_definition()? - .filter(|&def_name| self.type_index.contains_key(def_name)) - .map(ToOwned::to_owned); + .array_schema + .as_ref() + .map(|array_schema| { + let suffix = array_schema + .items + .is_undocumented_primitive() + .then(|| { + array_schema + .items + .ty + .as_ref() + .map(|item_ty| format!("<{item_ty}>")) + }) + .flatten(); + + itertools::chain(["array"], suffix.as_deref()).collect() + }) + .or(schema.inner.ty); let base = SectionData { key: schema.key, @@ -244,8 +287,8 @@ impl RootContext<'_> { description: schema.inner.description, default: schema.inner.default, examples: schema.inner.examples, + ty, format: schema.inner.format, - ty: schema.inner.ty, enum_schema: schema.inner.enum_schema, type_index_ref, }; @@ -282,10 +325,6 @@ impl SchemaKey { segments, } } - - fn last_segment(&self) -> &SchemaKeySegment { - self.segments.last().unwrap() - } } impl fmt::Display for SchemaKey { @@ -327,7 +366,7 @@ The top level config for cargo-deny, by default called `deny.toml`. ## Example - cargo-deny's own configuration ```ini -{{{{#include ../../../deny.toml}}}} +{{#include ../../../deny.toml}} ```"; let cfg = RenderingConfig { @@ -336,9 +375,7 @@ The top level config for cargo-deny, by default called `deny.toml`. let files = Doc::from_root_schema(root)?.render(&cfg); - for file in files { - file.write(out_dir)?; - } + files.iter().try_for_each(|file| file.write(out_dir))?; Ok(()) } diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs index de908d83..e82face2 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -1,5 +1,5 @@ -use super::{SchemaKey, Section, SectionData}; -use crate::cli::codegen::md_doc::SchemaKeySegment; +use super::{Doc, SchemaKey, Section, SectionData, TypeInfo}; +use crate::cli::codegen::md_doc::{SchemaKeyOrigin, SchemaKeySegment}; use anyhow::{Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; @@ -21,32 +21,7 @@ pub(crate) struct RenderedSection { children: Vec, } -impl RenderedSection { - pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { - Self { - header: header.into(), - body: body.into(), - children: vec![], - } - } - - /// Render the section as markdown with the headers starting at the given level - fn to_markdown(&self, level: usize) -> String { - let header = self.header.clone(); - let sharps = "#".repeat(level); - let header = format!("{sharps} {header}"); - let body = self.body.clone(); - - let children = self - .children - .iter() - .map(|child| child.to_markdown(level + 1)); - - itertools::chain([header, body], children).join("\n\n") - } -} - -impl super::Doc { +impl Doc { pub(crate) fn render(&self, cfg: &RenderingConfig) -> Vec { let root_sections = self.root.children.iter().map(|section| { let key = §ion.data.key; @@ -68,26 +43,47 @@ impl super::Doc { File::new(format!("{key}/cfg.md"), rendered) }); - itertools::chain([root], child_files).collect() + let type_index_sections = self.type_index.values().map(Section::render).collect(); + + let type_index = RenderedSection { + header: "Type Index".to_owned(), + body: "This is an index of common types used across the schema.".to_owned(), + children: type_index_sections, + }; + + let type_index = File::new("type-index.md", type_index); + + itertools::chain([root, type_index], child_files).collect() } } -impl Section { - fn render(&self) -> RenderedSection { - // let properties = gen_object_doc(root, 1, section, section.inner.try_as_object()?)?; - - // let section_key = §ion.key.last().unwrap(); +impl RenderedSection { + pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { + Self { + header: header.into(), + body: body.into(), + children: vec![], + } + } - // let content = format!( - // "\ - // # The `[{section_key}]` section + /// Render the section as markdown with the headers starting at the given level + fn to_markdown(&self, level: usize) -> String { + let header = self.header.clone(); + let sharps = "#".repeat(level); + let header = format!("{sharps} {header}"); + let body = self.body.clone(); - // {properties} - // ", - // ); + let children = self + .children + .iter() + .map(|child| child.to_markdown(level + 1)); - // write_file(format!("{section_key}/cfg.md"), &content) + itertools::chain([header, body], children).join("\n\n") + } +} +impl Section { + fn render(&self) -> RenderedSection { let children = [ self.data.enum_doc(), self.data.default(), @@ -104,14 +100,6 @@ impl Section { let header = self.data.header(); - // if items.inner.is_primitive() && gen_generic_details(&items, paragraph_level)?.is_empty() { - // let ty = primitive_type_label(&items)?; - // return Ok(format!( - // "`array of {ty}`\n\n\ - // {array_details}" - // )); - // } - RenderedSection { header, body: self.data.render_body(), @@ -122,33 +110,84 @@ impl Section { impl SectionData { fn header(&self) -> String { - let suffix = match self.key.last_segment() { - SchemaKeySegment::Field(field) => { - let requirement = match field.required { - true => "required", - false => "optional", - }; - format!("({requirement})") - } - SchemaKeySegment::Index => return "Items".to_owned(), - SchemaKeySegment::Variant(variant_name) => format!("(as {variant_name})"), - }; - - let prefix = &self.key; + if let SchemaKeyOrigin::Definition(def) = &self.key.root { + return format!("`{def}`"); + } + let last_segment = self.key.segments.last().unwrap_or_else(|| { + panic!( + "Last segment must always be present in a key with the origin \ + in root schema, but got empty key segments list: {:#?}", + self.key + ) + }); - format!("`{prefix}` {suffix}") + match last_segment { + SchemaKeySegment::Field(_) => format!("`{}`", self.key), + SchemaKeySegment::Index => "Items".to_owned(), + SchemaKeySegment::Variant(variant_name) => format!("Variant: `{variant_name}`"), + } } fn render_body(&self) -> String { - let type_label = self.type_label().map(|label| format!("`{label}`")); + let top = [&self.type_info(), &self.format(), &self.field_requirement()]; + + let top = top.into_iter().flatten().join("
\n"); - let parts = [&type_label, &self.title, &self.description]; + let parts = [&Some(top), &self.title, &self.description]; let body = parts.into_iter().flatten().join("\n\n"); body } + fn field_requirement(&self) -> Option { + let SchemaKeySegment::Field(field) = self.key.segments.last()? else { + return None; + }; + + let requirement = match field.required { + true => "yes", + false => "no", + }; + Some(format!("**Required:** `{requirement}`")) + } + + fn format(&self) -> Option { + let format = self + .format + .as_ref() + .or_else(|| self.type_index_ref.as_ref()?.format.as_ref())?; + + Some(format!("**Format:** `{format}`")) + } + + fn type_info(&self) -> Option { + let ty_ref = self.type_index_ref.as_ref().map(|ty_ref| { + let definition = &ty_ref.definition; + let anchor = definition.to_lowercase(); + format!("[`{definition}`](/checks2/type-index.html#{anchor})") + }); + + let ty = self + .ty + .as_ref() + .or_else(|| self.type_index_ref.as_ref()?.ty.as_ref()); + + let ty = if ty_ref.is_some() { + ty.map(|ty| format!("`({ty})`")) + } else { + ty.map(|ty| format!("`{ty}`")) + }; + + let parts = [ty_ref, ty].iter().flatten().join(" "); + + if parts.is_empty() { + return None; + } + + Some(format!("**Type:** {parts}")) + } + fn default(&self) -> Option { self.default .as_ref() @@ -160,16 +199,6 @@ impl SectionData { RenderedSection::leaf(header, toml) } - fn type_label(&self) -> Option { - let ty = self.ty.as_deref()?; - - let format = self.format.as_deref().map(|format| format!("({format})")); - - let label = itertools::chain([ty], format.as_deref()).join(" "); - - Some(label) - } - fn examples(&self) -> Option { match self.examples.as_slice() { [] => return None, @@ -191,13 +220,13 @@ impl SectionData { if i == 0 { f(&line) } else { - f(&format_args!(" {}", line)) + f(&format_args!(" {line}")) } }); format!("- {example}") }) - .join("\n\n"); + .join("\n"); Some(RenderedSection::leaf("Examples", examples)) } @@ -209,9 +238,10 @@ impl SectionData { .iter() .map(|enum_variant| { let (value, description) = enum_variant.value_and_description(); - let value = value.to_string(); - let doc = itertools::chain([value.as_str()], description).join("-"); - doc + let value = format!("`{value}`"); + let doc = itertools::chain([value.as_str()], description).format(" - "); + + format!("- {doc}") }) .join("\n\n"); @@ -239,7 +269,15 @@ impl SchemaKey { } } - let value = wrap(&self.segments, value.clone()); + let mut value = wrap(&self.segments, value.clone()); + + let is_primitive = !value.is_object() && !value.is_array(); + + // TOML doesn't support primitive values at the top level, so we use + // a hack to wrap it into an object + if is_primitive { + value = json!({ "value": value }); + } let toml = toml::to_string_pretty(&value).unwrap_or_else(|err| { panic!( @@ -267,9 +305,9 @@ impl File { pub(crate) fn write(&self, prefix: impl AsRef) -> Result<()> { let path = prefix.as_ref().join(&self.path); - std::fs::create_dir_all(&path.parent().unwrap())?; + std::fs::create_dir_all(path.parent().unwrap())?; - std::fs::write(&path, &self.rendered.to_markdown(1)) + std::fs::write(&path, self.rendered.to_markdown(1)) .with_context(|| format!("Failed to write to file: {path}")) } } From d9aa89142bd850b1f000301107a2a09a37d5758a Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 8 Apr 2024 08:15:16 +0000 Subject: [PATCH 09/20] Next iteration --- deny.schema.json | 28 ++++++++- deny.schema.yml | 28 +++++++-- docs/src/checks2/advisories/cfg.md | 73 +--------------------- docs/src/checks2/bans/cfg.md | 25 +++++++- docs/src/checks2/cfg.md | 22 +++++++ docs/src/checks2/type-index.md | 75 +++++++++++++++++++++++ xtask/src/cli/codegen/md_doc/rendering.rs | 2 + 7 files changed, 172 insertions(+), 81 deletions(-) diff --git a/deny.schema.json b/deny.schema.json index 11905b1f..2ff346e3 100644 --- a/deny.schema.json +++ b/deny.schema.json @@ -4,6 +4,9 @@ "advisories": { "$ref": "#/definitions/Advisories" }, + "bans": { + "$ref": "#/definitions/Bans" + }, "graph": { "$ref": "#/definitions/Graph" }, @@ -190,7 +193,7 @@ "description": "Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" } }, - "description": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as Unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" + "title": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as Unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" }, "AdvisoriesIgnoreAdvisory": { "type": "object", @@ -241,6 +244,22 @@ "crate" ] }, + "Bans": { + "type": "object", + "properties": { + "allow": { + "$ref": "#/definitions/BansAllow" + } + }, + "title": "Checks for specific crates in your graph, as well as duplicates.\n\nThis section is considered when running `cargo deny check bans`.\n" + }, + "BansAllow": { + "type": "array", + "items": { + "$ref": "#/definitions/PackageSpec" + }, + "description": "Determines specific crates that are allowed. If the `allow` list has one or more entries, then\nany crate not in that list will be denied, so use with care. Each entry uses the same\n[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nas other parts of cargo-deny's configuration.\n" + }, "Graph": { "type": "object", "properties": { @@ -284,7 +303,7 @@ "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" } }, - "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n" + "title": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n" }, "IgnoreReason": { "type": "string", @@ -316,7 +335,7 @@ "default": 1 } }, - "description": "The output table provides options for how/if diagnostics are outputted" + "title": "The output table provides options for how/if diagnostics are outputted" }, "PackageSpec": { "type": "string", @@ -378,6 +397,9 @@ "advisories": { "$ref": "#/definitions/Advisories" }, + "bans": { + "$ref": "#/definitions/Bans" + }, "graph": { "$ref": "#/definitions/Graph" }, diff --git a/deny.schema.yml b/deny.schema.yml index debe8cd1..31faceb1 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -36,6 +36,7 @@ description: Full documentation is at https://embarkstudios.github.io/cargo-deny type: object properties: advisories: { $ref: "#/definitions/Advisories" } + bans: { $ref: "#/definitions/Bans" } graph: { $ref: "#/definitions/Graph" } output: { $ref: "#/definitions/Output" } @@ -55,14 +56,12 @@ definitions: - { crate: yanked, reason: a new version has not been released } severity-threshold: medium - description: | + title: | Checks advisory databases for crates with security vulnerabilities, or that have been marked as Unmaintained, or which have been yanked from their source registry. This section is considered when running `cargo deny check advisories`. - # More documentation for the advisories section can be found - # [here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html) type: object properties: @@ -289,8 +288,27 @@ definitions: The old format uses a required `name` key and an optional `version` key. This format is deprecated and should not be used. - Graph: + Bans: + title: | + Checks for specific crates in your graph, as well as duplicates. + + This section is considered when running `cargo deny check bans`. + + type: object + properties: + allow: { $ref: "#/definitions/BansAllow" } + + BansAllow: + type: array + items: { $ref: "#/definitions/PackageSpec" } description: | + Determines specific crates that are allowed. If the `allow` list has one or more entries, then + any crate not in that list will be denied, so use with care. Each entry uses the same + [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + as other parts of cargo-deny's configuration. + + Graph: + title: | The graph table configures how the dependency graph is constructed and thus which crates the checks are performed against @@ -401,7 +419,7 @@ definitions: expressions require us to know the details about the target. Output: - description: The output table provides options for how/if diagnostics are outputted + title: The output table provides options for how/if diagnostics are outputted type: object properties: feature-depth: diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md index 171a767b..419f5744 100644 --- a/docs/src/checks2/advisories/cfg.md +++ b/docs/src/checks2/advisories/cfg.md @@ -249,80 +249,9 @@ ignore = ["RUSTSEC-2019-0001"] ##### `advisories.ignore[N] (as Yanked).crate` -**Type:** `string`
+**Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)`
**Required:** `yes` -Many configuration options require a package specifier at a minimum, which we'll describe here. -The options that use package specifiers will be called out in their individual documentation. -We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. - -### String format - -If the particular only requires a package spec at a minimum, then the string format can be used, -which comes in three forms. - -#### Simple - -```toml -# Will match any version of the simple crate -deny = ["simple"] -``` - -The simplest string is one which is just the crate name. In this case, the version requirement -used when checking will be `*` meaning it will match against all versions of that crate in the graph. - -#### With Version Requirements - -```toml -# Will match only these versions of the simple crate that match the predicate(s) -deny = ["simple:<=0.1,>0.2"] -``` - -If you want to apply version requirements (predicates) to the crate, simply append them following -a `:` separator. - -#### Exact - -```toml -# Will match only this exact version of the simple crate -deny = [ - "simple@0.1.0", - # This is semantically equivalent to the above - "simple:=0.1.0", -] -``` - -The exact form is a specialization of the version requirements, where the semver after the `@` -is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). - -### Table format - -#### Crate format - -```toml -deny = [ - { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" - { crate = "simple", wrappers = ["example"] }, -] -``` - -The crate format is a replacement for the old `name` and/or `version` table format. It uses -the string format described above in a single `crate` key. - -#### Old format - -```toml -deny = [ - { name = "simple" }, - { name = "simple", version = "*" } - { name = "simple", wrappers = ["example"] } -] -``` - -The old format uses a required `name` key and an optional `version` key. This format is deprecated -and should not be used. - - ##### `advisories.ignore[N] (as Yanked).reason` **Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
diff --git a/docs/src/checks2/bans/cfg.md b/docs/src/checks2/bans/cfg.md index 1417945b..1850e76e 100644 --- a/docs/src/checks2/bans/cfg.md +++ b/docs/src/checks2/bans/cfg.md @@ -1 +1,24 @@ -# config +# `bans` + +**Type:** `object`
+**Required:** `no` + +Checks for specific crates in your graph, as well as duplicates. + +This section is considered when running `cargo deny check bans`. + + +## `bans.allow` + +**Type:** `array`
+**Required:** `no` + +Determines specific crates that are allowed. If the `allow` list has one or more entries, then +any crate not in that list will be denied, so use with care. Each entry uses the same +[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +as other parts of cargo-deny's configuration. + + +### Items + +**Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)` \ No newline at end of file diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md index 6606eefa..acab86b0 100644 --- a/docs/src/checks2/cfg.md +++ b/docs/src/checks2/cfg.md @@ -10,12 +10,34 @@ The top level config for cargo-deny, by default called `deny.toml`. ## The `[advisories]` section +Checks advisory databases for crates with security vulnerabilities, +or that have been marked as Unmaintained, or which have been yanked from +their source registry. + +This section is considered when running `cargo deny check advisories`. + + See [advisories config](advisories/cfg.html) for more info. +## The `[bans]` section + +Checks for specific crates in your graph, as well as duplicates. + +This section is considered when running `cargo deny check bans`. + + +See [bans config](bans/cfg.html) for more info. + ## The `[graph]` section +The graph table configures how the dependency graph is constructed and thus which crates the +checks are performed against + + See [graph config](graph/cfg.html) for more info. ## The `[output]` section +The output table provides options for how/if diagnostics are outputted + See [output config](output/cfg.html) for more info. \ No newline at end of file diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md index 06ff0fb9..966e8c1a 100644 --- a/docs/src/checks2/type-index.md +++ b/docs/src/checks2/type-index.md @@ -20,6 +20,81 @@ Free-form string that can be used to describe the reason why the advisory is ign - `"allow"` - Print a note about the problem, but don't fail the check. +## `PackageSpec` + +**Type:** `string` + +Many configuration options require a package specifier at a minimum, which we'll describe here. +The options that use package specifiers will be called out in their individual documentation. +We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + +### String format + +If the particular only requires a package spec at a minimum, then the string format can be used, +which comes in three forms. + +#### Simple + +```toml +# Will match any version of the simple crate +deny = ["simple"] +``` + +The simplest string is one which is just the crate name. In this case, the version requirement +used when checking will be `*` meaning it will match against all versions of that crate in the graph. + +#### With Version Requirements + +```toml +# Will match only these versions of the simple crate that match the predicate(s) +deny = ["simple:<=0.1,>0.2"] +``` + +If you want to apply version requirements (predicates) to the crate, simply append them following +a `:` separator. + +#### Exact + +```toml +# Will match only this exact version of the simple crate +deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", +] +``` + +The exact form is a specialization of the version requirements, where the semver after the `@` +is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + +### Table format + +#### Crate format + +```toml +deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, +] +``` + +The crate format is a replacement for the old `name` and/or `version` table format. It uses +the string format described above in a single `crate` key. + +#### Old format + +```toml +deny = [ + { name = "simple" }, + { name = "simple", version = "*" } + { name = "simple", wrappers = ["example"] } +] +``` + +The old format uses a required `name` key and an optional `version` key. This format is deprecated +and should not be used. + + ## `TargetString` **Type:** `string` diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs index e82face2..dcbe97db 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -27,6 +27,8 @@ impl Doc { let key = §ion.data.key; let header = format!("The `[{key}]` section"); let body = format!("See [{key} config]({key}/cfg.html) for more info."); + let body = itertools::chain(§ion.data.title, [&body]).join("\n\n"); + RenderedSection::leaf(header, body) }); From 791d869eb3f9feb61c1326361ffadcbe1df4a385 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 14 Apr 2024 16:09:17 +0000 Subject: [PATCH 10/20] Next iteration --- deny.schema.json | 12 +- deny.schema.yml | 20 +- deny.template.toml | 2 +- docs/src/checks2/advisories/cfg.md | 37 +-- docs/src/checks2/bans/cfg.md | 2 +- docs/src/checks2/cfg.md | 10 +- docs/src/checks2/graph/cfg.md | 10 +- docs/src/checks2/type-index.md | 2 +- xtask/src/cli/codegen/input.rs | 109 +++--- xtask/src/cli/codegen/md_doc/mod.rs | 384 +++++++++++++++------- xtask/src/cli/codegen/md_doc/rendering.rs | 246 +++++++------- 11 files changed, 497 insertions(+), 337 deletions(-) diff --git a/deny.schema.json b/deny.schema.json index 2ff346e3..635ff281 100644 --- a/deny.schema.json +++ b/deny.schema.json @@ -193,7 +193,7 @@ "description": "Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" } }, - "title": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as Unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" + "title": "Checks advisory databases for crates with security vulnerabilities,\nor that have been marked as unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n" }, "AdvisoriesIgnoreAdvisory": { "type": "object", @@ -216,16 +216,16 @@ "AdvisoriesIgnoreItem": { "oneOf": [ { - "name": "String", + "name": null, "type": "string", "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." }, { - "name": "Advisory", + "name": null, "$ref": "#/definitions/AdvisoriesIgnoreAdvisory" }, { - "name": "Yanked", + "name": null, "$ref": "#/definitions/AdvisoriesIgnoreYanked" } ] @@ -344,11 +344,11 @@ "Target": { "oneOf": [ { - "name": "String", + "name": null, "$ref": "#/definitions/TargetString" }, { - "name": "Advanced", + "name": null, "$ref": "#/definitions/TargetAdvanced" } ] diff --git a/deny.schema.yml b/deny.schema.yml index 31faceb1..ed61fc41 100644 --- a/deny.schema.yml +++ b/deny.schema.yml @@ -58,7 +58,7 @@ definitions: title: | Checks advisory databases for crates with security vulnerabilities, - or that have been marked as Unmaintained, or which have been yanked from + or that have been marked as unmaintained, or which have been yanked from their source registry. This section is considered when running `cargo deny check advisories`. @@ -174,15 +174,12 @@ definitions: AdvisoriesIgnoreItem: oneOf: - - name: String - type: string + - type: string description: Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - - name: Advisory - $ref: "#/definitions/AdvisoriesIgnoreAdvisory" + - $ref: "#/definitions/AdvisoriesIgnoreAdvisory" - - name: Yanked - $ref: "#/definitions/AdvisoriesIgnoreYanked" + - $ref: "#/definitions/AdvisoriesIgnoreYanked" AdvisoriesIgnoreAdvisory: type: object @@ -280,7 +277,7 @@ definitions: ```toml deny = [ { name = "simple" }, - { name = "simple", version = "*" } + { name = "simple", version = "*" }, { name = "simple", wrappers = ["example"] } ] ``` @@ -378,11 +375,8 @@ definitions: Target: oneOf: - - name: String - $ref: "#/definitions/TargetString" - - - name: Advanced - $ref: "#/definitions/TargetAdvanced" + - $ref: "#/definitions/TargetString" + - $ref: "#/definitions/TargetAdvanced" TargetAdvanced: description: Advanced configurations to apply for the target triple diff --git a/deny.template.toml b/deny.template.toml index 43bdcb5d..23a94040 100644 --- a/deny.template.toml +++ b/deny.template.toml @@ -1,4 +1,4 @@ -#:schema deny16.schema.json +#:schema deny.schema.json # This template contains all of the possible sections and their default values diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md index 419f5744..3a6cddfa 100644 --- a/docs/src/checks2/advisories/cfg.md +++ b/docs/src/checks2/advisories/cfg.md @@ -4,7 +4,7 @@ **Required:** `no` Checks advisory databases for crates with security vulnerabilities, -or that have been marked as Unmaintained, or which have been yanked from +or that have been marked as unmaintained, or which have been yanked from their source registry. This section is considered when running `cargo deny check advisories`. @@ -31,7 +31,7 @@ severity-threshold = "medium" ## `advisories.db-urls` -**Type:** `array`
+**Type:** `array`
**Required:** `no` URLs to one or more advisory databases. @@ -43,11 +43,6 @@ URLs to one or more advisory databases. db-urls = ["https://github.com/RustSec/advisory-db"] ``` -### Items - -**Type:** `string`
-**Format:** `uri` - ## `advisories.db-path` **Type:** `string`
@@ -77,7 +72,7 @@ db-path = "$CARGO_HOME/advisory-dbs" ## `advisories.version` -**Type:** `integer`
+**Type:** `integer (enum)`
**Required:** `no` The advisories section has an upcoming breaking change, with deprecation warnings for several @@ -100,7 +95,7 @@ As before, if you want to ignore a specific advisory, add it to the `ignore` fie ## `advisories.vulnerability` -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
**Required:** `no` **DEPRECATED** (see `version` field) @@ -117,7 +112,7 @@ vulnerability = "deny" ## `advisories.unmaintained` -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
**Required:** `no` **DEPRECATED** (see `version` field) @@ -134,7 +129,7 @@ unmaintained = "warn" ## `advisories.unsound` -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
**Required:** `no` **DEPRECATED** (see `version` field) @@ -151,7 +146,7 @@ unsound = "warn" ## `advisories.notice` -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
**Required:** `no` **DEPRECATED** (see `version` field) @@ -171,7 +166,7 @@ notice = "warn" ## `advisories.yanked` -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string)`
+**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
**Required:** `no` Determines what happens when a crate with a version that has been yanked from its source @@ -210,21 +205,21 @@ ignore = [ ] ``` -### Items +### Array item -#### Variant: `String` +#### Variant: `string` **Type:** `string` Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). -#### Variant: `Advisory` +#### Variant: `AdvisoriesIgnoreAdvisory` **Type:** `object` -##### `advisories.ignore[N] (as Advisory).id` +##### `advisories.ignore array item as AdvisoriesIgnoreAdvisory.id` **Type:** `string`
**Required:** `yes` @@ -238,21 +233,21 @@ The unique identifier of the advisory to ignore ignore = ["RUSTSEC-2019-0001"] ``` -##### `advisories.ignore[N] (as Advisory).reason` +##### `advisories.ignore array item as AdvisoriesIgnoreAdvisory.reason` **Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
**Required:** `no` -#### Variant: `Yanked` +#### Variant: `AdvisoriesIgnoreYanked` **Type:** `object` -##### `advisories.ignore[N] (as Yanked).crate` +##### `advisories.ignore array item as AdvisoriesIgnoreYanked.crate` **Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)`
**Required:** `yes` -##### `advisories.ignore[N] (as Yanked).reason` +##### `advisories.ignore array item as AdvisoriesIgnoreYanked.reason` **Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
**Required:** `no` \ No newline at end of file diff --git a/docs/src/checks2/bans/cfg.md b/docs/src/checks2/bans/cfg.md index 1850e76e..e2b40e39 100644 --- a/docs/src/checks2/bans/cfg.md +++ b/docs/src/checks2/bans/cfg.md @@ -19,6 +19,6 @@ any crate not in that list will be denied, so use with care. Each entry uses the as other parts of cargo-deny's configuration. -### Items +### Array item **Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)` \ No newline at end of file diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md index acab86b0..4cd83aec 100644 --- a/docs/src/checks2/cfg.md +++ b/docs/src/checks2/cfg.md @@ -8,10 +8,10 @@ The top level config for cargo-deny, by default called `deny.toml`. {{#include ../../../deny.toml}} ``` -## The `[advisories]` section +## The `[advisories]` type_doc Checks advisory databases for crates with security vulnerabilities, -or that have been marked as Unmaintained, or which have been yanked from +or that have been marked as unmaintained, or which have been yanked from their source registry. This section is considered when running `cargo deny check advisories`. @@ -19,7 +19,7 @@ This section is considered when running `cargo deny check advisories`. See [advisories config](advisories/cfg.html) for more info. -## The `[bans]` section +## The `[bans]` type_doc Checks for specific crates in your graph, as well as duplicates. @@ -28,7 +28,7 @@ This section is considered when running `cargo deny check bans`. See [bans config](bans/cfg.html) for more info. -## The `[graph]` section +## The `[graph]` type_doc The graph table configures how the dependency graph is constructed and thus which crates the checks are performed against @@ -36,7 +36,7 @@ checks are performed against See [graph config](graph/cfg.html) for more info. -## The `[output]` section +## The `[output]` type_doc The output table provides options for how/if diagnostics are outputted diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md index 2be7ab24..da27a905 100644 --- a/docs/src/checks2/graph/cfg.md +++ b/docs/src/checks2/graph/cfg.md @@ -33,15 +33,15 @@ to it, it is not included into the crate graph that the checks are executed against. -### Items +### Array item -#### Variant: `String` +#### Variant: `TargetString` **Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)` -#### Variant: `Advanced` +#### Variant: `TargetAdvanced` **Type:** `object` @@ -59,12 +59,12 @@ Advanced configurations to apply for the target triple features = ["some-feature"] ``` -##### `graph.targets[N] (as Advanced).triple` +##### `graph.targets array item as TargetAdvanced.triple` **Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)`
**Required:** `yes` -##### `graph.targets[N] (as Advanced).features` +##### `graph.targets array item as TargetAdvanced.features` **Type:** `string`
**Required:** `no` diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md index 966e8c1a..47104d2e 100644 --- a/docs/src/checks2/type-index.md +++ b/docs/src/checks2/type-index.md @@ -10,7 +10,7 @@ Free-form string that can be used to describe the reason why the advisory is ign ## `LintLevel` -**Type:** `string` +**Type:** `string (enum)` ### Possible values diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/input.rs index 0099ecf7..ef1cddfd 100644 --- a/xtask/src/cli/codegen/input.rs +++ b/xtask/src/cli/codegen/input.rs @@ -87,10 +87,12 @@ enum CustomEnumValue { #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct OneOfVariantSchema { - /// Name of the variant. It's main use case is when generating a Rust enum, - /// which requires a name for each variant. However, it's also useful for - /// documentation purposes as a succinct display name for the variant. - pub(crate) name: String, + /// Override the name of the variant. It's main use case is when generating + /// a Rust enum, which requires a name for each variant. However, it's also + /// useful for documentation purposes as a succinct display name for the + /// variant. By default the variant name is inferred from the `$ref` or + /// from the `type` clause of the schema. + pub(crate) name: Option, #[serde(flatten)] pub(crate) schema: Schema, @@ -130,6 +132,11 @@ pub(crate) struct ArraySchema { pub(crate) items: Box, } +pub(crate) struct SchemaEntry<'a> { + pub(crate) schema: &'a Schema, + pub(crate) level: usize, +} + impl Schema { pub(crate) fn is_primitive(&self) -> bool { self.object_schema.is_none() @@ -140,10 +147,15 @@ impl Schema { /// Returns all schemas stored inside of this one. It doesn't resolve /// references. - pub(crate) fn inner_schemas(&self) -> impl Iterator { - let mut stack = vec![self]; + pub(crate) fn entries<'a>(&'a self) -> impl Iterator> { + let mut stack = vec![SchemaEntry { + schema: self, + level: 0, + }]; + std::iter::from_fn(move || { - let schema = stack.pop()?; + let entry = stack.pop()?; + let schema = entry.schema; let object_properties = schema .object_schema @@ -158,13 +170,18 @@ impl Schema { let array_items = schema.array_schema.iter().map(|array| array.items.as_ref()); - stack.extend(itertools::chain!( - object_properties, - one_of_variants, - array_items - )); + let new_entries = std::iter::empty() + .chain(object_properties) + .chain(one_of_variants) + .chain(array_items) + .map(|schema| SchemaEntry { + schema, + level: entry.level + 1, + }); + + stack.extend(new_entries); - Some(schema) + Some(entry) }) } @@ -260,7 +277,7 @@ impl Schema { self, Self { ty: _, - format: None, + format: _, deprecated: false, examples, object_schema: None, @@ -305,17 +322,27 @@ impl RootSchema { let mut schema = schema.clone(); schema.reference = None; - let mut schema_value = serde_json::to_value(schema).unwrap(); - let definition_value = serde_json::to_value(definition).unwrap(); - - merge_json_values_mut(&mut schema_value, definition_value); - - let schema = serde_json::from_value(schema_value).unwrap(); + merge_json_mut(&mut schema, definition); Ok(schema) } } +impl OneOfVariantSchema { + pub(crate) fn name(&self) -> Result<&str> { + self.name + .as_deref() + .or_else(|| { + self.schema + .reference + .as_deref()? + .strip_prefix("#/definitions/") + }) + .or(self.schema.ty.as_deref()) + .with_context(|| format!("Expected name for one-of variant, but got: {self:#?}")) + } +} + impl CustomEnumValue { fn to_json_value(&self) -> Value { match self { @@ -333,14 +360,18 @@ impl EnumVariantSchema { let description = schema.description.as_str(); (value, Some(description)) } - EnumVariantSchema::Undocumented(value) => (value.clone().into(), None), + EnumVariantSchema::Undocumented(value) => (value.clone(), None), } } } -pub(crate) fn merge_json_values(mut a: Value, b: Value) -> Value { - merge_json_values_mut(&mut a, b); - a +fn merge_json_mut(dest: &mut T, src: &T) { + let mut dest_value = serde_json::to_value(&*dest).unwrap(); + let src_value = serde_json::to_value(src).unwrap(); + + merge_json_values_mut(&mut dest_value, src_value); + + *dest = serde_json::from_value(dest_value).unwrap(); } pub(crate) fn merge_json_values_mut(a: &mut Value, b: Value) { @@ -365,33 +396,3 @@ pub(crate) fn merge_json_values_mut(a: &mut Value, b: Value) { (a, b) => *a = b, } } - -// fn merge_serializable(a: &mut T, b: T) { -// let mut a_value = serde_json::to_value(&a).unwrap(); -// let b_value = serde_json::to_value(b).unwrap(); -// merge_json_values(&mut a_value, b_value); - -// *a = serde_json::from_value(a_value).unwrap(); -// } - -// #[derive(Serialize, Deserialize, Debug, Clone)] -// struct XTaplo { -// docs: XTaploDocs, - -// #[serde(flatten)] -// untyped: Object, -// } - -// #[derive(Serialize, Deserialize, Debug, Clone)] -// struct XTaploDocs { -// enum_values: Vec, - -// #[serde(flatten)] -// untyped: Object, -// } - -// impl Schema { -// fn merge(&mut self, other: &Schema) { -// merge_serializable(self, other.clone()); -// } -// } diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/xtask/src/cli/codegen/md_doc/mod.rs index 246d8f89..9d8e5d5f 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -1,52 +1,90 @@ mod rendering; -use self::rendering::{RenderedSection, RenderingConfig}; +use self::rendering::{RenderedSection, Renderer}; use crate::cli::codegen::input::{EnumVariantSchema, RootSchema, Schema}; -use anyhow::Result; +use anyhow::{Context, Result}; use itertools::Itertools; use serde_json::Value; use std::collections::BTreeMap; use std::fmt; +struct DocOptions<'a> { + root: &'a RootSchema, + max_level: usize, +} + pub(crate) struct Doc { - root: Section, - type_index: BTreeMap, + root: TypeDocNode, + type_index: BTreeMap, } #[derive(Debug)] -struct SectionData { +struct TypeDoc { key: SchemaKey, title: Option, description: Option, default: Option, examples: Vec, - enum_schema: Option>, - ty: Option, - format: Option, + ty: Type, type_index_ref: Option, } #[derive(Debug)] struct TypeIndexRef { definition: String, + ty: Type, +} + +#[derive(Debug, Clone)] +struct LeafType { ty: Option, format: Option, + enum_schema: Option>, } -#[derive(Debug)] -struct TypeInfo { - inner: Option, - format: Option, +impl LeafType { + fn from_schema(schema: &Schema) -> Self { + Self { + ty: schema.ty.clone(), + format: schema.format.clone(), + enum_schema: schema.enum_schema.clone(), + } + } +} + +#[derive(Debug, Clone)] +struct Type { + inner: LeafType, + + /// [`LeafType`] exists to make sure we don't have recursion in this field. + /// We describe at max two levels of nesting in type tags. + array_items_ty: Option, +} + +impl Type { + fn from_schema(schema: &Schema) -> Self { + let inner = LeafType::from_schema(schema); + + let array_items_ty = schema + .array_schema + .as_ref() + .map(|array| LeafType::from_schema(&array.items)); + + Self { + inner, + array_items_ty, + } + } } #[derive(Debug)] -struct Section { - data: SectionData, - children: Vec
, +struct TypeDocNode { + inner: TypeDoc, + children: Vec, } -struct RootContext<'a> { - root: &'a RootSchema, +struct CreateDoc<'a> { + options: &'a DocOptions<'a>, type_index: &'a BTreeMap, } @@ -62,6 +100,37 @@ struct SchemaKey { segments: Vec, } +impl SchemaKey { + fn push_inline_segment(&self, new_segment: SchemaKeySegmentKind) -> Self { + let mut segments = self.segments.clone(); + segments.push(SchemaKeySegment::inline(new_segment)); + Self { + root: self.root.clone(), + segments, + } + } + + fn definition(&self) -> Option<&str> { + self.segments.last()?.definition.as_deref() + } +} + +impl fmt::Display for SchemaKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut segments = self.segments.iter(); + + if let Some(segment) = segments.next() { + write!(f, "{segment}")?; + } + + segments.try_for_each(|segment| match &segment.kind { + SchemaKeySegmentKind::Field(_) => write!(f, ".{segment}"), + SchemaKeySegmentKind::Index => write!(f, " array item"), + SchemaKeySegmentKind::Variant(_) => write!(f, " as {segment}"), + }) + } +} + #[derive(Clone, Debug)] enum SchemaKeyOrigin { Root, @@ -69,7 +138,25 @@ enum SchemaKeyOrigin { } #[derive(Clone, Debug)] -enum SchemaKeySegment { +struct SchemaKeySegment { + kind: SchemaKeySegmentKind, + + /// If this part of the key is a reference to a definition, then this field + /// stores the name of that definition. + definition: Option, +} + +impl SchemaKeySegment { + fn inline(kind: SchemaKeySegmentKind) -> Self { + Self { + definition: None, + kind, + } + } +} + +#[derive(Clone, Debug)] +enum SchemaKeySegmentKind { Field(SchemaKeySegmentField), Index, Variant(String), @@ -82,12 +169,17 @@ struct SchemaKeySegmentField { } impl Doc { - fn from_root_schema(root: &RootSchema) -> Result { - let schemas_in_root = root.schema.inner_schemas(); - let schemas_in_defs = root.definitions.values().flat_map(Schema::inner_schemas); + fn new(options: DocOptions<'_>) -> Result { + let DocOptions { root, max_level } = options; - let definition_ref_counts = itertools::chain(schemas_in_root, schemas_in_defs) - .map(Schema::referenced_definition) + let all_schemas = || { + let schemas_in_root = root.schema.entries(); + let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); + itertools::chain(schemas_in_root, schemas_in_defs) + }; + + let definition_ref_counts = all_schemas() + .map(|entry| entry.schema.referenced_definition()) .flatten_ok() .process_results(|iter| iter.counts())?; @@ -102,7 +194,7 @@ impl Doc { "Found unused definitions: {unused_defs:#?}", ); - let type_index: BTreeMap<_, _> = definition_ref_counts + let repeated_references: BTreeMap<_, _> = definition_ref_counts .into_iter() // For schemas that are repeatedly referenced, we want to include them in the // "Type Index". This is separate page where common types are defined such @@ -114,32 +206,118 @@ impl Doc { }) .try_collect()?; - let ctx = RootContext { + let flattened = all_schemas() + .filter(|entry| entry.level % max_level == 0) + .map(|entry| { + let schema = entry.schema; + + }) + .collect(); + + let ctx = CreateDoc { root, - type_index: &type_index, + type_index: &repeated_references, }; - Ok(Self { - root: ctx.root_section()?, - type_index: ctx.type_index_sections()?, - }) + let mut doc = Self { + root: ctx.root_type_doc()?, + type_index: ctx.type_index_docs()?, + }; + + doc.flatten(max_level)?; + + Ok(doc) + } + + fn flatten(&mut self, max_level: usize) -> Result<()> { + FlattenDoc { + ty_index: &mut self.type_index, + max_level, + } + .flatten(&mut self.root, 0) } } -impl RootContext<'_> { - fn root_section(&self) -> Result
{ +struct FlattenDoc<'a> { + ty_index: &'a mut BTreeMap, + max_level: usize, +} + +impl FlattenDoc<'_> { + fn flatten(&mut self, node: &mut TypeDocNode, level: usize) -> Result<()> { + for child in &mut node.children { + if level <= self.max_level { + Self { + ty_index: self.ty_index, + max_level: self.max_level, + } + } + + self.flatten(child, level + 1)?; + } + + if level <= self.max_level { + return Ok(()); + } + + node.children.clear(); + + let type_doc = &node.inner; + + let definition = type_doc + .key + .definition() + .with_context(|| { + format!( + "Can't flatten node at level {level}, because the name to \ + assign to it in the type index can not be inferred.\n\ + Schema key: {}\n\ + Try moving the schema to a definition, and the definition key \ + will be used as a name for this type in the type index", + type_doc.key + ) + })? + .to_owned(); + + let type_index_entry = self.ty_index.get(&definition).unwrap_or_else(|| { + panic!("We inlined this type before, so it must be in type index: {definition}") + }); + + let type_index_ref = TypeIndexRef { + definition: definition.clone(), + ty: type_index_entry.inner.ty.clone(), + }; + + let new_type_doc = TypeDoc { + key: type_doc.key.clone(), + title: None, + description: None, + default: None, + examples: vec![], + ty: type_doc.ty.clone(), + type_index_ref: Some(type_index_ref), + }; + + let node = std::mem::replace(node, TypeDocNode::leaf(new_type_doc)); + + self.ty_index.insert(definition, node); + + Ok(()) + } +} + +impl CreateDoc<'_> { + fn root_type_doc(&self) -> Result { let key = SchemaKey { root: SchemaKeyOrigin::Root, segments: vec![], }; let root_schema = KeyedSchema::new(key, self.root.schema.clone()); - let section = self.section(root_schema)?; - - Ok(section) + self.type_doc_node(root_schema) } - fn type_index_sections(&self) -> Result> { + fn type_index_docs(&self) -> Result> { self.type_index .iter() .map(|(def_name, &schema)| { @@ -149,23 +327,23 @@ impl RootContext<'_> { }; let schema = KeyedSchema::new(key, schema.clone()); - anyhow::Ok((def_name.clone(), self.section(schema)?)) + anyhow::Ok((def_name.clone(), self.type_doc_node(schema)?)) }) .collect() } - fn section(&self, schema: KeyedSchema) -> Result
{ + fn type_doc_node(&self, schema: KeyedSchema) -> Result { let referenced_def = schema.inner.referenced_definition()?; // If this schema references a type from the type index, then avoid - // inlining the schema and finish the section early. + // inlining the schema and finish the type doc early. if referenced_def.is_some_and(|def| self.type_index.contains_key(def)) { - return Ok(Section::leaf(self.section_data(schema.clone())?)); + return Ok(TypeDocNode::leaf(self.type_doc(schema.clone())?)); } let schema = schema.inline_referenced_definition(self.root)?; - let section_data = self.section_data(schema.clone())?; + let type_doc = self.type_doc(schema.clone())?; let children = if schema.inner.array_schema.is_some() { Self::array_children(schema)? @@ -179,11 +357,11 @@ impl RootContext<'_> { let children = children .into_iter() - .map(|child| self.section(child)) + .map(|child| self.type_doc_node(child)) .try_collect()?; - Ok(Section { - data: section_data, + Ok(TypeDocNode { + inner: type_doc, children, }) } @@ -196,7 +374,7 @@ impl RootContext<'_> { return Ok(vec![]); } - let key = schema.key.next_level(SchemaKeySegment::Index); + let key = schema.key.push_inline_segment(SchemaKeySegmentKind::Index); let items = KeyedSchema::new(key, *array.items); Ok(vec![items]) } @@ -212,7 +390,9 @@ impl RootContext<'_> { required: object.required.contains(&key), }; - let key = schema.key.next_level(SchemaKeySegment::Field(key)); + let key = schema + .key + .push_inline_segment(SchemaKeySegmentKind::Field(key)); KeyedSchema::new(key, value) }) .collect(); @@ -222,12 +402,12 @@ impl RootContext<'_> { fn one_of_children(schema: KeyedSchema) -> Result> { let variants = schema.inner.try_into_one_of()?; - - let duplicates: Vec<_> = variants + let names: Vec<_> = variants .iter() - .map(|variant| &variant.name) - .duplicates() - .collect(); + .map(|variant| variant.name().map(ToOwned::to_owned)) + .try_collect()?; + + let duplicates: Vec<_> = names.iter().duplicates().collect(); anyhow::ensure!( duplicates.is_empty(), @@ -238,10 +418,11 @@ impl RootContext<'_> { let variants = variants .into_iter() - .map(|variant| { + .zip(names) + .map(|(variant, name)| { let key = schema .key - .next_level(SchemaKeySegment::Variant(variant.name.clone())); + .push_inline_segment(SchemaKeySegmentKind::Variant(name)); KeyedSchema::new(key, variant.schema) }) @@ -250,46 +431,34 @@ impl RootContext<'_> { Ok(variants) } - fn section_data(&self, schema: KeyedSchema) -> Result { - let type_index_ref = schema.inner.referenced_definition()?.and_then(|def_name| { - let schema = self.type_index.get(def_name)?; + fn type_index_ref(&self, schema: &Schema) -> Result> { + let ty_index_ref = schema.referenced_definition()?.and_then(|def_name| { + let ty = self + .type_index + .get(def_name) + .copied() + .map(Type::from_schema)?; + Some(TypeIndexRef { definition: def_name.to_owned(), - ty: schema.ty.clone(), - format: schema.format.clone(), + ty, }) }); - let ty = schema - .inner - .array_schema - .as_ref() - .map(|array_schema| { - let suffix = array_schema - .items - .is_undocumented_primitive() - .then(|| { - array_schema - .items - .ty - .as_ref() - .map(|item_ty| format!("<{item_ty}>")) - }) - .flatten(); - - itertools::chain(["array"], suffix.as_deref()).collect() - }) - .or(schema.inner.ty); + Ok(ty_index_ref) + } + + fn type_doc(&self, schema: KeyedSchema) -> Result { + let type_index_ref = self.type_index_ref(&schema.inner)?; + let ty = Type::from_schema(&schema.inner); - let base = SectionData { + let base = TypeDoc { key: schema.key, title: schema.inner.title, description: schema.inner.description, default: schema.inner.default, examples: schema.inner.examples, ty, - format: schema.inner.format, - enum_schema: schema.inner.enum_schema, type_index_ref, }; @@ -297,10 +466,10 @@ impl RootContext<'_> { } } -impl Section { - fn leaf(data: SectionData) -> Self { +impl TypeDocNode { + fn leaf(data: TypeDoc) -> Self { Self { - data, + inner: data, children: vec![], } } @@ -308,47 +477,26 @@ impl Section { impl fmt::Display for SchemaKeySegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SchemaKeySegment::Field(field) => f.write_str(&field.name), - SchemaKeySegment::Index => f.write_str("N"), - SchemaKeySegment::Variant(name) => f.write_str(name), + match &self.kind { + SchemaKeySegmentKind::Field(field) => f.write_str(&field.name), + SchemaKeySegmentKind::Index => f.write_str("n"), + SchemaKeySegmentKind::Variant(name) => f.write_str(name), } } } -impl SchemaKey { - fn next_level(&self, new_segment: SchemaKeySegment) -> Self { - let mut segments = self.segments.clone(); - segments.push(new_segment); - Self { - root: self.root.clone(), - segments, - } - } -} - -impl fmt::Display for SchemaKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut segments = self.segments.iter(); - - if let Some(segment) = segments.next() { - write!(f, "{segment}")?; - } - - segments.try_for_each(|segment| match segment { - SchemaKeySegment::Field(_) => write!(f, ".{segment}"), - SchemaKeySegment::Index => write!(f, "[{segment}]"), - SchemaKeySegment::Variant(_) => write!(f, " (as {segment})"), - }) - } -} - impl KeyedSchema { fn new(key: SchemaKey, inner: Schema) -> Self { Self { key, inner } } - fn inline_referenced_definition(self, root: &RootSchema) -> Result { + fn inline_referenced_definition(mut self, root: &RootSchema) -> Result { + if let Some(last_segment) = self.key.segments.last_mut() { + if let Some(definition) = self.inner.referenced_definition()? { + last_segment.definition = Some(definition.to_owned()); + } + } + Ok(Self::new( self.key, root.inline_referenced_definition(&self.inner)?, @@ -369,11 +517,11 @@ The top level config for cargo-deny, by default called `deny.toml`. {{#include ../../../deny.toml}} ```"; - let cfg = RenderingConfig { + let renderer = Renderer { root_file_base: RenderedSection::leaf(header, body), }; - let files = Doc::from_root_schema(root)?.render(&cfg); + let files = renderer.doc(&Doc::new(root, 2)?); files.iter().try_for_each(|file| file.write(out_dir))?; diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs index dcbe97db..20dd775a 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -1,51 +1,43 @@ -use super::{Doc, SchemaKey, Section, SectionData, TypeInfo}; +use super::{Doc, LeafType, SchemaKey, SchemaKeySegmentKind, Type, TypeDoc, TypeDocNode}; use crate::cli::codegen::md_doc::{SchemaKeyOrigin, SchemaKeySegment}; use anyhow::{Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; use serde_json::{json, Value}; -pub(crate) struct RenderingConfig { +pub(crate) struct Renderer { pub(crate) root_file_base: RenderedSection, } -pub(crate) struct File { - path: Utf8PathBuf, - rendered: RenderedSection, -} - -#[derive(Clone, Debug)] -pub(crate) struct RenderedSection { - header: String, - body: String, - children: Vec, -} - -impl Doc { - pub(crate) fn render(&self, cfg: &RenderingConfig) -> Vec { - let root_sections = self.root.children.iter().map(|section| { - let key = §ion.data.key; - let header = format!("The `[{key}]` section"); +impl Renderer { + pub(crate) fn doc(&self, doc: &Doc) -> Vec { + let root_sections = doc.root.children.iter().map(|type_doc| { + let key = &type_doc.inner.key; + let header = format!("The `[{key}]` type_doc"); let body = format!("See [{key} config]({key}/cfg.html) for more info."); - let body = itertools::chain(§ion.data.title, [&body]).join("\n\n"); + let body = itertools::chain(&type_doc.inner.title, [&body]).join("\n\n"); RenderedSection::leaf(header, body) }); - let mut rendered = cfg.root_file_base.clone(); + let mut rendered = self.root_file_base.clone(); rendered.children.extend(root_sections); let root = File::new("cfg.md", rendered); - let child_files = self.root.children.iter().map(|section| { - let rendered = section.render(); + let child_files = doc.root.children.iter().map(|type_doc| { + let rendered = self.type_doc_node(type_doc); - let key = §ion.data.key; + let key = &type_doc.inner.key; File::new(format!("{key}/cfg.md"), rendered) }); - let type_index_sections = self.type_index.values().map(Section::render).collect(); + let type_index_sections = doc + .type_index + .values() + .map(|type_doc| self.type_doc_node(type_doc)) + .collect(); let type_index = RenderedSection { header: "Type Index".to_owned(), @@ -57,42 +49,18 @@ impl Doc { itertools::chain([root, type_index], child_files).collect() } -} - -impl RenderedSection { - pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { - Self { - header: header.into(), - body: body.into(), - children: vec![], - } - } - /// Render the section as markdown with the headers starting at the given level - fn to_markdown(&self, level: usize) -> String { - let header = self.header.clone(); - let sharps = "#".repeat(level); - let header = format!("{sharps} {header}"); - let body = self.body.clone(); - - let children = self - .children - .iter() - .map(|child| child.to_markdown(level + 1)); - - itertools::chain([header, body], children).join("\n\n") - } -} - -impl Section { - fn render(&self) -> RenderedSection { + fn type_doc_node(&self, type_doc: &TypeDocNode) -> RenderedSection { let children = [ - self.data.enum_doc(), - self.data.default(), - self.data.examples(), + self.enum_doc(&type_doc.inner.ty.inner), + self.default(&type_doc.inner), + self.examples(&type_doc.inner), ]; - let child_schemas = self.children.iter().map(Section::render); + let child_schemas = type_doc + .children + .iter() + .map(|type_doc| self.type_doc_node(type_doc)); let children = children .into_iter() @@ -100,50 +68,49 @@ impl Section { .chain(child_schemas) .collect(); - let header = self.data.header(); + let header = self.type_doc_header(&type_doc.inner); RenderedSection { header, - body: self.data.render_body(), + body: self.type_doc_body(&type_doc.inner), children, } } -} -impl SectionData { - fn header(&self) -> String { - if let SchemaKeyOrigin::Definition(def) = &self.key.root { + fn type_doc_header(&self, type_doc: &TypeDoc) -> String { + if let SchemaKeyOrigin::Definition(def) = &type_doc.key.root { return format!("`{def}`"); } - let last_segment = self.key.segments.last().unwrap_or_else(|| { + let last_segment = type_doc.key.segments.last().unwrap_or_else(|| { panic!( "Last segment must always be present in a key with the origin \ in root schema, but got empty key segments list: {:#?}", - self.key + type_doc.key ) }); - match last_segment { - SchemaKeySegment::Field(_) => format!("`{}`", self.key), - SchemaKeySegment::Index => "Items".to_owned(), - SchemaKeySegment::Variant(variant_name) => format!("Variant: `{variant_name}`"), + match &last_segment.kind { + SchemaKeySegmentKind::Field(_) => format!("`{}`", type_doc.key), + SchemaKeySegmentKind::Index => "Array item".to_owned(), + SchemaKeySegmentKind::Variant(variant_name) => format!("Variant: `{variant_name}`"), } } - fn render_body(&self) -> String { - let top = [&self.type_info(), &self.format(), &self.field_requirement()]; - - let top = top.into_iter().flatten().join("
\n"); + fn type_doc_body(&self, type_doc: &TypeDoc) -> String { + let top = [ + &self.tag_for_type(type_doc), + &self.tag_for_required(type_doc), + ]; - let parts = [&Some(top), &self.title, &self.description]; + let top = top.iter().copied().flatten().join("
\n"); - let body = parts.into_iter().flatten().join("\n\n"); + let parts = [&Some(top), &type_doc.title, &type_doc.description]; - body + parts.iter().copied().flatten().join("\n\n") } - fn field_requirement(&self) -> Option { - let SchemaKeySegment::Field(field) = self.key.segments.last()? else { + fn tag_for_required(&self, type_doc: &TypeDoc) -> Option { + let SchemaKeySegmentKind::Field(field) = &type_doc.key.segments.last()?.kind else { return None; }; @@ -154,26 +121,16 @@ impl SectionData { Some(format!("**Required:** `{requirement}`")) } - fn format(&self) -> Option { - let format = self - .format - .as_ref() - .or_else(|| self.type_index_ref.as_ref()?.format.as_ref())?; - - Some(format!("**Format:** `{format}`")) - } - - fn type_info(&self) -> Option { - let ty_ref = self.type_index_ref.as_ref().map(|ty_ref| { + fn tag_for_type(&self, type_doc: &TypeDoc) -> Option { + let ty_ref = type_doc.type_index_ref.as_ref().map(|ty_ref| { let definition = &ty_ref.definition; let anchor = definition.to_lowercase(); format!("[`{definition}`](/checks2/type-index.html#{anchor})") }); let ty = self - .ty - .as_ref() - .or_else(|| self.type_index_ref.as_ref()?.ty.as_ref()); + .ty(&type_doc.ty) + .or_else(|| self.ty(&type_doc.type_index_ref.as_ref()?.ty)); let ty = if ty_ref.is_some() { ty.map(|ty| format!("`({ty})`")) @@ -190,31 +147,61 @@ impl SectionData { Some(format!("**Type:** {parts}")) } - fn default(&self) -> Option { - self.default + fn leaf_type(&self, ty: &LeafType) -> Option { + let supplementary: Vec<_> = [ + ty.format.as_deref(), + ty.enum_schema.is_some().then_some("enum"), + ] + .into_iter() + .flatten() + .collect(); + + let rendered = match (&ty.ty, supplementary.as_slice()) { + (Some(ty), &[]) => ty.clone(), + (Some(ty), _) => format!("{ty} ({})", supplementary.join(", ")), + (None, &[]) => return None, + (None, &[first]) => first.to_owned(), + (None, &[first, ref rest @ ..]) => format!("{first} ({})", rest.iter().format(", ")), + }; + Some(rendered) + } + + fn ty(&self, ty: &Type) -> Option { + let array_suffix = ty + .array_items_ty .as_ref() - .map(|value| self.value_showcase("Default", value)) + .and_then(|items| self.leaf_type(items)) + .map(|items_ty| format!("<{items_ty}>")); + + let ty = self.leaf_type(&ty.inner)?; + + Some([Some(ty), array_suffix].into_iter().flatten().collect()) + } + + fn default(&self, type_doc: &TypeDoc) -> Option { + let value = type_doc.default.as_ref()?; + Some(self.value_showcase(type_doc, "Default", value)) } - fn value_showcase(&self, header: &str, value: &Value) -> RenderedSection { - let toml = self.key.render_value(value); + fn value_showcase(&self, type_doc: &TypeDoc, header: &str, value: &Value) -> RenderedSection { + let toml = self.value(&type_doc.key, value); RenderedSection::leaf(header, toml) } - fn examples(&self) -> Option { - match self.examples.as_slice() { + fn examples(&self, type_doc: &TypeDoc) -> Option { + match type_doc.examples.as_slice() { [] => return None, - [example] => return Some(self.value_showcase("Example", example)), + [example] => return Some(self.value_showcase(type_doc, "Example", example)), _ => {} }; - let examples = self + let examples = type_doc .examples .iter() .map(|value| { // Properly indent the example to fit into the markdown // list syntax - let example = self.key.render_value(value); + let example = self.value(&type_doc.key, value); let example = example .lines() .enumerate() @@ -233,8 +220,8 @@ impl SectionData { Some(RenderedSection::leaf("Examples", examples)) } - fn enum_doc(&self) -> Option { - let doc = self + fn enum_doc(&self, ty: &LeafType) -> Option { + let doc = ty .enum_schema .as_ref()? .iter() @@ -249,29 +236,27 @@ impl SectionData { Some(RenderedSection::leaf("Possible values", doc)) } -} -impl SchemaKey { - fn render_value(&self, value: &Value) -> String { + fn value(&self, key: &SchemaKey, value: &Value) -> String { fn wrap(key: &[SchemaKeySegment], value: Value) -> Value { let Some((first, rest)) = key.split_first() else { return value; }; - match first { - SchemaKeySegment::Field(_) => { + match &first.kind { + SchemaKeySegmentKind::Field(_) => { json!({ first.to_string(): wrap(rest, value) }) } - SchemaKeySegment::Index => { + SchemaKeySegmentKind::Index => { json!([wrap(rest, value)]) } // We use untagged one-of representations, so there is nothing // to wrap here - SchemaKeySegment::Variant(_) => value, + SchemaKeySegmentKind::Variant(_) => value, } } - let mut value = wrap(&self.segments, value.clone()); + let mut value = wrap(&key.segments, value.clone()); let is_primitive = !value.is_object() && !value.is_array(); @@ -296,6 +281,43 @@ impl SchemaKey { } } +#[derive(Clone, Debug)] +pub(crate) struct RenderedSection { + header: String, + body: String, + children: Vec, +} + +impl RenderedSection { + pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { + Self { + header: header.into(), + body: body.into(), + children: vec![], + } + } + + /// Render the type_doc as markdown with the headers starting at the given level + fn to_markdown(&self, level: usize) -> String { + let header = self.header.clone(); + let sharps = "#".repeat(level); + let header = format!("{sharps} {header}"); + let body = self.body.clone(); + + let children = self + .children + .iter() + .map(|child| child.to_markdown(level + 1)); + + itertools::chain([header, body], children).join("\n\n") + } +} + +pub(crate) struct File { + path: Utf8PathBuf, + rendered: RenderedSection, +} + impl File { fn new(path: impl Into, rendered: RenderedSection) -> Self { Self { From f7abf89073270051534f87686c29eb6e9d9a93a7 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Tue, 16 Apr 2024 00:11:50 +0000 Subject: [PATCH 11/20] Nested files approach --- Cargo.lock | 16 + deny.schema.json | 2 +- xtask/Cargo.toml | 2 + xtask/src/cli/codegen.rs | 4 +- xtask/src/cli/codegen/json_schema.rs | 2 +- xtask/src/cli/codegen/md_doc/dom.rs | 180 +++++ xtask/src/cli/codegen/md_doc/mod.rs | 643 ++++++------------ xtask/src/cli/codegen/md_doc/rendering.rs | 326 +++++---- xtask/src/cli/codegen/{input.rs => source.rs} | 26 +- 9 files changed, 641 insertions(+), 560 deletions(-) create mode 100644 xtask/src/cli/codegen/md_doc/dom.rs rename xtask/src/cli/codegen/{input.rs => source.rs} (93%) diff --git a/Cargo.lock b/Cargo.lock index 5042ca47..5f27288b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1809,6 +1809,15 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "markdown" +version = "1.0.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0f0025e8c0d89b84d6dc63e859475e40e8e82ab1a08be0a93ad5731513a508" +dependencies = [ + "unicode-id", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2988,6 +2997,12 @@ version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" +[[package]] +name = "unicode-id" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -3367,6 +3382,7 @@ dependencies = [ "clap", "indexmap", "itertools", + "markdown", "serde", "serde_json", "serde_yaml", diff --git a/deny.schema.json b/deny.schema.json index 635ff281..02d89f44 100644 --- a/deny.schema.json +++ b/deny.schema.json @@ -339,7 +339,7 @@ }, "PackageSpec": { "type": "string", - "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" + "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" },\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" }, "Target": { "oneOf": [ diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 910c62f8..61598941 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -19,6 +19,8 @@ itertools = "0.12" # Map that preserves the order of fields indexmap = { version = "2.0", features = ["serde"] } +markdown = "1.0.0-alpha.16" + # The coolest serialization framework in the world serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/xtask/src/cli/codegen.rs b/xtask/src/cli/codegen.rs index 25f3df18..cca2b5c7 100644 --- a/xtask/src/cli/codegen.rs +++ b/xtask/src/cli/codegen.rs @@ -1,4 +1,4 @@ -mod input; +mod source; mod json_schema; mod md_doc; @@ -14,7 +14,7 @@ impl CodegenCommand { let Self {} = self; let input = fs::read_to_string("deny.schema.yml")?; - let input: input::RootSchema = serde_yaml::from_str(&input)?; + let input: source::RootSchema = serde_yaml::from_str(&input)?; md_doc::gen(&input)?; json_schema::gen(&input)?; diff --git a/xtask/src/cli/codegen/json_schema.rs b/xtask/src/cli/codegen/json_schema.rs index c6b05a27..b60e3939 100644 --- a/xtask/src/cli/codegen/json_schema.rs +++ b/xtask/src/cli/codegen/json_schema.rs @@ -1,4 +1,4 @@ -use super::input::{EnumVariantSchema, RootSchema, Schema}; +use super::source::{EnumVariantSchema, RootSchema, Schema}; use anyhow::Result; /// Generate the JSON schema based on the input YML schema. diff --git a/xtask/src/cli/codegen/md_doc/dom.rs b/xtask/src/cli/codegen/md_doc/dom.rs new file mode 100644 index 00000000..170be5a3 --- /dev/null +++ b/xtask/src/cli/codegen/md_doc/dom.rs @@ -0,0 +1,180 @@ +use crate::cli::codegen::source; +use anyhow::Result; +use serde_json::Value; +use std::fmt; + +#[derive(Debug)] +pub(crate) struct SchemaNode { + pub(crate) schema: Schema, + pub(crate) children: Vec, +} + +impl SchemaNode { + pub(crate) fn leaf(schema: Schema) -> Self { + Self { + schema, + children: vec![], + } + } +} + +#[derive(Debug)] +pub(crate) struct Schema { + pub(crate) path: Path, + pub(crate) ty: Type, + pub(crate) doc: SchemaDoc, +} + +#[derive(Debug)] +pub(crate) enum SchemaDoc { + /// Documentation should be embedded in the same file. The value is [`None`] + Embedded(SchemaDocData), + + /// Schema should live as a nested document + Nested(SchemaDocData), + + /// This schema is a reference to some other schema. It may be either a reference + /// to a definition within the same schema or a reference to some external schema. + Ref(String), +} + +#[derive(Debug)] +pub(crate) struct SchemaDocData { + pub(crate) title: Option, + pub(crate) description: Option, + pub(crate) default: Option, + pub(crate) examples: Vec, +} + +#[derive(Clone, Debug)] +pub(crate) struct Path { + pub(crate) origin: PathOrigin, + pub(crate) segments: Vec, +} + +impl Path { + pub(crate) fn new(origin: PathOrigin) -> Self { + Self { + origin, + segments: vec![], + } + } + + #[must_use] + pub(crate) fn add_segment(&self, new_segment: PathSegment) -> Self { + let mut segments = self.segments.clone(); + segments.push(new_segment); + Self { + origin: self.origin.clone(), + segments, + } + } +} + +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut segments = self.segments.iter(); + + if let Some(segment) = segments.next() { + write!(f, "{segment}")?; + } + + segments.try_for_each(|segment| match &segment { + PathSegment::Field(_) => write!(f, ".{segment}"), + PathSegment::Index => write!(f, " array item"), + PathSegment::Variant(_) => write!(f, " as {segment}"), + }) + } +} + +#[derive(Clone, Debug)] +pub(crate) enum PathOrigin { + Root, + Definition(String), +} + +impl fmt::Display for PathSegment { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + PathSegment::Field(field) => f.write_str(&field.name), + PathSegment::Index => f.write_str("n"), + PathSegment::Variant(name) => f.write_str(name), + } + } +} + +#[derive(Clone, Debug)] +pub(crate) enum PathSegment { + Field(Field), + Index, + Variant(String), +} + +#[derive(Clone, Debug)] +pub(crate) struct Field { + pub(crate) name: String, + pub(crate) required: bool, +} + +#[derive(Debug, Clone)] +pub(crate) struct LeafType { + pub(crate) ty: Option, + pub(crate) format: Option, + pub(crate) enum_schema: Option>, +} + +impl LeafType { + fn from_source_schema(schema: &source::Schema) -> Self { + Self { + ty: schema.ty.clone(), + format: schema.format.clone(), + enum_schema: schema.enum_schema.clone(), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct Type { + pub(crate) inner: LeafType, + + /// [`LeafType`] exists to make sure we don't have recursion in this field. + /// We describe at max two levels of nesting in type tags. + pub(crate) array_items_ty: Option, +} + +impl Type { + pub(crate) fn from_source_schema(schema: &source::Schema) -> Self { + let inner = LeafType::from_source_schema(schema); + + let array_items_ty = schema + .array_schema + .as_ref() + .map(|array| LeafType::from_source_schema(&array.items)); + + Self { + inner, + array_items_ty, + } + } +} + +#[derive(Clone, Debug)] +pub(crate) struct PathedSourceSchema { + pub(crate) path: Path, + pub(crate) inner: source::Schema, +} + +impl PathedSourceSchema { + pub(crate) fn new(path: Path, inner: source::Schema) -> Self { + Self { path, inner } + } + + pub(crate) fn origin(origin: PathOrigin, inner: source::Schema) -> Self { + Self::new(Path::new(origin), inner) + } + + fn inline_referenced_definition(mut self, root: &source::RootSchema) -> Result { + self.inner = root.inline_referenced_definition(&self.inner)?; + Ok(self) + } +} diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/xtask/src/cli/codegen/md_doc/mod.rs index 9d8e5d5f..b3a072af 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -1,409 +1,273 @@ +mod dom; mod rendering; -use self::rendering::{RenderedSection, Renderer}; -use crate::cli::codegen::input::{EnumVariantSchema, RootSchema, Schema}; -use anyhow::{Context, Result}; +use self::dom::*; +use self::rendering::*; + +use super::source::{ArraySchema, ObjectSchema, OneOfVariantSchema}; +use crate::cli::codegen::source; +use anyhow::Result; use itertools::Itertools; -use serde_json::Value; use std::collections::BTreeMap; -use std::fmt; -struct DocOptions<'a> { - root: &'a RootSchema, - max_level: usize, +struct DocOptions { + root: source::RootSchema, + max_nesting_in_file: usize, } pub(crate) struct Doc { - root: TypeDocNode, - type_index: BTreeMap, -} - -#[derive(Debug)] -struct TypeDoc { - key: SchemaKey, - title: Option, - description: Option, - default: Option, - examples: Vec, - ty: Type, - type_index_ref: Option, -} - -#[derive(Debug)] -struct TypeIndexRef { - definition: String, - ty: Type, -} - -#[derive(Debug, Clone)] -struct LeafType { - ty: Option, - format: Option, - enum_schema: Option>, -} - -impl LeafType { - fn from_schema(schema: &Schema) -> Self { - Self { - ty: schema.ty.clone(), - format: schema.format.clone(), - enum_schema: schema.enum_schema.clone(), - } - } -} - -#[derive(Debug, Clone)] -struct Type { - inner: LeafType, - - /// [`LeafType`] exists to make sure we don't have recursion in this field. - /// We describe at max two levels of nesting in type tags. - array_items_ty: Option, -} - -impl Type { - fn from_schema(schema: &Schema) -> Self { - let inner = LeafType::from_schema(schema); - - let array_items_ty = schema - .array_schema - .as_ref() - .map(|array| LeafType::from_schema(&array.items)); - - Self { - inner, - array_items_ty, - } - } -} - -#[derive(Debug)] -struct TypeDocNode { - inner: TypeDoc, - children: Vec, -} - -struct CreateDoc<'a> { - options: &'a DocOptions<'a>, - type_index: &'a BTreeMap, -} - -#[derive(Clone, Debug)] -struct KeyedSchema { - key: SchemaKey, - inner: Schema, -} - -#[derive(Clone, Debug)] -struct SchemaKey { - root: SchemaKeyOrigin, - segments: Vec, -} - -impl SchemaKey { - fn push_inline_segment(&self, new_segment: SchemaKeySegmentKind) -> Self { - let mut segments = self.segments.clone(); - segments.push(SchemaKeySegment::inline(new_segment)); - Self { - root: self.root.clone(), - segments, - } - } - - fn definition(&self) -> Option<&str> { - self.segments.last()?.definition.as_deref() - } + root: SchemaNode, + type_index: BTreeMap, } -impl fmt::Display for SchemaKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut segments = self.segments.iter(); - - if let Some(segment) = segments.next() { - write!(f, "{segment}")?; - } - - segments.try_for_each(|segment| match &segment.kind { - SchemaKeySegmentKind::Field(_) => write!(f, ".{segment}"), - SchemaKeySegmentKind::Index => write!(f, " array item"), - SchemaKeySegmentKind::Variant(_) => write!(f, " as {segment}"), - }) - } -} - -#[derive(Clone, Debug)] -enum SchemaKeyOrigin { - Root, - Definition(String), +struct GenerateDoc { + options: DocOptions, } -#[derive(Clone, Debug)] -struct SchemaKeySegment { - kind: SchemaKeySegmentKind, - - /// If this part of the key is a reference to a definition, then this field - /// stores the name of that definition. - definition: Option, -} +impl Doc { + fn new(options: DocOptions) -> Result { + // let all_schemas = || { + // let schemas_in_root = root.schema.entries(); + // let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); + // itertools::chain(schemas_in_root, schemas_in_defs) + // }; + + // let definition_ref_counts = all_schemas() + // .map(|entry| entry.schema.referenced_definition()) + // .flatten_ok() + // .process_results(|iter| iter.counts())?; + + // let unused_defs: Vec<_> = root + // .definitions + // .iter() + // .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) + // .collect(); + + // anyhow::ensure!( + // unused_defs.is_empty(), + // "Found unused definitions: {unused_defs:#?}", + // ); + + // let repeated_references: BTreeMap<_, _> = definition_ref_counts + // .into_iter() + // // For schemas that are repeatedly referenced, we want to include them in the + // // "Type Index". This is separate page where common types are defined such + // // that we don't duplicate their docs all over the place. + // .filter(|(_, count)| *count > 1) + // .map(|(def_name, _)| { + // let schema = root.find_definition(def_name)?; + // anyhow::Ok((def_name.to_owned(), schema)) + // }) + // .try_collect()?; + + // let flattened = all_schemas() + // .filter(|entry| entry.level % max_level == 0) + // .map(|entry| { + // let schema = entry.schema; + // }) + // .collect(); + + let doc = GenerateDoc { options }.run()?; + + // doc.flatten(max_level)?; -impl SchemaKeySegment { - fn inline(kind: SchemaKeySegmentKind) -> Self { - Self { - definition: None, - kind, - } + Ok(doc) } -} - -#[derive(Clone, Debug)] -enum SchemaKeySegmentKind { - Field(SchemaKeySegmentField), - Index, - Variant(String), -} -#[derive(Clone, Debug)] -struct SchemaKeySegmentField { - name: String, - required: bool, + // fn flatten(&mut self, max_level: usize) -> Result<()> { + // FlattenDoc { + // ty_index: &mut self.type_index, + // max_level, + // } + // .flatten(&mut self.root, 0) + // } } -impl Doc { - fn new(options: DocOptions<'_>) -> Result { - let DocOptions { root, max_level } = options; - - let all_schemas = || { - let schemas_in_root = root.schema.entries(); - let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); - itertools::chain(schemas_in_root, schemas_in_defs) - }; - - let definition_ref_counts = all_schemas() - .map(|entry| entry.schema.referenced_definition()) - .flatten_ok() - .process_results(|iter| iter.counts())?; - - let unused_defs: Vec<_> = root +// struct FlattenDoc<'a> { +// ty_index: &'a mut BTreeMap, +// max_level: usize, +// } + +// impl FlattenDoc<'_> { +// fn flatten(&mut self, node: &mut TypeDocNode, level: usize) -> Result<()> { +// for child in &mut node.children { +// if level <= self.max_level { +// Self { +// ty_index: self.ty_index, +// max_level: self.max_level, +// } +// } + +// self.flatten(child, level + 1)?; +// } + +// if level <= self.max_level { +// return Ok(()); +// } + +// node.children.clear(); + +// let type_doc = &node.inner; + +// let definition = type_doc +// .key +// .definition() +// .with_context(|| { +// format!( +// "Can't flatten node at level {level}, because the name to \ +// assign to it in the type index can not be inferred.\n\ +// Schema key: {}\n\ +// Try moving the schema to a definition, and the definition key \ +// will be used as a name for this type in the type index", +// type_doc.key +// ) +// })? +// .to_owned(); + +// let type_index_entry = self.ty_index.get(&definition).unwrap_or_else(|| { +// panic!("We inlined this type before, so it must be in type index: {definition}") +// }); + +// let type_index_ref = TypeIndexRef { +// definition: definition.clone(), +// ty: type_index_entry.inner.ty.clone(), +// }; + +// let new_type_doc = TypeDoc { +// key: type_doc.key.clone(), +// title: None, +// description: None, +// default: None, +// examples: vec![], +// ty: type_doc.ty.clone(), +// type_index_ref: Some(type_index_ref), +// }; + +// let node = std::mem::replace(node, TypeDocNode::leaf(new_type_doc)); + +// self.ty_index.insert(definition, node); + +// Ok(()) +// } +// } + +impl GenerateDoc { + fn run(self) -> Result { + let root = PathedSourceSchema::origin(PathOrigin::Root, self.options.root.schema.clone()); + let root = self.schema_node(root)?; + + let definitions = self + .options + .root .definitions .iter() - .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) - .collect(); - - anyhow::ensure!( - unused_defs.is_empty(), - "Found unused definitions: {unused_defs:#?}", - ); - - let repeated_references: BTreeMap<_, _> = definition_ref_counts - .into_iter() - // For schemas that are repeatedly referenced, we want to include them in the - // "Type Index". This is separate page where common types are defined such - // that we don't duplicate their docs all over the place. - .filter(|(_, count)| *count > 1) - .map(|(def_name, _)| { - let schema = root.find_definition(def_name)?; - anyhow::Ok((def_name.to_owned(), schema)) - }) - .try_collect()?; - - let flattened = all_schemas() - .filter(|entry| entry.level % max_level == 0) - .map(|entry| { - let schema = entry.schema; + .map(|(def_name, schema)| { + let origin = PathOrigin::Definition(def_name.clone()); + let schema = PathedSourceSchema::origin(origin, schema.clone()); + Ok((def_name.clone(), self.schema_node(schema)?)) }) - .collect(); + .collect::>()?; - let ctx = CreateDoc { + Ok(Doc { root, - type_index: &repeated_references, - }; - - let mut doc = Self { - root: ctx.root_type_doc()?, - type_index: ctx.type_index_docs()?, - }; - - doc.flatten(max_level)?; - - Ok(doc) + type_index: definitions, + }) } - fn flatten(&mut self, max_level: usize) -> Result<()> { - FlattenDoc { - ty_index: &mut self.type_index, - max_level, + fn schema_node(&self, schema: PathedSourceSchema) -> Result { + if let Some(reference) = schema.inner.reference.clone() { + self.schema_node_ref(schema, reference) + } else { + self.schema_node_non_ref(schema) } - .flatten(&mut self.root, 0) } -} -struct FlattenDoc<'a> { - ty_index: &'a mut BTreeMap, - max_level: usize, -} + fn schema_node_ref(&self, schema: PathedSourceSchema, reference: String) -> Result { + let doc = SchemaDoc::Ref(reference); + let path = schema.path; -impl FlattenDoc<'_> { - fn flatten(&mut self, node: &mut TypeDocNode, level: usize) -> Result<()> { - for child in &mut node.children { - if level <= self.max_level { - Self { - ty_index: self.ty_index, - max_level: self.max_level, - } - } - - self.flatten(child, level + 1)?; - } + let inline = self + .options + .root + .inline_referenced_definition(&schema.inner)?; - if level <= self.max_level { - return Ok(()); - } - - node.children.clear(); - - let type_doc = &node.inner; - - let definition = type_doc - .key - .definition() - .with_context(|| { - format!( - "Can't flatten node at level {level}, because the name to \ - assign to it in the type index can not be inferred.\n\ - Schema key: {}\n\ - Try moving the schema to a definition, and the definition key \ - will be used as a name for this type in the type index", - type_doc.key - ) - })? - .to_owned(); - - let type_index_entry = self.ty_index.get(&definition).unwrap_or_else(|| { - panic!("We inlined this type before, so it must be in type index: {definition}") - }); - - let type_index_ref = TypeIndexRef { - definition: definition.clone(), - ty: type_index_entry.inner.ty.clone(), - }; - - let new_type_doc = TypeDoc { - key: type_doc.key.clone(), - title: None, - description: None, - default: None, - examples: vec![], - ty: type_doc.ty.clone(), - type_index_ref: Some(type_index_ref), - }; - - let node = std::mem::replace(node, TypeDocNode::leaf(new_type_doc)); + let ty = Type::from_source_schema(&inline); - self.ty_index.insert(definition, node); + let schema = Schema { path, ty, doc }; - Ok(()) + Ok(SchemaNode::leaf(schema)) } -} -impl CreateDoc<'_> { - fn root_type_doc(&self) -> Result { - let key = SchemaKey { - root: SchemaKeyOrigin::Root, - segments: vec![], - }; - let root_schema = KeyedSchema::new(key, self.root.schema.clone()); + fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { + let path = schema.path; + let ty = Type::from_source_schema(&schema.inner); - self.type_doc_node(root_schema) - } - - fn type_index_docs(&self) -> Result> { - self.type_index - .iter() - .map(|(def_name, &schema)| { - let key = SchemaKey { - root: SchemaKeyOrigin::Definition(def_name.clone()), - segments: vec![], - }; - let schema = KeyedSchema::new(key, schema.clone()); - - anyhow::Ok((def_name.clone(), self.type_doc_node(schema)?)) - }) - .collect() - } - - fn type_doc_node(&self, schema: KeyedSchema) -> Result { - let referenced_def = schema.inner.referenced_definition()?; + let schema = schema.inner; - // If this schema references a type from the type index, then avoid - // inlining the schema and finish the type doc early. - if referenced_def.is_some_and(|def| self.type_index.contains_key(def)) { - return Ok(TypeDocNode::leaf(self.type_doc(schema.clone())?)); - } - - let schema = schema.inline_referenced_definition(self.root)?; - - let type_doc = self.type_doc(schema.clone())?; - - let children = if schema.inner.array_schema.is_some() { - Self::array_children(schema)? - } else if schema.inner.object_schema.is_some() { - Self::object_children(schema)? - } else if schema.inner.one_of.is_some() { - Self::one_of_children(schema)? + let children = if let Some(array) = schema.array_schema { + Self::array_children(&path, array)? + } else if let Some(object) = schema.object_schema { + Self::object_children(&path, object)? + } else if let Some(variants) = schema.one_of { + Self::one_of_children(&path, variants)? } else { vec![] }; let children = children .into_iter() - .map(|child| self.type_doc_node(child)) + .map(|child| self.schema_node(child)) .try_collect()?; - Ok(TypeDocNode { - inner: type_doc, - children, - }) - } + let data = SchemaDocData { + title: schema.title, + description: schema.description, + default: schema.default, + examples: schema.examples, + }; - fn array_children(schema: KeyedSchema) -> Result> { - let array = schema.inner.try_into_array()?; + let doc = if path.segments.len() % (self.options.max_nesting_in_file + 1) == 0 { + SchemaDoc::Nested(data) + } else { + SchemaDoc::Embedded(data) + }; - // Avoid adding useless documentation for item - if array.items.is_undocumented_primitive() { - return Ok(vec![]); - } + let schema = Schema { path, ty, doc }; + + Ok(SchemaNode { schema, children }) + } - let key = schema.key.push_inline_segment(SchemaKeySegmentKind::Index); - let items = KeyedSchema::new(key, *array.items); + fn array_children(path: &Path, array: ArraySchema) -> Result> { + let path = path.add_segment(PathSegment::Index); + let items = PathedSourceSchema::new(path, *array.items); Ok(vec![items]) } - fn object_children(schema: KeyedSchema) -> Result> { - let object = schema.inner.try_into_object()?; + fn object_children(path: &Path, object: ObjectSchema) -> Result> { let properties = object .properties .into_iter() - .map(|(key, value)| { - let key = SchemaKeySegmentField { - name: key.clone(), - required: object.required.contains(&key), + .map(|(name, value)| { + let field = Field { + name: name.clone(), + required: object.required.contains(&name), }; - - let key = schema - .key - .push_inline_segment(SchemaKeySegmentKind::Field(key)); - KeyedSchema::new(key, value) + let path = path.add_segment(PathSegment::Field(field)); + PathedSourceSchema::new(path, value) }) .collect(); Ok(properties) } - fn one_of_children(schema: KeyedSchema) -> Result> { - let variants = schema.inner.try_into_one_of()?; + fn one_of_children( + path: &Path, + variants: Vec, + ) -> Result> { let names: Vec<_> = variants - .iter() + .clone() + .into_iter() .map(|variant| variant.name().map(ToOwned::to_owned)) .try_collect()?; @@ -420,91 +284,17 @@ impl CreateDoc<'_> { .into_iter() .zip(names) .map(|(variant, name)| { - let key = schema - .key - .push_inline_segment(SchemaKeySegmentKind::Variant(name)); + let path = path.add_segment(PathSegment::Variant(name)); - KeyedSchema::new(key, variant.schema) + PathedSourceSchema::new(path, variant.schema) }) .collect(); Ok(variants) } - - fn type_index_ref(&self, schema: &Schema) -> Result> { - let ty_index_ref = schema.referenced_definition()?.and_then(|def_name| { - let ty = self - .type_index - .get(def_name) - .copied() - .map(Type::from_schema)?; - - Some(TypeIndexRef { - definition: def_name.to_owned(), - ty, - }) - }); - - Ok(ty_index_ref) - } - - fn type_doc(&self, schema: KeyedSchema) -> Result { - let type_index_ref = self.type_index_ref(&schema.inner)?; - let ty = Type::from_schema(&schema.inner); - - let base = TypeDoc { - key: schema.key, - title: schema.inner.title, - description: schema.inner.description, - default: schema.inner.default, - examples: schema.inner.examples, - ty, - type_index_ref, - }; - - Ok(base) - } -} - -impl TypeDocNode { - fn leaf(data: TypeDoc) -> Self { - Self { - inner: data, - children: vec![], - } - } -} - -impl fmt::Display for SchemaKeySegment { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.kind { - SchemaKeySegmentKind::Field(field) => f.write_str(&field.name), - SchemaKeySegmentKind::Index => f.write_str("n"), - SchemaKeySegmentKind::Variant(name) => f.write_str(name), - } - } -} - -impl KeyedSchema { - fn new(key: SchemaKey, inner: Schema) -> Self { - Self { key, inner } - } - - fn inline_referenced_definition(mut self, root: &RootSchema) -> Result { - if let Some(last_segment) = self.key.segments.last_mut() { - if let Some(definition) = self.inner.referenced_definition()? { - last_segment.definition = Some(definition.to_owned()); - } - } - - Ok(Self::new( - self.key, - root.inline_referenced_definition(&self.inner)?, - )) - } } -pub(crate) fn gen(root: &RootSchema) -> Result<()> { +pub(crate) fn gen(root: &source::RootSchema) -> Result<()> { let out_dir = "docs/src/checks2"; let header = "config"; @@ -518,10 +308,15 @@ The top level config for cargo-deny, by default called `deny.toml`. ```"; let renderer = Renderer { - root_file_base: RenderedSection::leaf(header, body), + root_file_base: Section::leaf(header, body), + }; + + let options = DocOptions { + root: root.clone(), + max_nesting_in_file: 2, }; - let files = renderer.doc(&Doc::new(root, 2)?); + let files = renderer.doc(&Doc::new(options)?); files.iter().try_for_each(|file| file.write(out_dir))?; diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs index 20dd775a..773e1e35 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -1,116 +1,195 @@ -use super::{Doc, LeafType, SchemaKey, SchemaKeySegmentKind, Type, TypeDoc, TypeDocNode}; -use crate::cli::codegen::md_doc::{SchemaKeyOrigin, SchemaKeySegment}; +use super::{ + Doc, LeafType, Path, PathOrigin, PathSegment, Schema, SchemaDoc, SchemaDocData, SchemaNode, + Type, +}; use anyhow::{Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; use serde_json::{json, Value}; +use std::collections::BTreeMap; pub(crate) struct Renderer { - pub(crate) root_file_base: RenderedSection, + pub(crate) root_file_base: Section, } impl Renderer { pub(crate) fn doc(&self, doc: &Doc) -> Vec { - let root_sections = doc.root.children.iter().map(|type_doc| { - let key = &type_doc.inner.key; - let header = format!("The `[{key}]` type_doc"); - let body = format!("See [{key} config]({key}/cfg.html) for more info."); - let body = itertools::chain(&type_doc.inner.title, [&body]).join("\n\n"); + // let root_sections = doc.root.children.iter().map(|schema| { + // let key = &schema.doc.path; + // let header = format!("`[{key}]`"); + // let body = format!("See [{key} config]({key}/cfg.html) for more info."); + // let body = itertools::chain(&schema.doc.title, [&body]).join("\n\n"); - RenderedSection::leaf(header, body) - }); + // RenderedSection::leaf(header, body) + // }); - let mut rendered = self.root_file_base.clone(); - rendered.children.extend(root_sections); + // let mut rendered = self.root_file_base.clone(); + // rendered.children.extend(root_sections); - let root = File::new("cfg.md", rendered); + // let root = File::new("cfg.md", rendered); - let child_files = doc.root.children.iter().map(|type_doc| { - let rendered = self.type_doc_node(type_doc); + // let child_files = doc.root.children.iter().map(|schema| { + // let rendered = self.schema_node(schema); - let key = &type_doc.inner.key; + // let key = &schema.doc.path; - File::new(format!("{key}/cfg.md"), rendered) - }); + // File::new(format!("{key}/cfg.md"), rendered) + // }); + + let root = NamedDocument { + name: "root".to_owned(), + document: Document { + section: self.root_file_base.clone(), + children: vec![NamedDocument { + name: "schema".to_owned(), + document: self.schema_node(&doc.root), + }], + }, + }; + + let type_index = self.type_index(&doc.type_index); + + itertools::chain([root], type_index) + .flat_map(NamedDocument::into_files) + .collect() + } + + fn type_index(&self, type_index: &BTreeMap) -> Option { + if type_index.is_empty() { + return None; + } - let type_index_sections = doc - .type_index - .values() - .map(|type_doc| self.type_doc_node(type_doc)) + let children = type_index + .iter() + .map(|(name, schema)| NamedDocument { + name: name.clone(), + document: self.schema_node(schema), + }) .collect(); - let type_index = RenderedSection { - header: "Type Index".to_owned(), - body: "This is an index of common types used across the schema.".to_owned(), - children: type_index_sections, + let section = Section::leaf( + "Type Index", + "This is an index of common types used across the schema.", + ); + + let document = Document { section, children }; + + Some(NamedDocument { + name: "type-index".to_owned(), + document, + }) + } + + fn schema_node(&self, node: &SchemaNode) -> Document { + match &node.schema.doc { + SchemaDoc::Embedded(doc) => self.schema_embedded(&node, doc), + SchemaDoc::Nested(doc) => self.schema_embedded(&node, doc), + SchemaDoc::Ref(reference) => self.schema_ref(&node, reference), + } + } + + fn schema_ref(&self, node: &SchemaNode, reference: &str) -> Document { + let (ref_name, url) = reference + .strip_prefix("#/definitions/") + .map(|definition| { + let anchor = definition.to_lowercase(); + (definition, format!("/checks2/type-index.html#{anchor})")) + }) + .unwrap_or_else(|| ("{ExternalSchema}", reference.to_owned())); + + let section = self.type_reference(&node.schema, ref_name, &url); + + Document::leaf(section) + } + + fn type_reference(&self, schema: &Schema, ref_name: &str, url: &str) -> Section { + let reference = format!("[`{ref_name}`]({url})"); + + let ty = self + .ty(&schema.ty) + .map(|ty| format!(" `{ty}`")) + .unwrap_or_default(); + + let body = format!("**Type:**: {reference}{ty}"); + + Section::leaf(self.section_header(schema), body) + } + + fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { + let document = self.schema_embedded(node, doc); + + let name = node.schema.path.segments.last().unwrap().to_string(); + + let nested = NamedDocument { + name: name.clone(), + document, }; - let type_index = File::new("type-index.md", type_index); + let url = format!("./{name}.md"); + let section = self.type_reference(&node.schema, "Nested", &url); - itertools::chain([root, type_index], child_files).collect() + Document { + section, + children: vec![nested], + } } - fn type_doc_node(&self, type_doc: &TypeDocNode) -> RenderedSection { + fn schema_embedded(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { let children = [ - self.enum_doc(&type_doc.inner.ty.inner), - self.default(&type_doc.inner), - self.examples(&type_doc.inner), + self.enum_doc(&node.schema.ty.inner), + self.default(&node.schema.path, &doc), + self.examples(&node.schema.path, &doc), ]; + let child_schemas = node.children.iter().map(|schema| self.schema_node(schema)); - let child_schemas = type_doc - .children - .iter() - .map(|type_doc| self.type_doc_node(type_doc)); - - let children = children + let (child_sections, child_docs): (Vec<_>, Vec<_>) = children .into_iter() .flatten() + .map(Document::leaf) .chain(child_schemas) - .collect(); + .map(|doc| (doc.section, doc.children)) + .unzip(); - let header = self.type_doc_header(&type_doc.inner); + let header = self.section_header(&node.schema); - RenderedSection { + let section = Section { header, - body: self.type_doc_body(&type_doc.inner), - children, + body: self.section_body(&node.schema, &doc), + children: child_sections, + }; + Document { + section, + children: itertools::concat(child_docs), } } - fn type_doc_header(&self, type_doc: &TypeDoc) -> String { - if let SchemaKeyOrigin::Definition(def) = &type_doc.key.root { + fn section_header(&self, schema: &Schema) -> String { + if let PathOrigin::Definition(def) = &schema.path.origin { return format!("`{def}`"); } - let last_segment = type_doc.key.segments.last().unwrap_or_else(|| { - panic!( - "Last segment must always be present in a key with the origin \ - in root schema, but got empty key segments list: {:#?}", - type_doc.key - ) - }); + let Some(last_segment) = schema.path.segments.last() else { + return "Schema".to_owned(); + }; - match &last_segment.kind { - SchemaKeySegmentKind::Field(_) => format!("`{}`", type_doc.key), - SchemaKeySegmentKind::Index => "Array item".to_owned(), - SchemaKeySegmentKind::Variant(variant_name) => format!("Variant: `{variant_name}`"), + match &last_segment { + PathSegment::Field(_) => format!("`{}`", schema.path), + PathSegment::Index => "Array item".to_owned(), + PathSegment::Variant(variant_name) => format!("Variant: `{variant_name}`"), } } - fn type_doc_body(&self, type_doc: &TypeDoc) -> String { - let top = [ - &self.tag_for_type(type_doc), - &self.tag_for_required(type_doc), - ]; + fn section_body(&self, schema: &Schema, doc: &SchemaDocData) -> String { + let top = [self.tag_for_type(&schema.ty), self.tag_for_required(schema)]; - let top = top.iter().copied().flatten().join("
\n"); + let top = top.iter().flatten().join("
\n"); - let parts = [&Some(top), &type_doc.title, &type_doc.description]; + let parts = [&Some(top), &doc.title, &doc.description]; parts.iter().copied().flatten().join("\n\n") } - fn tag_for_required(&self, type_doc: &TypeDoc) -> Option { - let SchemaKeySegmentKind::Field(field) = &type_doc.key.segments.last()?.kind else { + fn tag_for_required(&self, schema: &Schema) -> Option { + let PathSegment::Field(field) = &schema.path.segments.last()? else { return None; }; @@ -121,30 +200,9 @@ impl Renderer { Some(format!("**Required:** `{requirement}`")) } - fn tag_for_type(&self, type_doc: &TypeDoc) -> Option { - let ty_ref = type_doc.type_index_ref.as_ref().map(|ty_ref| { - let definition = &ty_ref.definition; - let anchor = definition.to_lowercase(); - format!("[`{definition}`](/checks2/type-index.html#{anchor})") - }); - - let ty = self - .ty(&type_doc.ty) - .or_else(|| self.ty(&type_doc.type_index_ref.as_ref()?.ty)); - - let ty = if ty_ref.is_some() { - ty.map(|ty| format!("`({ty})`")) - } else { - ty.map(|ty| format!("`{ty}`")) - }; - - let parts = [ty_ref, ty].iter().flatten().join(" "); - - if parts.is_empty() { - return None; - } - - Some(format!("**Type:** {parts}")) + fn tag_for_type(&self, ty: &Type) -> Option { + let ty = self.ty(&ty)?; + Some(format!("**Type:** `{ty}`")) } fn leaf_type(&self, ty: &LeafType) -> Option { @@ -178,30 +236,30 @@ impl Renderer { Some([Some(ty), array_suffix].into_iter().flatten().collect()) } - fn default(&self, type_doc: &TypeDoc) -> Option { - let value = type_doc.default.as_ref()?; - Some(self.value_showcase(type_doc, "Default", value)) + fn default(&self, path: &Path, doc: &SchemaDocData) -> Option
{ + let value = doc.default.as_ref()?; + Some(self.value_showcase(path, "Default", value)) } - fn value_showcase(&self, type_doc: &TypeDoc, header: &str, value: &Value) -> RenderedSection { - let toml = self.value(&type_doc.key, value); - RenderedSection::leaf(header, toml) + fn value_showcase(&self, path: &Path, header: &str, value: &Value) -> Section { + let toml = self.value(path, value); + Section::leaf(header, toml) } - fn examples(&self, type_doc: &TypeDoc) -> Option { - match type_doc.examples.as_slice() { + fn examples(&self, path: &Path, doc: &SchemaDocData) -> Option
{ + match doc.examples.as_slice() { [] => return None, - [example] => return Some(self.value_showcase(type_doc, "Example", example)), + [example] => return Some(self.value_showcase(path, "Example", example)), _ => {} }; - let examples = type_doc + let examples = doc .examples .iter() .map(|value| { // Properly indent the example to fit into the markdown // list syntax - let example = self.value(&type_doc.key, value); + let example = self.value(path, value); let example = example .lines() .enumerate() @@ -217,10 +275,10 @@ impl Renderer { }) .join("\n"); - Some(RenderedSection::leaf("Examples", examples)) + Some(Section::leaf("Examples", examples)) } - fn enum_doc(&self, ty: &LeafType) -> Option { + fn enum_doc(&self, ty: &LeafType) -> Option
{ let doc = ty .enum_schema .as_ref()? @@ -234,25 +292,25 @@ impl Renderer { }) .join("\n\n"); - Some(RenderedSection::leaf("Possible values", doc)) + Some(Section::leaf("Possible values", doc)) } - fn value(&self, key: &SchemaKey, value: &Value) -> String { - fn wrap(key: &[SchemaKeySegment], value: Value) -> Value { + fn value(&self, key: &Path, value: &Value) -> String { + fn wrap(key: &[PathSegment], value: Value) -> Value { let Some((first, rest)) = key.split_first() else { return value; }; - match &first.kind { - SchemaKeySegmentKind::Field(_) => { + match &first { + PathSegment::Field(_) => { json!({ first.to_string(): wrap(rest, value) }) } - SchemaKeySegmentKind::Index => { + PathSegment::Index => { json!([wrap(rest, value)]) } // We use untagged one-of representations, so there is nothing // to wrap here - SchemaKeySegmentKind::Variant(_) => value, + PathSegment::Variant(_) => value, } } @@ -282,13 +340,13 @@ impl Renderer { } #[derive(Clone, Debug)] -pub(crate) struct RenderedSection { +pub(crate) struct Section { header: String, body: String, - children: Vec, + children: Vec
, } -impl RenderedSection { +impl Section { pub(crate) fn leaf(header: impl Into, body: impl Into) -> Self { Self { header: header.into(), @@ -297,7 +355,7 @@ impl RenderedSection { } } - /// Render the type_doc as markdown with the headers starting at the given level + /// Render the schema as markdown with the headers starting at the given level fn to_markdown(&self, level: usize) -> String { let header = self.header.clone(); let sharps = "#".repeat(level); @@ -313,13 +371,51 @@ impl RenderedSection { } } +struct NamedDocument { + name: String, + document: Document, +} + +impl NamedDocument { + fn into_files(self) -> Vec { + let mut files = vec![]; + let path = Utf8PathBuf::new(); + self.into_files_imp(path, &mut files); + files + } + + fn into_files_imp(self, path: Utf8PathBuf, files: &mut Vec) { + let file_name = format!("{}.md", self.name); + let file = File::new(path.join(file_name), self.document.section); + files.push(file); + + for child in self.document.children { + child.into_files_imp(path.join(&self.name), files); + } + } +} + +struct Document { + section: Section, + children: Vec, +} + +impl Document { + fn leaf(section: Section) -> Self { + Self { + section, + children: vec![], + } + } +} + pub(crate) struct File { path: Utf8PathBuf, - rendered: RenderedSection, + rendered: Section, } impl File { - fn new(path: impl Into, rendered: RenderedSection) -> Self { + fn new(path: impl Into, rendered: Section) -> Self { Self { path: path.into(), rendered, diff --git a/xtask/src/cli/codegen/input.rs b/xtask/src/cli/codegen/source.rs similarity index 93% rename from xtask/src/cli/codegen/input.rs rename to xtask/src/cli/codegen/source.rs index ef1cddfd..c7133aa0 100644 --- a/xtask/src/cli/codegen/input.rs +++ b/xtask/src/cli/codegen/source.rs @@ -260,16 +260,8 @@ impl Schema { .with_context(|| format!("Expected description for schema, but found none: {self:#?}")) } - pub(crate) fn referenced_definition(&self) -> Result> { - let Some(reference) = &self.reference else { - return Ok(None); - }; - - let reference = reference.strip_prefix("#/definitions/").with_context(|| { - format!("Reference to anything but `#/definitions` is disallowed: {reference}") - })?; - - Ok(Some(reference)) + pub(crate) fn referenced_definition(&self) -> Option<&str> { + self.reference.as_ref()?.strip_prefix("#/definitions/") } pub(crate) fn is_undocumented_primitive(&self) -> bool { @@ -296,26 +288,26 @@ impl Schema { } impl RootSchema { - pub(crate) fn find_definition(&self, def_name: &str) -> Result<&Schema> { + pub(crate) fn definition(&self, definition: &str) -> Result<&Schema> { self.definitions - .get(def_name) - .with_context(|| format!("Reference to unknown definition: `{def_name}`")) + .get(definition) + .with_context(|| format!("Reference to unknown definition: `{definition}`")) } - fn find_reference(&self, schema: &Schema) -> Result> { - let Some(def_name) = schema.referenced_definition()? else { + fn referenced_definition(&self, schema: &Schema) -> Result> { + let Some(definition) = schema.referenced_definition() else { return Ok(None); }; let definition = self - .find_definition(def_name) + .definition(definition) .with_context(|| format!("inside of schema: {schema:#?}"))?; Ok(Some(definition)) } pub(crate) fn inline_referenced_definition(&self, schema: &Schema) -> Result { - let Some(definition) = self.find_reference(schema)? else { + let Some(definition) = self.referenced_definition(schema)? else { return Ok(schema.clone()); }; From c9e525b9765d8dbc9936245f62e2e4b62d6182ed Mon Sep 17 00:00:00 2001 From: Veetaha Date: Wed, 17 Apr 2024 00:58:29 +0000 Subject: [PATCH 12/20] g g p --- Cargo.lock | 64 +++++-- xtask/Cargo.toml | 5 +- xtask/src/cli/codegen/md_doc/dom.rs | 35 +++- xtask/src/cli/codegen/md_doc/mod.rs | 48 +++-- xtask/src/cli/codegen/md_doc/rendering.rs | 174 ++++++++++-------- .../src/cli/codegen/md_doc/rendering/mdast.rs | 165 +++++++++++++++++ xtask/src/cli/codegen/source.rs | 10 +- 7 files changed, 381 insertions(+), 120 deletions(-) create mode 100644 xtask/src/cli/codegen/md_doc/rendering/mdast.rs diff --git a/Cargo.lock b/Cargo.lock index 5f27288b..82882aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -736,6 +736,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1809,15 +1818,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "markdown" -version = "1.0.0-alpha.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0f0025e8c0d89b84d6dc63e859475e40e8e82ab1a08be0a93ad5731513a508" -dependencies = [ - "unicode-id", -] - [[package]] name = "matchers" version = "0.1.0" @@ -2058,6 +2058,34 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" +[[package]] +name = "pulldown-cmark" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0530d13d87d1f549b66a3e8d0c688952abe5994e204ed62615baaf25dc029c" +dependencies = [ + "bitflags 2.5.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b" + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b" +dependencies = [ + "pulldown-cmark", +] + [[package]] name = "quote" version = "1.0.35" @@ -2985,6 +3013,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -2997,12 +3034,6 @@ version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" -[[package]] -name = "unicode-id" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -3382,7 +3413,8 @@ dependencies = [ "clap", "indexmap", "itertools", - "markdown", + "pulldown-cmark", + "pulldown-cmark-to-cmark", "serde", "serde_json", "serde_yaml", diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 61598941..fadd68b1 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -13,14 +13,15 @@ camino = "1.1" # Amazing CLI arg parser clap = { version = "4.3", features = ["derive"] } +pulldown-cmark = "0.10" +pulldown-cmark-to-cmark = "13.0" + # The best iterators utilities itertools = "0.12" # Map that preserves the order of fields indexmap = { version = "2.0", features = ["serde"] } -markdown = "1.0.0-alpha.16" - # The coolest serialization framework in the world serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/xtask/src/cli/codegen/md_doc/dom.rs b/xtask/src/cli/codegen/md_doc/dom.rs index 170be5a3..d61672bc 100644 --- a/xtask/src/cli/codegen/md_doc/dom.rs +++ b/xtask/src/cli/codegen/md_doc/dom.rs @@ -35,7 +35,24 @@ pub(crate) enum SchemaDoc { /// This schema is a reference to some other schema. It may be either a reference /// to a definition within the same schema or a reference to some external schema. - Ref(String), + Ref(SchemaDocRef), +} + +impl SchemaDoc { + pub(crate) fn reference(&self) -> Option<&str> { + match self { + SchemaDoc::Ref(reference) => Some(&reference.reference), + _ => None, + } + } +} + +#[derive(Debug)] +pub(crate) struct SchemaDocRef { + pub(crate) reference: String, + + /// Additional data that may override the details of the referenced schema. + pub(crate) data: SchemaDocData, } #[derive(Debug)] @@ -76,13 +93,17 @@ impl fmt::Display for Path { let mut segments = self.segments.iter(); if let Some(segment) = segments.next() { - write!(f, "{segment}")?; + if let PathSegment::Variant(_) = segment { + write!(f, "As {segment}")?; + } else { + write!(f, "{segment}")?; + } } segments.try_for_each(|segment| match &segment { PathSegment::Field(_) => write!(f, ".{segment}"), - PathSegment::Index => write!(f, " array item"), - PathSegment::Variant(_) => write!(f, " as {segment}"), + PathSegment::Index => write!(f, "{segment}"), + PathSegment::Variant(_) => write!(f, "as {segment}"), }) } } @@ -97,8 +118,10 @@ impl fmt::Display for PathSegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self { PathSegment::Field(field) => f.write_str(&field.name), - PathSegment::Index => f.write_str("n"), - PathSegment::Variant(name) => f.write_str(name), + // . + // [..] + PathSegment::Index => f.write_str("[N]"), + PathSegment::Variant(name) => write!(f, "{name}"), } } } diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/xtask/src/cli/codegen/md_doc/mod.rs index b3a072af..41f93d72 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/xtask/src/cli/codegen/md_doc/mod.rs @@ -176,32 +176,38 @@ impl GenerateDoc { } fn schema_node(&self, schema: PathedSourceSchema) -> Result { - if let Some(reference) = schema.inner.reference.clone() { - self.schema_node_ref(schema, reference) - } else { - self.schema_node_non_ref(schema) - } - } + // if let Some(reference) = schema.inner.reference.clone() { + // self.schema_node_ref(schema, reference) + // } else { + // self.schema_node_non_ref(schema) + // } + // } - fn schema_node_ref(&self, schema: PathedSourceSchema, reference: String) -> Result { - let doc = SchemaDoc::Ref(reference); - let path = schema.path; + // fn schema_node_ref(&self, schema: PathedSourceSchema, reference: String) -> Result { + // let doc = SchemaDoc::Ref(reference); + // let path = schema.path; - let inline = self - .options - .root - .inline_referenced_definition(&schema.inner)?; + // let inline = self + // .options + // .root + // .inline_referenced_definition(&schema.inner)?; - let ty = Type::from_source_schema(&inline); + // let ty = Type::from_source_schema(&inline); - let schema = Schema { path, ty, doc }; + // let schema = Schema { path, ty, doc }; - Ok(SchemaNode::leaf(schema)) - } + // Ok(SchemaNode::leaf(schema)) + // } - fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { + // fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { let path = schema.path; - let ty = Type::from_source_schema(&schema.inner); + + let ty = Type::from_source_schema( + &self + .options + .root + .inline_referenced_definition(&schema.inner)?, + ); let schema = schema.inner; @@ -227,7 +233,9 @@ impl GenerateDoc { examples: schema.examples, }; - let doc = if path.segments.len() % (self.options.max_nesting_in_file + 1) == 0 { + let doc = if let Some(reference) = schema.reference.clone() { + SchemaDoc::Ref(SchemaDocRef { reference, data }) + } else if path.segments.len() % (self.options.max_nesting_in_file + 1) == 0 { SchemaDoc::Nested(data) } else { SchemaDoc::Embedded(data) diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/xtask/src/cli/codegen/md_doc/rendering.rs index 773e1e35..19d5b928 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/xtask/src/cli/codegen/md_doc/rendering.rs @@ -1,3 +1,6 @@ +mod mdast; + +use self::mdast::MdNode; use super::{ Doc, LeafType, Path, PathOrigin, PathSegment, Schema, SchemaDoc, SchemaDocData, SchemaNode, Type, @@ -36,22 +39,24 @@ impl Renderer { // File::new(format!("{key}/cfg.md"), rendered) // }); + let type_index = self.type_index(&doc.type_index); let root = NamedDocument { name: "root".to_owned(), + document: self.schema_node(&doc.root), + }; + let children = itertools::chain([root], type_index).collect(); + + let schema = NamedDocument { + name: "schema".to_owned(), document: Document { section: self.root_file_base.clone(), - children: vec![NamedDocument { - name: "schema".to_owned(), - document: self.schema_node(&doc.root), - }], + children, }, }; - let type_index = self.type_index(&doc.type_index); + println!("{}", schema.summary().to_markdown()); - itertools::chain([root], type_index) - .flat_map(NamedDocument::into_files) - .collect() + schema.files() } fn type_index(&self, type_index: &BTreeMap) -> Option { @@ -84,59 +89,39 @@ impl Renderer { match &node.schema.doc { SchemaDoc::Embedded(doc) => self.schema_embedded(&node, doc), SchemaDoc::Nested(doc) => self.schema_embedded(&node, doc), - SchemaDoc::Ref(reference) => self.schema_ref(&node, reference), + SchemaDoc::Ref(reference) => self.schema_embedded(&node, &reference.data), } } - fn schema_ref(&self, node: &SchemaNode, reference: &str) -> Document { - let (ref_name, url) = reference - .strip_prefix("#/definitions/") - .map(|definition| { - let anchor = definition.to_lowercase(); - (definition, format!("/checks2/type-index.html#{anchor})")) - }) - .unwrap_or_else(|| ("{ExternalSchema}", reference.to_owned())); + // fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { + // let document = self.schema_embedded(node, doc); - let section = self.type_reference(&node.schema, ref_name, &url); + // let name = node.schema.path.segments.last().unwrap().to_string(); - Document::leaf(section) - } - - fn type_reference(&self, schema: &Schema, ref_name: &str, url: &str) -> Section { - let reference = format!("[`{ref_name}`]({url})"); - - let ty = self - .ty(&schema.ty) - .map(|ty| format!(" `{ty}`")) - .unwrap_or_default(); + // let nested = NamedDocument { + // name: name.clone(), + // document, + // }; - let body = format!("**Type:**: {reference}{ty}"); - - Section::leaf(self.section_header(schema), body) - } + // let url = format!("./{name}.md"); + // let section = self.type_reference(&node.schema, "Nested", &url); - fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { - let document = self.schema_embedded(node, doc); - - let name = node.schema.path.segments.last().unwrap().to_string(); - - let nested = NamedDocument { - name: name.clone(), - document, - }; - - let url = format!("./{name}.md"); - let section = self.type_reference(&node.schema, "Nested", &url); - - Document { - section, - children: vec![nested], - } - } + // Document { + // section, + // children: vec![nested], + // } + // } fn schema_embedded(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { + let enum_doc = node + .schema + .doc + .reference() + .is_none() + .then(|| self.enum_doc(&node.schema.ty.inner)); + let children = [ - self.enum_doc(&node.schema.ty.inner), + enum_doc.flatten(), self.default(&node.schema.path, &doc), self.examples(&node.schema.path, &doc), ]; @@ -154,7 +139,7 @@ impl Renderer { let section = Section { header, - body: self.section_body(&node.schema, &doc), + body: self.section_body(&node.schema, doc), children: child_sections, }; Document { @@ -164,22 +149,22 @@ impl Renderer { } fn section_header(&self, schema: &Schema) -> String { - if let PathOrigin::Definition(def) = &schema.path.origin { - return format!("`{def}`"); - } let Some(last_segment) = schema.path.segments.last() else { - return "Schema".to_owned(); + return match &schema.path.origin { + PathOrigin::Definition(def) => format!("`{def}`"), + PathOrigin::Root => "Root".to_owned(), + }; }; match &last_segment { PathSegment::Field(_) => format!("`{}`", schema.path), - PathSegment::Index => "Array item".to_owned(), - PathSegment::Variant(variant_name) => format!("Variant: `{variant_name}`"), + PathSegment::Index => format!("`{}`", schema.path), + PathSegment::Variant(_) => format!("`{}`", schema.path), } } fn section_body(&self, schema: &Schema, doc: &SchemaDocData) -> String { - let top = [self.tag_for_type(&schema.ty), self.tag_for_required(schema)]; + let top = [self.tag_for_type(schema), self.tag_for_required(schema)]; let top = top.iter().flatten().join("
\n"); @@ -194,15 +179,38 @@ impl Renderer { }; let requirement = match field.required { - true => "yes", - false => "no", + true => "required", + false => "optional", }; - Some(format!("**Required:** `{requirement}`")) + Some(format!("**Key:** `{requirement}`")) } - fn tag_for_type(&self, ty: &Type) -> Option { - let ty = self.ty(&ty)?; - Some(format!("**Type:** `{ty}`")) + fn tag_for_type(&self, schema: &Schema) -> Option { + let reference = schema.doc.reference().map(|reference| { + let (label, url) = reference + .strip_prefix("#/definitions/") + // TODO: unhardcode + .map(|definition| { + ( + definition, + format!("/checks2/schema/type-index/{definition}.md"), + ) + }) + .unwrap_or_else(|| ("{ExternalSchema}", reference.to_owned())); + + format!("[`{label}`]({url})") + }); + + let ty = self.ty(&schema.ty); + + let value = match (ty, reference) { + (None, None) => return None, + (None, Some(reference)) => reference, + (Some(ty), None) => format!("`{ty}`"), + (Some(ty), Some(reference)) => format!("{reference} `{ty}`"), + }; + + Some(format!("**Type:** {value}")) } fn leaf_type(&self, ty: &LeafType) -> Option { @@ -290,7 +298,7 @@ impl Renderer { format!("- {doc}") }) - .join("\n\n"); + .join("\n"); Some(Section::leaf("Possible values", doc)) } @@ -377,20 +385,42 @@ struct NamedDocument { } impl NamedDocument { - fn into_files(self) -> Vec { + fn summary(&self) -> MdNode<'_> { + // TODO: unhardcode root path + let path = Utf8PathBuf::from("checks2"); + let node = self.summary_imp(path); + MdNode::unordered_list([node]) + } + + fn summary_imp(&self, path: Utf8PathBuf) -> MdNode<'_> { + let url = path.join(format!("{}.md", self.name)); + let link = MdNode::link([MdNode::text(self.name.as_str())], url.into_string()); + + let children = self + .document + .children + .iter() + .map(|child| child.summary_imp(path.join(&self.name))); + + MdNode::many([link, MdNode::unordered_list(children)]) + } + + fn files(&self) -> Vec { let mut files = vec![]; + let path = Utf8PathBuf::new(); - self.into_files_imp(path, &mut files); + + self.files_imp(path, &mut files); files } - fn into_files_imp(self, path: Utf8PathBuf, files: &mut Vec) { + fn files_imp(&self, path: Utf8PathBuf, files: &mut Vec) { let file_name = format!("{}.md", self.name); - let file = File::new(path.join(file_name), self.document.section); + let file = File::new(path.join(file_name), self.document.section.clone()); files.push(file); - for child in self.document.children { - child.into_files_imp(path.join(&self.name), files); + for child in &self.document.children { + child.files_imp(path.join(&self.name), files); } } } diff --git a/xtask/src/cli/codegen/md_doc/rendering/mdast.rs b/xtask/src/cli/codegen/md_doc/rendering/mdast.rs new file mode 100644 index 00000000..5be4ca20 --- /dev/null +++ b/xtask/src/cli/codegen/md_doc/rendering/mdast.rs @@ -0,0 +1,165 @@ +use pulldown_cmark::{CowStr, Event, LinkType, Tag}; + +pub(crate) enum MdNode<'a> { + Many(Vec), + + Code(CowStr<'a>), + + Text(CowStr<'a>), + + Link { + label: Vec, + url: CowStr<'a>, + }, + + List { + children: Vec, + + /// Defines the start number for an ordered list. + /// If [`None`] it is an unordered list. + start: Option, + }, + + Paragraph { + children: Vec, + }, +} + +impl<'a> MdNode<'a> { + fn for_each_pulldown_cmark_event(&'a self, visit: &mut dyn FnMut(Event<'a>)) { + match self { + MdNode::Many(nodes) => { + for node in nodes { + node.for_each_pulldown_cmark_event(visit); + } + } + MdNode::Code(code) => { + visit(Event::Code(CowStr::Borrowed(code))); + } + MdNode::Text(text) => { + visit(Event::Text(CowStr::Borrowed(text))); + } + MdNode::Link { label, url } => { + let link = TagGuard::new( + visit, + Tag::Link { + link_type: LinkType::Inline, + dest_url: CowStr::Borrowed(url), + title: "".into(), + id: "".into(), + }, + ); + + for node in label { + node.for_each_pulldown_cmark_event(link.visit); + } + } + MdNode::List { children, start } => { + if children.is_empty() { + return; + } + + let mut list = TagGuard::new(visit, Tag::List(*start)); + + for node in children { + let item = list.nest(Tag::Item); + node.for_each_pulldown_cmark_event(item.visit); + } + } + MdNode::Paragraph { children } => { + let paragraph = TagGuard::new(visit, Tag::Paragraph); + for node in children { + node.for_each_pulldown_cmark_event(paragraph.visit); + } + } + } + } + + pub(crate) fn to_markdown(&self) -> String { + let options = pulldown_cmark_to_cmark::Options { + list_token: '-', + ..Default::default() + }; + + let mut buf = String::new(); + let mut state = None; + + self.for_each_pulldown_cmark_event(&mut |event| { + let events = [event].into_iter(); + let new_state = pulldown_cmark_to_cmark::cmark_resume_with_options( + events, + &mut buf, + state.take(), + options.clone(), + ) + .expect("Writing to String should not fail"); + state = Some(new_state); + }); + + buf + } + + pub(crate) fn many(nodes: impl IntoIterator) -> Self { + MdNode::Many(Vec::from_iter(nodes)) + } + + pub(crate) fn code(code: impl Into>) -> Self { + MdNode::Code(code.into()) + } + + pub(crate) fn text(text: impl Into>) -> Self { + MdNode::Text(text.into()) + } + + pub(crate) fn link(label: impl IntoIterator, url: impl Into>) -> Self { + MdNode::Link { + label: Vec::from_iter(label), + url: url.into(), + } + } + + pub(crate) fn unordered_list(items: impl IntoIterator) -> Self { + MdNode::List { + children: Vec::from_iter(items), + start: None, + } + } + + pub(crate) fn paragraph(content: impl IntoIterator) -> Self { + MdNode::Paragraph { + children: Vec::from_iter(content), + } + } +} + +struct TagGuard<'e, 'v> { + end: Option>, + visit: &'v mut dyn FnMut(Event<'e>), +} + +impl Drop for TagGuard<'_, '_> { + fn drop(&mut self) { + (self.visit)(self.end.take().unwrap()) + } +} + +impl<'e, 'v> TagGuard<'e, 'v> { + #[must_use] + fn new(visit: &'v mut dyn FnMut(Event<'e>), start: Tag<'e>) -> Self { + let end = start.to_end(); + visit(Event::Start(start)); + + Self { + end: Some(Event::End(end)), + visit, + } + } + + fn visit(&mut self, event: Event<'e>) { + (self.visit)(event) + } + + fn nest(&mut self, start: Tag<'e>) -> TagGuard<'e, '_> { + TagGuard::new(&mut *self.visit, start) + } +} diff --git a/xtask/src/cli/codegen/source.rs b/xtask/src/cli/codegen/source.rs index c7133aa0..d68c4a83 100644 --- a/xtask/src/cli/codegen/source.rs +++ b/xtask/src/cli/codegen/source.rs @@ -311,12 +311,14 @@ impl RootSchema { return Ok(schema.clone()); }; - let mut schema = schema.clone(); - schema.reference = None; + let mut output = definition.clone(); - merge_json_mut(&mut schema, definition); + // Values from the schema should take priority + merge_json_mut(&mut output, schema); - Ok(schema) + output.reference = None; + + Ok(output) } } From ca7dec945422cff8a70c8ceb70c6d3fe813fc6e8 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 28 Apr 2024 12:53:09 +0000 Subject: [PATCH 13/20] Next iteratio --- docs/src/SUMMARY.md | 32 +-- docs/src/checks2/advisories/cfg.md | 254 +----------------- docs/src/checks2/bans/cfg.md | 25 +- docs/src/checks2/cfg.md | 43 --- docs/src/checks2/graph/cfg.md | 141 +--------- docs/src/checks2/output/cfg.md | 24 +- docs/src/checks2/schema.md | 9 + docs/src/checks2/schema/root.md | 27 ++ docs/src/checks2/schema/type-index.md | 3 + .../checks2/schema/type-index/Advisories.md | 204 ++++++++++++++ .../type-index/AdvisoriesIgnoreAdvisory.md | 21 ++ .../schema/type-index/AdvisoriesIgnoreItem.md | 17 ++ .../type-index/AdvisoriesIgnoreYanked.md | 13 + docs/src/checks2/schema/type-index/Bans.md | 13 + .../checks2/schema/type-index/BansAllow.md | 13 + docs/src/checks2/schema/type-index/Graph.md | 105 ++++++++ .../checks2/schema/type-index/IgnoreReason.md | 5 + .../checks2/schema/type-index/LintLevel.md | 9 + docs/src/checks2/schema/type-index/Output.md | 21 ++ .../checks2/schema/type-index/PackageSpec.md | 73 +++++ docs/src/checks2/schema/type-index/Target.md | 11 + .../schema/type-index/TargetAdvanced.md | 32 +++ .../checks2/schema/type-index/TargetString.md | 22 ++ docs/src/checks2/type-index.md | 118 +------- docs/src/checks2/type-index/Advisories.md | 142 ++++++++++ .../type-index/AdvisoriesIgnoreAdvisory.md | 20 ++ .../type-index/AdvisoriesIgnoreItem.md | 17 ++ .../type-index/AdvisoriesIgnoreYanked.md | 11 + docs/src/checks2/type-index/Bans.md | 12 + docs/src/checks2/type-index/BansAllow.md | 13 + docs/src/checks2/type-index/Graph.md | 105 ++++++++ docs/src/checks2/type-index/IgnoreReason.md | 5 + docs/src/checks2/type-index/LintLevel.md | 11 + docs/src/checks2/type-index/Output.md | 21 ++ docs/src/checks2/type-index/PackageSpec.md | 73 +++++ docs/src/checks2/type-index/Target.md | 11 + docs/src/checks2/type-index/TargetAdvanced.md | 31 +++ docs/src/checks2/type-index/TargetString.md | 22 ++ docs/src/checs2/graph/README.md | 1 - docs/src/checs2/output/README.md | 1 - .../src/cli/codegen/md_doc/rendering/mdast.rs | 14 + 41 files changed, 1133 insertions(+), 612 deletions(-) delete mode 100644 docs/src/checks2/cfg.md create mode 100644 docs/src/checks2/schema.md create mode 100644 docs/src/checks2/schema/root.md create mode 100644 docs/src/checks2/schema/type-index.md create mode 100644 docs/src/checks2/schema/type-index/Advisories.md create mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md create mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md create mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md create mode 100644 docs/src/checks2/schema/type-index/Bans.md create mode 100644 docs/src/checks2/schema/type-index/BansAllow.md create mode 100644 docs/src/checks2/schema/type-index/Graph.md create mode 100644 docs/src/checks2/schema/type-index/IgnoreReason.md create mode 100644 docs/src/checks2/schema/type-index/LintLevel.md create mode 100644 docs/src/checks2/schema/type-index/Output.md create mode 100644 docs/src/checks2/schema/type-index/PackageSpec.md create mode 100644 docs/src/checks2/schema/type-index/Target.md create mode 100644 docs/src/checks2/schema/type-index/TargetAdvanced.md create mode 100644 docs/src/checks2/schema/type-index/TargetString.md create mode 100644 docs/src/checks2/type-index/Advisories.md create mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md create mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreItem.md create mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md create mode 100644 docs/src/checks2/type-index/Bans.md create mode 100644 docs/src/checks2/type-index/BansAllow.md create mode 100644 docs/src/checks2/type-index/Graph.md create mode 100644 docs/src/checks2/type-index/IgnoreReason.md create mode 100644 docs/src/checks2/type-index/LintLevel.md create mode 100644 docs/src/checks2/type-index/Output.md create mode 100644 docs/src/checks2/type-index/PackageSpec.md create mode 100644 docs/src/checks2/type-index/Target.md create mode 100644 docs/src/checks2/type-index/TargetAdvanced.md create mode 100644 docs/src/checks2/type-index/TargetString.md delete mode 100644 docs/src/checs2/graph/README.md delete mode 100644 docs/src/checs2/output/README.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d2b5fd42..c87ba305 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -22,18 +22,20 @@ - [diagnostics](checks/sources/diags.md) - [Type Index](checks2/type-index.md) - [Checks2](checks/README.md) - - [config](checks2/cfg.md) - - [advisories](checks2/advisories/README.md) - - [config](checks2/advisories/cfg.md) - - [diagnostics](checks2/advisories/diags.md) - - [bans](checks2/bans/README.md) - - [config](checks2/bans/cfg.md) - - [diagnostics](checks2/bans/diags.md) - - [graph](checks2/graph/cfg.md) - - [licenses](checks2/licenses/README.md) - - [config](checks2/licenses/cfg.md) - - [diagnostics](checks2/licenses/diags.md) - - [output](checks2/output/cfg.md) - - [sources](checks2/sources/README.md) - - [config](checks2/sources/cfg.md) - - [diagnostics](checks2/sources/diags.md) + - [schema](checks2/schema.md) + - [root](checks2/schema/root.md) + - [type-index](checks2/schema/type-index.md) + - [Advisories](checks2/schema/type-index/Advisories.md) + - [AdvisoriesIgnoreAdvisory](checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md) + - [AdvisoriesIgnoreItem](checks2/schema/type-index/AdvisoriesIgnoreItem.md) + - [AdvisoriesIgnoreYanked](checks2/schema/type-index/AdvisoriesIgnoreYanked.md) + - [Bans](checks2/schema/type-index/Bans.md) + - [BansAllow](checks2/schema/type-index/BansAllow.md) + - [Graph](checks2/schema/type-index/Graph.md) + - [IgnoreReason](checks2/schema/type-index/IgnoreReason.md) + - [LintLevel](checks2/schema/type-index/LintLevel.md) + - [Output](checks2/schema/type-index/Output.md) + - [PackageSpec](checks2/schema/type-index/PackageSpec.md) + - [Target](checks2/schema/type-index/Target.md) + - [TargetAdvanced](checks2/schema/type-index/TargetAdvanced.md) + - [TargetString](checks2/schema/type-index/TargetString.md) diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md index 3a6cddfa..1417945b 100644 --- a/docs/src/checks2/advisories/cfg.md +++ b/docs/src/checks2/advisories/cfg.md @@ -1,253 +1 @@ -# `advisories` - -**Type:** `object`
-**Required:** `no` - -Checks advisory databases for crates with security vulnerabilities, -or that have been marked as unmaintained, or which have been yanked from -their source registry. - -This section is considered when running `cargo deny check advisories`. - - -## Example - -```toml -[advisories] -db-path = "~/.cargo/advisory-dbs" -db-urls = ["https://github.com/RustSec/advisory-db"] -vulnerability = "deny" -unmaintained = "warn" -unsound = "warn" -yanked = "warn" -notice = "warn" -ignore = [ - "RUSTSEC-0000-0000", - "crate@0.1", - { crate = "yanked", reason = "a new version has not been released" }, -] -severity-threshold = "medium" -``` - -## `advisories.db-urls` - -**Type:** `array`
-**Required:** `no` - -URLs to one or more advisory databases. - -### Default - -```toml -[advisories] -db-urls = ["https://github.com/RustSec/advisory-db"] -``` - -## `advisories.db-path` - -**Type:** `string`
-**Required:** `no` - -Path to the root directory into which one or more advisory databases are cloned into. - -This value supports basic shell expansion: - -- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) -- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) - or the fallback value if it doesn't exist (everything between the `:-` and `}`) -- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) - if it exists, otherwise expands to `$(home::home_dir())/.cargo` - -Note that the path must be valid utf-8, after expansion. - - -### Default - -```toml -[advisories] -db-path = "$CARGO_HOME/advisory-dbs" -``` - -## `advisories.version` - -**Type:** `integer (enum)`
-**Required:** `no` - -The advisories section has an upcoming breaking change, with deprecation warnings for several -fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. - -The breaking change is as follows: - -- `vulnerability` - Removed, all vulnerability advisories now emit errors. -- `unmaintained` - Removed, all unmaintained advisories now emit errors. -- `unsound` - Removed, all unsound advisories now emit errors. -- `notice` - Removed, all notice advisories now emit errors. -- `severity-threshold` - Removed, all vulnerability advisories now emit errors. - -As before, if you want to ignore a specific advisory, add it to the `ignore` field. - - -### Possible values - -- `2` - -## `advisories.vulnerability` - -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
-**Required:** `no` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a security vulnerability is encountered. - - -### Default - -```toml -[advisories] -vulnerability = "deny" -``` - -## `advisories.unmaintained` - -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
-**Required:** `no` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unmaintained` advisory is encountered. - - -### Default - -```toml -[advisories] -unmaintained = "warn" -``` - -## `advisories.unsound` - -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
-**Required:** `no` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unsound` advisory is encountered. - - -### Default - -```toml -[advisories] -unsound = "warn" -``` - -## `advisories.notice` - -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
-**Required:** `no` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a `notice` advisory is encountered. - -**NOTE**: As of 2019-12-17 there are no `notice` advisories in the -[RustSec Advisory DB](https://github.com/RustSec/advisory-db) - - -### Default - -```toml -[advisories] -notice = "warn" -``` - -## `advisories.yanked` - -**Type:** [`LintLevel`](/checks2/type-index.html#lintlevel) `(string (enum))`
-**Required:** `no` - -Determines what happens when a crate with a version that has been yanked from its source -registry is encountered. - - -### Default - -```toml -[advisories] -yanked = "warn" -``` - -## `advisories.ignore` - -**Type:** `array`
-**Required:** `no` - -Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. -Putting an identifier in this array will cause the advisory to be treated as a note, rather -than a warning or error. - -In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -with an optional `reason`. - - -### Example - -```toml -[advisories] -ignore = [ - "RUSTSEC-0000-0000", - { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, - "yanked@0.1.1", - { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, -] -``` - -### Array item - - - -#### Variant: `string` - -**Type:** `string` - -Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - -#### Variant: `AdvisoriesIgnoreAdvisory` - -**Type:** `object` - -##### `advisories.ignore array item as AdvisoriesIgnoreAdvisory.id` - -**Type:** `string`
-**Required:** `yes` - -The unique identifier of the advisory to ignore - -###### Example - -```toml -[advisories] -ignore = ["RUSTSEC-2019-0001"] -``` - -##### `advisories.ignore array item as AdvisoriesIgnoreAdvisory.reason` - -**Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
-**Required:** `no` - -#### Variant: `AdvisoriesIgnoreYanked` - -**Type:** `object` - -##### `advisories.ignore array item as AdvisoriesIgnoreYanked.crate` - -**Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)`
-**Required:** `yes` - -##### `advisories.ignore array item as AdvisoriesIgnoreYanked.reason` - -**Type:** [`IgnoreReason`](/checks2/type-index.html#ignorereason) `(string)`
-**Required:** `no` \ No newline at end of file +# config diff --git a/docs/src/checks2/bans/cfg.md b/docs/src/checks2/bans/cfg.md index e2b40e39..1417945b 100644 --- a/docs/src/checks2/bans/cfg.md +++ b/docs/src/checks2/bans/cfg.md @@ -1,24 +1 @@ -# `bans` - -**Type:** `object`
-**Required:** `no` - -Checks for specific crates in your graph, as well as duplicates. - -This section is considered when running `cargo deny check bans`. - - -## `bans.allow` - -**Type:** `array`
-**Required:** `no` - -Determines specific crates that are allowed. If the `allow` list has one or more entries, then -any crate not in that list will be denied, so use with care. Each entry uses the same -[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -as other parts of cargo-deny's configuration. - - -### Array item - -**Type:** [`PackageSpec`](/checks2/type-index.html#packagespec) `(string)` \ No newline at end of file +# config diff --git a/docs/src/checks2/cfg.md b/docs/src/checks2/cfg.md deleted file mode 100644 index 4cd83aec..00000000 --- a/docs/src/checks2/cfg.md +++ /dev/null @@ -1,43 +0,0 @@ -# config - -The top level config for cargo-deny, by default called `deny.toml`. - -## Example - cargo-deny's own configuration - -```ini -{{#include ../../../deny.toml}} -``` - -## The `[advisories]` type_doc - -Checks advisory databases for crates with security vulnerabilities, -or that have been marked as unmaintained, or which have been yanked from -their source registry. - -This section is considered when running `cargo deny check advisories`. - - -See [advisories config](advisories/cfg.html) for more info. - -## The `[bans]` type_doc - -Checks for specific crates in your graph, as well as duplicates. - -This section is considered when running `cargo deny check bans`. - - -See [bans config](bans/cfg.html) for more info. - -## The `[graph]` type_doc - -The graph table configures how the dependency graph is constructed and thus which crates the -checks are performed against - - -See [graph config](graph/cfg.html) for more info. - -## The `[output]` type_doc - -The output table provides options for how/if diagnostics are outputted - -See [output config](output/cfg.html) for more info. \ No newline at end of file diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md index da27a905..8dc858c5 100644 --- a/docs/src/checks2/graph/cfg.md +++ b/docs/src/checks2/graph/cfg.md @@ -1,140 +1 @@ -# `graph` - -**Type:** `object`
-**Required:** `no` - -The graph table configures how the dependency graph is constructed and thus which crates the -checks are performed against - - -## `graph.targets` - -**Type:** `array`
-**Required:** `no` - -By default, cargo-deny will consider every single crate that is resolved by cargo, including -target specific dependencies e.g. - -```toml -[target.x86_64-pc-windows-msvc.dependencies] -winapi = "0.3.8" - -[target.'cfg(target_os = "fuchsia")'.dependencies] -fuchsia-cprng = "0.1.1" -``` - -But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is -never actually going to be compiled or linked into your project, so checking it is pointless for you. - -The `targets` field allows you to specify one or more targets which you **actually** build for. -Every dependency link to a crate is checked against this list, and if none of the listed targets -satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links -to it, it is not included into the crate graph that the checks are -executed against. - - -### Array item - - - -#### Variant: `TargetString` - -**Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)` - -#### Variant: `TargetAdvanced` - -**Type:** `object` - -Advanced configurations to apply for the target triple - -##### Examples - -- ```toml - [[graph.targets]] - triple = "aarch64-apple-darwin" - ``` -- ```toml - [[graph.targets]] - triple = "x86_64-pc-windows-msvc" - features = ["some-feature"] - ``` - -##### `graph.targets array item as TargetAdvanced.triple` - -**Type:** [`TargetString`](/checks2/type-index.html#targetstring) `(string)`
-**Required:** `yes` - -##### `graph.targets array item as TargetAdvanced.features` - -**Type:** `string`
-**Required:** `no` - -Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) -predicate, but at the moment, the only way to actually pass them when compiling is to use -the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more -`target_feature`s you plan to build with, for a particular target triple. At the time of -this writing, cargo-deny does not attempt to validate that the features you specify are -actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). - - -## `graph.exclude` - -**Type:** `array`
-**Required:** `no` - -Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) -that will cause the crate(s) in question to be excluded from the crate graph that is used -for the operation you are performing. - -Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced -via the excluded crate, they will also be excluded from the crate graph. - - -### Example - -```toml -[graph] -exclude = "some-crate@0.1.0" -``` - -## `graph.all-features` - -**Type:** `boolean`
-**Required:** `no` - -If set to `true`, `--all-features` will be used when collecting metadata. - -## `graph.no-default-features` - -**Type:** `boolean`
-**Required:** `no` - -If set to `true`, `--no-default-features` will be used when collecting metadata. - -## `graph.features` - -**Type:** `array`
-**Required:** `no` - -If set, and `--features` is not specified on the cmd line, these features will be used when -collecting metadata. - - -### Example - -```toml -[graph] -features = "some-feature" -``` - -## `graph.exclude-dev` - -**Type:** `boolean`
-**Required:** `no` - -If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included -in the crate graph used for any of the checks. This option can also be enabled on cmd line -with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) -the `check` subcommand. +# graph diff --git a/docs/src/checks2/output/cfg.md b/docs/src/checks2/output/cfg.md index 07286ccd..2580f631 100644 --- a/docs/src/checks2/output/cfg.md +++ b/docs/src/checks2/output/cfg.md @@ -1,23 +1 @@ -# `output` - -**Type:** `object`
-**Required:** `no` - -The output table provides options for how/if diagnostics are outputted - -## `output.feature-depth` - -**Type:** `integer`
-**Required:** `no` - -The maximum depth that features will be displayed when inclusion graphs are shown in -diagnostics, unless specified via `--feature-depth` on the command line. Only applies to -diagnostics that actually print features. - - -### Default - -```toml -[output] -feature-depth = 1 -``` \ No newline at end of file +# output diff --git a/docs/src/checks2/schema.md b/docs/src/checks2/schema.md new file mode 100644 index 00000000..367e4ee6 --- /dev/null +++ b/docs/src/checks2/schema.md @@ -0,0 +1,9 @@ +# config + +The top level config for cargo-deny, by default called `deny.toml`. + +## Example - cargo-deny's own configuration + +```ini +{{#include ../../../deny.toml}} +``` \ No newline at end of file diff --git a/docs/src/checks2/schema/root.md b/docs/src/checks2/schema/root.md new file mode 100644 index 00000000..d24c9a4b --- /dev/null +++ b/docs/src/checks2/schema/root.md @@ -0,0 +1,27 @@ +# Root + +**Type:** `object` + +Configuration file for cargo-deny, by default called `deny.toml`. + +Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html + +## `advisories` + +**Type:** [`Advisories`](/checks2/schema/type-index/Advisories.md) `object`
+**Key:** `optional` + +## `bans` + +**Type:** [`Bans`](/checks2/schema/type-index/Bans.md) `object`
+**Key:** `optional` + +## `graph` + +**Type:** [`Graph`](/checks2/schema/type-index/Graph.md) `object`
+**Key:** `optional` + +## `output` + +**Type:** [`Output`](/checks2/schema/type-index/Output.md) `object`
+**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index.md b/docs/src/checks2/schema/type-index.md new file mode 100644 index 00000000..dc677c54 --- /dev/null +++ b/docs/src/checks2/schema/type-index.md @@ -0,0 +1,3 @@ +# Type Index + +This is an index of common types used across the schema. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Advisories.md b/docs/src/checks2/schema/type-index/Advisories.md new file mode 100644 index 00000000..a2d31a9e --- /dev/null +++ b/docs/src/checks2/schema/type-index/Advisories.md @@ -0,0 +1,204 @@ +# `Advisories` + +**Type:** `object` + +Checks advisory databases for crates with security vulnerabilities, +or that have been marked as unmaintained, or which have been yanked from +their source registry. + +This section is considered when running `cargo deny check advisories`. + + +## Example + +```toml +db-path = "~/.cargo/advisory-dbs" +db-urls = ["https://github.com/RustSec/advisory-db"] +vulnerability = "deny" +unmaintained = "warn" +unsound = "warn" +yanked = "warn" +notice = "warn" +ignore = [ + "RUSTSEC-0000-0000", + "crate@0.1", + { crate = "yanked", reason = "a new version has not been released" }, +] +severity-threshold = "medium" +``` + +## `db-urls` + +**Type:** `array`
+**Key:** `optional` + +URLs to one or more advisory databases. + +### Default + +```toml +db-urls = ["https://github.com/RustSec/advisory-db"] +``` + +### `db-urls[N]` + +**Type:** `string (uri)` + +## `db-path` + +**Type:** `string`
+**Key:** `optional` + +Path to the root directory into which one or more advisory databases are cloned into. + +This value supports basic shell expansion: + +- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) +- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + or the fallback value if it doesn't exist (everything between the `:-` and `}`) +- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + if it exists, otherwise expands to `$(home::home_dir())/.cargo` + +Note that the path must be valid utf-8, after expansion. + + +### Default + +```toml +db-path = "$CARGO_HOME/advisory-dbs" +``` + +## `version` + +**Type:** `integer (enum)`
+**Key:** `optional` + +The advisories section has an upcoming breaking change, with deprecation warnings for several +fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + +The breaking change is as follows: + +- `vulnerability` - Removed, all vulnerability advisories now emit errors. +- `unmaintained` - Removed, all unmaintained advisories now emit errors. +- `unsound` - Removed, all unsound advisories now emit errors. +- `notice` - Removed, all notice advisories now emit errors. +- `severity-threshold` - Removed, all vulnerability advisories now emit errors. + +As before, if you want to ignore a specific advisory, add it to the `ignore` field. + + +### Possible values + +- `2` + +## `vulnerability` + +**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
+**Key:** `optional` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with a security vulnerability is encountered. + + +### Default + +```toml +vulnerability = "deny" +``` + +## `unmaintained` + +**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
+**Key:** `optional` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with an `unmaintained` advisory is encountered. + + +### Default + +```toml +unmaintained = "warn" +``` + +## `unsound` + +**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
+**Key:** `optional` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with an `unsound` advisory is encountered. + + +### Default + +```toml +unsound = "warn" +``` + +## `notice` + +**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
+**Key:** `optional` + +**DEPRECATED** (see `version` field) + +Determines what happens when a crate with a `notice` advisory is encountered. + +**NOTE**: As of 2019-12-17 there are no `notice` advisories in the +[RustSec Advisory DB](https://github.com/RustSec/advisory-db) + + +### Default + +```toml +notice = "warn" +``` + +## `yanked` + +**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
+**Key:** `optional` + +Determines what happens when a crate with a version that has been yanked from its source +registry is encountered. + + +### Default + +```toml +yanked = "warn" +``` + +## `ignore` + +**Type:** `array`
+**Key:** `optional` + +Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. +Putting an identifier in this array will cause the advisory to be treated as a note, rather +than a warning or error. + +In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +with an optional `reason`. + + +### Example + +```toml +ignore = [ + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, + "yanked@0.1.1", + { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, +] +``` + +### `ignore[N]` + +**Type:** [`AdvisoriesIgnoreItem`](/checks2/schema/type-index/AdvisoriesIgnoreItem.md) \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md new file mode 100644 index 00000000..f6a48ec0 --- /dev/null +++ b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md @@ -0,0 +1,21 @@ +# `AdvisoriesIgnoreAdvisory` + +**Type:** `object` + +## `id` + +**Type:** `string`
+**Key:** `required` + +The unique identifier of the advisory to ignore + +### Example + +```toml +id = "RUSTSEC-2019-0001" +``` + +## `reason` + +**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
+**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md new file mode 100644 index 00000000..33d4d2de --- /dev/null +++ b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md @@ -0,0 +1,17 @@ +# `AdvisoriesIgnoreItem` + + + +## `As string` + +**Type:** `string` + +Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). + +## `As AdvisoriesIgnoreAdvisory` + +**Type:** [`AdvisoriesIgnoreAdvisory`](/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md) `object` + +## `As AdvisoriesIgnoreYanked` + +**Type:** [`AdvisoriesIgnoreYanked`](/checks2/schema/type-index/AdvisoriesIgnoreYanked.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md new file mode 100644 index 00000000..f5c80e22 --- /dev/null +++ b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md @@ -0,0 +1,13 @@ +# `AdvisoriesIgnoreYanked` + +**Type:** `object` + +## `crate` + +**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string`
+**Key:** `required` + +## `reason` + +**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
+**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Bans.md b/docs/src/checks2/schema/type-index/Bans.md new file mode 100644 index 00000000..17a8d57b --- /dev/null +++ b/docs/src/checks2/schema/type-index/Bans.md @@ -0,0 +1,13 @@ +# `Bans` + +**Type:** `object` + +Checks for specific crates in your graph, as well as duplicates. + +This section is considered when running `cargo deny check bans`. + + +## `allow` + +**Type:** [`BansAllow`](/checks2/schema/type-index/BansAllow.md) `array`
+**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/BansAllow.md b/docs/src/checks2/schema/type-index/BansAllow.md new file mode 100644 index 00000000..7d99ce2c --- /dev/null +++ b/docs/src/checks2/schema/type-index/BansAllow.md @@ -0,0 +1,13 @@ +# `BansAllow` + +**Type:** `array` + +Determines specific crates that are allowed. If the `allow` list has one or more entries, then +any crate not in that list will be denied, so use with care. Each entry uses the same +[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +as other parts of cargo-deny's configuration. + + +## `[N]` + +**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Graph.md b/docs/src/checks2/schema/type-index/Graph.md new file mode 100644 index 00000000..69d9ea06 --- /dev/null +++ b/docs/src/checks2/schema/type-index/Graph.md @@ -0,0 +1,105 @@ +# `Graph` + +**Type:** `object` + +The graph table configures how the dependency graph is constructed and thus which crates the +checks are performed against + + +## `targets` + +**Type:** `array`
+**Key:** `optional` + +By default, cargo-deny will consider every single crate that is resolved by cargo, including +target specific dependencies e.g. + +```toml +[target.x86_64-pc-windows-msvc.dependencies] +winapi = "0.3.8" + +[target.'cfg(target_os = "fuchsia")'.dependencies] +fuchsia-cprng = "0.1.1" +``` + +But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is +never actually going to be compiled or linked into your project, so checking it is pointless for you. + +The `targets` field allows you to specify one or more targets which you **actually** build for. +Every dependency link to a crate is checked against this list, and if none of the listed targets +satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links +to it, it is not included into the crate graph that the checks are +executed against. + + +### `targets[N]` + +**Type:** [`Target`](/checks2/schema/type-index/Target.md) + +## `exclude` + +**Type:** `array`
+**Key:** `optional` + +Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) +that will cause the crate(s) in question to be excluded from the crate graph that is used +for the operation you are performing. + +Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced +via the excluded crate, they will also be excluded from the crate graph. + + +### Example + +```toml +exclude = "some-crate@0.1.0" +``` + +### `exclude[N]` + +**Type:** `string` + +## `all-features` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, `--all-features` will be used when collecting metadata. + +## `no-default-features` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, `--no-default-features` will be used when collecting metadata. + +## `features` + +**Type:** `array`
+**Key:** `optional` + +If set, and `--features` is not specified on the cmd line, these features will be used when +collecting metadata. + + +### Example + +```toml +features = "some-feature" +``` + +### `features[N]` + +**Type:** `string` + +## `exclude-dev` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included +in the crate graph used for any of the checks. This option can also be enabled on cmd line +with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) +the `check` subcommand. diff --git a/docs/src/checks2/schema/type-index/IgnoreReason.md b/docs/src/checks2/schema/type-index/IgnoreReason.md new file mode 100644 index 00000000..2b0899c3 --- /dev/null +++ b/docs/src/checks2/schema/type-index/IgnoreReason.md @@ -0,0 +1,5 @@ +# `IgnoreReason` + +**Type:** `string` + +Free-form string that can be used to describe the reason why the advisory is ignored. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/LintLevel.md b/docs/src/checks2/schema/type-index/LintLevel.md new file mode 100644 index 00000000..4da3f64e --- /dev/null +++ b/docs/src/checks2/schema/type-index/LintLevel.md @@ -0,0 +1,9 @@ +# `LintLevel` + +**Type:** `string (enum)` + +## Possible values + +- `"deny"` - Emit an error with details about the problem, and fail the check. +- `"warn"` - Print a warning for each propblem, but don't fail the check. +- `"allow"` - Print a note about the problem, but don't fail the check. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Output.md b/docs/src/checks2/schema/type-index/Output.md new file mode 100644 index 00000000..3028661c --- /dev/null +++ b/docs/src/checks2/schema/type-index/Output.md @@ -0,0 +1,21 @@ +# `Output` + +**Type:** `object` + +The output table provides options for how/if diagnostics are outputted + +## `feature-depth` + +**Type:** `integer`
+**Key:** `optional` + +The maximum depth that features will be displayed when inclusion graphs are shown in +diagnostics, unless specified via `--feature-depth` on the command line. Only applies to +diagnostics that actually print features. + + +### Default + +```toml +feature-depth = 1 +``` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/PackageSpec.md b/docs/src/checks2/schema/type-index/PackageSpec.md new file mode 100644 index 00000000..bb3985a1 --- /dev/null +++ b/docs/src/checks2/schema/type-index/PackageSpec.md @@ -0,0 +1,73 @@ +# `PackageSpec` + +**Type:** `string` + +Many configuration options require a package specifier at a minimum, which we'll describe here. +The options that use package specifiers will be called out in their individual documentation. +We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + +### String format + +If the particular only requires a package spec at a minimum, then the string format can be used, +which comes in three forms. + +#### Simple + +```toml +# Will match any version of the simple crate +deny = ["simple"] +``` + +The simplest string is one which is just the crate name. In this case, the version requirement +used when checking will be `*` meaning it will match against all versions of that crate in the graph. + +#### With Version Requirements + +```toml +# Will match only these versions of the simple crate that match the predicate(s) +deny = ["simple:<=0.1,>0.2"] +``` + +If you want to apply version requirements (predicates) to the crate, simply append them following +a `:` separator. + +#### Exact + +```toml +# Will match only this exact version of the simple crate +deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", +] +``` + +The exact form is a specialization of the version requirements, where the semver after the `@` +is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + +### Table format + +#### Crate format + +```toml +deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, +] +``` + +The crate format is a replacement for the old `name` and/or `version` table format. It uses +the string format described above in a single `crate` key. + +#### Old format + +```toml +deny = [ + { name = "simple" }, + { name = "simple", version = "*" }, + { name = "simple", wrappers = ["example"] } +] +``` + +The old format uses a required `name` key and an optional `version` key. This format is deprecated +and should not be used. diff --git a/docs/src/checks2/schema/type-index/Target.md b/docs/src/checks2/schema/type-index/Target.md new file mode 100644 index 00000000..df380b55 --- /dev/null +++ b/docs/src/checks2/schema/type-index/Target.md @@ -0,0 +1,11 @@ +# `Target` + + + +## `As TargetString` + +**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string` + +## `As TargetAdvanced` + +**Type:** [`TargetAdvanced`](/checks2/schema/type-index/TargetAdvanced.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/TargetAdvanced.md b/docs/src/checks2/schema/type-index/TargetAdvanced.md new file mode 100644 index 00000000..743f9226 --- /dev/null +++ b/docs/src/checks2/schema/type-index/TargetAdvanced.md @@ -0,0 +1,32 @@ +# `TargetAdvanced` + +**Type:** `object` + +Advanced configurations to apply for the target triple + +## Examples + +- ```toml + triple = "aarch64-apple-darwin" + ``` +- ```toml + triple = "x86_64-pc-windows-msvc" + features = ["some-feature"] + ``` + +## `triple` + +**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string`
+**Key:** `required` + +## `features` + +**Type:** `string`
+**Key:** `optional` + +Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) +predicate, but at the moment, the only way to actually pass them when compiling is to use +the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more +`target_feature`s you plan to build with, for a particular target triple. At the time of +this writing, cargo-deny does not attempt to validate that the features you specify are +actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). diff --git a/docs/src/checks2/schema/type-index/TargetString.md b/docs/src/checks2/schema/type-index/TargetString.md new file mode 100644 index 00000000..9972e1c6 --- /dev/null +++ b/docs/src/checks2/schema/type-index/TargetString.md @@ -0,0 +1,22 @@ +# `TargetString` + +**Type:** `string` + +The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target +you wish to filter target specific dependencies with. If the target triple specified is **not** +one of the targets builtin to `rustc`, the configuration check for that target will be limited +to only the raw `[target..dependencies]` style of target configuration, as `cfg()` +expressions require us to know the details about the target. + + +## Examples + +- ```toml + value = "x86_64-unknown-linux-gnu" + ``` +- ```toml + value = "x86_64-pc-windows-msvc" + ``` +- ```toml + value = "aarch64-apple-darwin" + ``` \ No newline at end of file diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md index 47104d2e..4edfa85d 100644 --- a/docs/src/checks2/type-index.md +++ b/docs/src/checks2/type-index.md @@ -2,118 +2,12 @@ This is an index of common types used across the schema. -## `IgnoreReason` +
-**Type:** `string` +This is a bad thing that you should pay attention to. -Free-form string that can be used to describe the reason why the advisory is ignored. +Warning blocks should be used sparingly in documentation, to avoid "warning +fatigue," where people are trained to ignore them because they usually don't +matter for what they're doing. -## `LintLevel` - -**Type:** `string (enum)` - -### Possible values - -- `"deny"` - Emit an error with details about the problem, and fail the check. - -- `"warn"` - Print a warning for each propblem, but don't fail the check. - -- `"allow"` - Print a note about the problem, but don't fail the check. - -## `PackageSpec` - -**Type:** `string` - -Many configuration options require a package specifier at a minimum, which we'll describe here. -The options that use package specifiers will be called out in their individual documentation. -We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. - -### String format - -If the particular only requires a package spec at a minimum, then the string format can be used, -which comes in three forms. - -#### Simple - -```toml -# Will match any version of the simple crate -deny = ["simple"] -``` - -The simplest string is one which is just the crate name. In this case, the version requirement -used when checking will be `*` meaning it will match against all versions of that crate in the graph. - -#### With Version Requirements - -```toml -# Will match only these versions of the simple crate that match the predicate(s) -deny = ["simple:<=0.1,>0.2"] -``` - -If you want to apply version requirements (predicates) to the crate, simply append them following -a `:` separator. - -#### Exact - -```toml -# Will match only this exact version of the simple crate -deny = [ - "simple@0.1.0", - # This is semantically equivalent to the above - "simple:=0.1.0", -] -``` - -The exact form is a specialization of the version requirements, where the semver after the `@` -is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). - -### Table format - -#### Crate format - -```toml -deny = [ - { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" - { crate = "simple", wrappers = ["example"] }, -] -``` - -The crate format is a replacement for the old `name` and/or `version` table format. It uses -the string format described above in a single `crate` key. - -#### Old format - -```toml -deny = [ - { name = "simple" }, - { name = "simple", version = "*" } - { name = "simple", wrappers = ["example"] } -] -``` - -The old format uses a required `name` key and an optional `version` key. This format is deprecated -and should not be used. - - -## `TargetString` - -**Type:** `string` - -The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target -you wish to filter target specific dependencies with. If the target triple specified is **not** -one of the targets builtin to `rustc`, the configuration check for that target will be limited -to only the raw `[target..dependencies]` style of target configuration, as `cfg()` -expressions require us to know the details about the target. - - -### Examples - -- ```toml - value = "x86_64-unknown-linux-gnu" - ``` -- ```toml - value = "x86_64-pc-windows-msvc" - ``` -- ```toml - value = "aarch64-apple-darwin" - ``` \ No newline at end of file +
diff --git a/docs/src/checks2/type-index/Advisories.md b/docs/src/checks2/type-index/Advisories.md new file mode 100644 index 00000000..9188ec72 --- /dev/null +++ b/docs/src/checks2/type-index/Advisories.md @@ -0,0 +1,142 @@ +# `Advisories` + +**Type:** `object` + +Checks advisory databases for crates with security vulnerabilities, +or that have been marked as unmaintained, or which have been yanked from +their source registry. + +This section is considered when running `cargo deny check advisories`. + + +## Example + +```toml +db-path = "~/.cargo/advisory-dbs" +db-urls = ["https://github.com/RustSec/advisory-db"] +vulnerability = "deny" +unmaintained = "warn" +unsound = "warn" +yanked = "warn" +notice = "warn" +ignore = [ + "RUSTSEC-0000-0000", + "crate@0.1", + { crate = "yanked", reason = "a new version has not been released" }, +] +severity-threshold = "medium" +``` + +## `db-urls` + +**Type:** `array`
+**Key:** `optional` + +URLs to one or more advisory databases. + +### Default + +```toml +db-urls = ["https://github.com/RustSec/advisory-db"] +``` + +### Array item + +**Type:** `string (uri)` + +## `db-path` + +**Type:** `string`
+**Key:** `optional` + +Path to the root directory into which one or more advisory databases are cloned into. + +This value supports basic shell expansion: + +- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) +- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) +- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + or the fallback value if it doesn't exist (everything between the `:-` and `}`) +- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + if it exists, otherwise expands to `$(home::home_dir())/.cargo` + +Note that the path must be valid utf-8, after expansion. + + +### Default + +```toml +db-path = "$CARGO_HOME/advisory-dbs" +``` + +## `version` + +**Type:** `integer (enum)`
+**Key:** `optional` + +The advisories section has an upcoming breaking change, with deprecation warnings for several +fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + +The breaking change is as follows: + +- `vulnerability` - Removed, all vulnerability advisories now emit errors. +- `unmaintained` - Removed, all unmaintained advisories now emit errors. +- `unsound` - Removed, all unsound advisories now emit errors. +- `notice` - Removed, all notice advisories now emit errors. +- `severity-threshold` - Removed, all vulnerability advisories now emit errors. + +As before, if you want to ignore a specific advisory, add it to the `ignore` field. + + +### Possible values + +- `2` + +## `vulnerability` + +**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` + +## `unmaintained` + +**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` + +## `unsound` + +**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` + +## `notice` + +**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` + +## `yanked` + +**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` + +## `ignore` + +**Type:** `array`
+**Key:** `optional` + +Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. +Putting an identifier in this array will cause the advisory to be treated as a note, rather +than a warning or error. + +In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +with an optional `reason`. + + +### Example + +```toml +ignore = [ + "RUSTSEC-0000-0000", + { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, + "yanked@0.1.1", + { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, +] +``` + +### Array item + +**Type:** [`AdvisoriesIgnoreItem`](/checks2/type-index/AdvisoriesIgnoreItem.md) \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md b/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md new file mode 100644 index 00000000..b297819c --- /dev/null +++ b/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md @@ -0,0 +1,20 @@ +# `AdvisoriesIgnoreAdvisory` + +**Type:** `object` + +## `id` + +**Type:** `string`
+**Key:** `required` + +The unique identifier of the advisory to ignore + +### Example + +```toml +id = "RUSTSEC-2019-0001" +``` + +## `reason` + +**Type:** [`IgnoreReason`](/checks2/type-index/IgnoreReason.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md b/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md new file mode 100644 index 00000000..b9b7bb3e --- /dev/null +++ b/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md @@ -0,0 +1,17 @@ +# `AdvisoriesIgnoreItem` + + + +## Variant: `string` + +**Type:** `string` + +Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). + +## Variant: `AdvisoriesIgnoreAdvisory` + +**Type:** [`AdvisoriesIgnoreAdvisory`](/checks2/type-index/AdvisoriesIgnoreAdvisory.md) `object` + +## Variant: `AdvisoriesIgnoreYanked` + +**Type:** [`AdvisoriesIgnoreYanked`](/checks2/type-index/AdvisoriesIgnoreYanked.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md b/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md new file mode 100644 index 00000000..20a1242c --- /dev/null +++ b/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md @@ -0,0 +1,11 @@ +# `AdvisoriesIgnoreYanked` + +**Type:** `object` + +## `crate` + +**Type:** [`PackageSpec`](/checks2/type-index/PackageSpec.md) `string` + +## `reason` + +**Type:** [`IgnoreReason`](/checks2/type-index/IgnoreReason.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/Bans.md b/docs/src/checks2/type-index/Bans.md new file mode 100644 index 00000000..b13d9ec1 --- /dev/null +++ b/docs/src/checks2/type-index/Bans.md @@ -0,0 +1,12 @@ +# `Bans` + +**Type:** `object` + +Checks for specific crates in your graph, as well as duplicates. + +This section is considered when running `cargo deny check bans`. + + +## `allow` + +**Type:** [`BansAllow`](/checks2/type-index/BansAllow.md) `array` \ No newline at end of file diff --git a/docs/src/checks2/type-index/BansAllow.md b/docs/src/checks2/type-index/BansAllow.md new file mode 100644 index 00000000..daf6dfb8 --- /dev/null +++ b/docs/src/checks2/type-index/BansAllow.md @@ -0,0 +1,13 @@ +# `BansAllow` + +**Type:** `array` + +Determines specific crates that are allowed. If the `allow` list has one or more entries, then +any crate not in that list will be denied, so use with care. Each entry uses the same +[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) +as other parts of cargo-deny's configuration. + + +## Array item + +**Type:** [`PackageSpec`](/checks2/type-index/PackageSpec.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/Graph.md b/docs/src/checks2/type-index/Graph.md new file mode 100644 index 00000000..9f34d63d --- /dev/null +++ b/docs/src/checks2/type-index/Graph.md @@ -0,0 +1,105 @@ +# `Graph` + +**Type:** `object` + +The graph table configures how the dependency graph is constructed and thus which crates the +checks are performed against + + +## `targets` + +**Type:** `array`
+**Key:** `optional` + +By default, cargo-deny will consider every single crate that is resolved by cargo, including +target specific dependencies e.g. + +```toml +[target.x86_64-pc-windows-msvc.dependencies] +winapi = "0.3.8" + +[target.'cfg(target_os = "fuchsia")'.dependencies] +fuchsia-cprng = "0.1.1" +``` + +But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is +never actually going to be compiled or linked into your project, so checking it is pointless for you. + +The `targets` field allows you to specify one or more targets which you **actually** build for. +Every dependency link to a crate is checked against this list, and if none of the listed targets +satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links +to it, it is not included into the crate graph that the checks are +executed against. + + +### Array item + +**Type:** [`Target`](/checks2/type-index/Target.md) + +## `exclude` + +**Type:** `array`
+**Key:** `optional` + +Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) +that will cause the crate(s) in question to be excluded from the crate graph that is used +for the operation you are performing. + +Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced +via the excluded crate, they will also be excluded from the crate graph. + + +### Example + +```toml +exclude = "some-crate@0.1.0" +``` + +### Array item + +**Type:** `string` + +## `all-features` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, `--all-features` will be used when collecting metadata. + +## `no-default-features` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, `--no-default-features` will be used when collecting metadata. + +## `features` + +**Type:** `array`
+**Key:** `optional` + +If set, and `--features` is not specified on the cmd line, these features will be used when +collecting metadata. + + +### Example + +```toml +features = "some-feature" +``` + +### Array item + +**Type:** `string` + +## `exclude-dev` + +**Type:** `boolean`
+**Key:** `optional` + +If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included +in the crate graph used for any of the checks. This option can also be enabled on cmd line +with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) +or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) +the `check` subcommand. diff --git a/docs/src/checks2/type-index/IgnoreReason.md b/docs/src/checks2/type-index/IgnoreReason.md new file mode 100644 index 00000000..2b0899c3 --- /dev/null +++ b/docs/src/checks2/type-index/IgnoreReason.md @@ -0,0 +1,5 @@ +# `IgnoreReason` + +**Type:** `string` + +Free-form string that can be used to describe the reason why the advisory is ignored. \ No newline at end of file diff --git a/docs/src/checks2/type-index/LintLevel.md b/docs/src/checks2/type-index/LintLevel.md new file mode 100644 index 00000000..4e4f897a --- /dev/null +++ b/docs/src/checks2/type-index/LintLevel.md @@ -0,0 +1,11 @@ +# `LintLevel` + +**Type:** `string (enum)` + +## Possible values + +- `"deny"` - Emit an error with details about the problem, and fail the check. + +- `"warn"` - Print a warning for each propblem, but don't fail the check. + +- `"allow"` - Print a note about the problem, but don't fail the check. \ No newline at end of file diff --git a/docs/src/checks2/type-index/Output.md b/docs/src/checks2/type-index/Output.md new file mode 100644 index 00000000..3028661c --- /dev/null +++ b/docs/src/checks2/type-index/Output.md @@ -0,0 +1,21 @@ +# `Output` + +**Type:** `object` + +The output table provides options for how/if diagnostics are outputted + +## `feature-depth` + +**Type:** `integer`
+**Key:** `optional` + +The maximum depth that features will be displayed when inclusion graphs are shown in +diagnostics, unless specified via `--feature-depth` on the command line. Only applies to +diagnostics that actually print features. + + +### Default + +```toml +feature-depth = 1 +``` \ No newline at end of file diff --git a/docs/src/checks2/type-index/PackageSpec.md b/docs/src/checks2/type-index/PackageSpec.md new file mode 100644 index 00000000..bb3985a1 --- /dev/null +++ b/docs/src/checks2/type-index/PackageSpec.md @@ -0,0 +1,73 @@ +# `PackageSpec` + +**Type:** `string` + +Many configuration options require a package specifier at a minimum, which we'll describe here. +The options that use package specifiers will be called out in their individual documentation. +We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + +### String format + +If the particular only requires a package spec at a minimum, then the string format can be used, +which comes in three forms. + +#### Simple + +```toml +# Will match any version of the simple crate +deny = ["simple"] +``` + +The simplest string is one which is just the crate name. In this case, the version requirement +used when checking will be `*` meaning it will match against all versions of that crate in the graph. + +#### With Version Requirements + +```toml +# Will match only these versions of the simple crate that match the predicate(s) +deny = ["simple:<=0.1,>0.2"] +``` + +If you want to apply version requirements (predicates) to the crate, simply append them following +a `:` separator. + +#### Exact + +```toml +# Will match only this exact version of the simple crate +deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", +] +``` + +The exact form is a specialization of the version requirements, where the semver after the `@` +is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + +### Table format + +#### Crate format + +```toml +deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, +] +``` + +The crate format is a replacement for the old `name` and/or `version` table format. It uses +the string format described above in a single `crate` key. + +#### Old format + +```toml +deny = [ + { name = "simple" }, + { name = "simple", version = "*" }, + { name = "simple", wrappers = ["example"] } +] +``` + +The old format uses a required `name` key and an optional `version` key. This format is deprecated +and should not be used. diff --git a/docs/src/checks2/type-index/Target.md b/docs/src/checks2/type-index/Target.md new file mode 100644 index 00000000..0b59ef1f --- /dev/null +++ b/docs/src/checks2/type-index/Target.md @@ -0,0 +1,11 @@ +# `Target` + + + +## Variant: `TargetString` + +**Type:** [`TargetString`](/checks2/type-index/TargetString.md) `string` + +## Variant: `TargetAdvanced` + +**Type:** [`TargetAdvanced`](/checks2/type-index/TargetAdvanced.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/type-index/TargetAdvanced.md b/docs/src/checks2/type-index/TargetAdvanced.md new file mode 100644 index 00000000..1562680c --- /dev/null +++ b/docs/src/checks2/type-index/TargetAdvanced.md @@ -0,0 +1,31 @@ +# `TargetAdvanced` + +**Type:** `object` + +Advanced configurations to apply for the target triple + +## Examples + +- ```toml + triple = "aarch64-apple-darwin" + ``` +- ```toml + triple = "x86_64-pc-windows-msvc" + features = ["some-feature"] + ``` + +## `triple` + +**Type:** [`TargetString`](/checks2/type-index/TargetString.md) `string` + +## `features` + +**Type:** `string`
+**Key:** `optional` + +Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) +predicate, but at the moment, the only way to actually pass them when compiling is to use +the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more +`target_feature`s you plan to build with, for a particular target triple. At the time of +this writing, cargo-deny does not attempt to validate that the features you specify are +actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). diff --git a/docs/src/checks2/type-index/TargetString.md b/docs/src/checks2/type-index/TargetString.md new file mode 100644 index 00000000..9972e1c6 --- /dev/null +++ b/docs/src/checks2/type-index/TargetString.md @@ -0,0 +1,22 @@ +# `TargetString` + +**Type:** `string` + +The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target +you wish to filter target specific dependencies with. If the target triple specified is **not** +one of the targets builtin to `rustc`, the configuration check for that target will be limited +to only the raw `[target..dependencies]` style of target configuration, as `cfg()` +expressions require us to know the details about the target. + + +## Examples + +- ```toml + value = "x86_64-unknown-linux-gnu" + ``` +- ```toml + value = "x86_64-pc-windows-msvc" + ``` +- ```toml + value = "aarch64-apple-darwin" + ``` \ No newline at end of file diff --git a/docs/src/checs2/graph/README.md b/docs/src/checs2/graph/README.md deleted file mode 100644 index 8dc858c5..00000000 --- a/docs/src/checs2/graph/README.md +++ /dev/null @@ -1 +0,0 @@ -# graph diff --git a/docs/src/checs2/output/README.md b/docs/src/checs2/output/README.md deleted file mode 100644 index 2580f631..00000000 --- a/docs/src/checs2/output/README.md +++ /dev/null @@ -1 +0,0 @@ -# output diff --git a/xtask/src/cli/codegen/md_doc/rendering/mdast.rs b/xtask/src/cli/codegen/md_doc/rendering/mdast.rs index 5be4ca20..9ee3b2e1 100644 --- a/xtask/src/cli/codegen/md_doc/rendering/mdast.rs +++ b/xtask/src/cli/codegen/md_doc/rendering/mdast.rs @@ -59,12 +59,26 @@ impl<'a> MdNode<'a> { return; } + // let tag = Tag::List(*start); + // let end = tag.to_end(); + // visit(Event::Start(tag)); + let mut list = TagGuard::new(visit, Tag::List(*start)); for node in children { + // let item = TagGuard::new(list.visit, Tag::Item); + let item = list.nest(Tag::Item); + // let tag = Tag::Item; + // let end = tag.to_end(); + // visit(Event::Start(tag)); + node.for_each_pulldown_cmark_event(item.visit); + + // visit(Event::End(end)); } + + // visit(Event::End(end)); } MdNode::Paragraph { children } => { let paragraph = TagGuard::new(visit, Tag::Paragraph); From fc2922ef58d38df188c6b40f6cd53de265ea4058 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 29 Apr 2024 23:38:02 +0000 Subject: [PATCH 14/20] Try docusaurus --- docs/src/checks2/type-index.md | 9 +- docus/.gitignore | 20 + docus/README.md | 41 + docus/babel.config.js | 3 + docus/blog/2019-05-28-first-blog-post.md | 12 + docus/blog/2019-05-29-long-blog-post.md | 44 + docus/blog/2021-08-01-mdx-blog-post.mdx | 20 + .../docusaurus-plushie-banner.jpeg | Bin 0 -> 96119 bytes docus/blog/2021-08-26-welcome/index.md | 25 + docus/blog/authors.yml | 17 + docus/docs/intro.md | 47 + docus/docs/tutorial-basics/_category_.json | 8 + docus/docs/tutorial-basics/congratulations.md | 23 + .../tutorial-basics/create-a-blog-post.md | 34 + .../docs/tutorial-basics/create-a-document.md | 57 + docus/docs/tutorial-basics/create-a-page.md | 43 + .../docs/tutorial-basics/deploy-your-site.md | 31 + .../tutorial-basics/markdown-features.mdx | 152 + docus/docs/tutorial-extras/_category_.json | 7 + .../img/docsVersionDropdown.png | Bin 0 -> 25426 bytes .../tutorial-extras/img/localeDropdown.png | Bin 0 -> 27840 bytes .../tutorial-extras/manage-docs-versions.md | 55 + .../tutorial-extras/translate-your-site.md | 88 + docus/docusaurus.config.ts | 133 + docus/package-lock.json | 14796 ++++++++++++++++ docus/package.json | 51 + docus/sidebars.ts | 31 + .../src/components/HomepageFeatures/index.tsx | 70 + .../HomepageFeatures/styles.module.css | 11 + docus/src/css/custom.css | 30 + docus/src/pages/index.module.css | 23 + docus/src/pages/index.tsx | 43 + docus/src/pages/markdown-page.md | 7 + docus/src/plugin/index.ts | 28 + docus/src/plugin/source.ts | 364 + docus/static/.nojekyll | 0 docus/static/img/docusaurus-social-card.jpg | Bin 0 -> 55746 bytes docus/static/img/docusaurus.png | Bin 0 -> 5141 bytes docus/static/img/favicon.ico | Bin 0 -> 3626 bytes docus/static/img/logo.svg | 1 + .../static/img/undraw_docusaurus_mountain.svg | 171 + docus/static/img/undraw_docusaurus_react.svg | 170 + docus/static/img/undraw_docusaurus_tree.svg | 40 + docus/tsconfig.json | 11 + package-lock.json | 6 + 45 files changed, 16716 insertions(+), 6 deletions(-) create mode 100644 docus/.gitignore create mode 100644 docus/README.md create mode 100644 docus/babel.config.js create mode 100644 docus/blog/2019-05-28-first-blog-post.md create mode 100644 docus/blog/2019-05-29-long-blog-post.md create mode 100644 docus/blog/2021-08-01-mdx-blog-post.mdx create mode 100644 docus/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg create mode 100644 docus/blog/2021-08-26-welcome/index.md create mode 100644 docus/blog/authors.yml create mode 100644 docus/docs/intro.md create mode 100644 docus/docs/tutorial-basics/_category_.json create mode 100644 docus/docs/tutorial-basics/congratulations.md create mode 100644 docus/docs/tutorial-basics/create-a-blog-post.md create mode 100644 docus/docs/tutorial-basics/create-a-document.md create mode 100644 docus/docs/tutorial-basics/create-a-page.md create mode 100644 docus/docs/tutorial-basics/deploy-your-site.md create mode 100644 docus/docs/tutorial-basics/markdown-features.mdx create mode 100644 docus/docs/tutorial-extras/_category_.json create mode 100644 docus/docs/tutorial-extras/img/docsVersionDropdown.png create mode 100644 docus/docs/tutorial-extras/img/localeDropdown.png create mode 100644 docus/docs/tutorial-extras/manage-docs-versions.md create mode 100644 docus/docs/tutorial-extras/translate-your-site.md create mode 100644 docus/docusaurus.config.ts create mode 100644 docus/package-lock.json create mode 100644 docus/package.json create mode 100644 docus/sidebars.ts create mode 100644 docus/src/components/HomepageFeatures/index.tsx create mode 100644 docus/src/components/HomepageFeatures/styles.module.css create mode 100644 docus/src/css/custom.css create mode 100644 docus/src/pages/index.module.css create mode 100644 docus/src/pages/index.tsx create mode 100644 docus/src/pages/markdown-page.md create mode 100644 docus/src/plugin/index.ts create mode 100644 docus/src/plugin/source.ts create mode 100644 docus/static/.nojekyll create mode 100644 docus/static/img/docusaurus-social-card.jpg create mode 100644 docus/static/img/docusaurus.png create mode 100644 docus/static/img/favicon.ico create mode 100644 docus/static/img/logo.svg create mode 100644 docus/static/img/undraw_docusaurus_mountain.svg create mode 100644 docus/static/img/undraw_docusaurus_react.svg create mode 100644 docus/static/img/undraw_docusaurus_tree.svg create mode 100644 docus/tsconfig.json create mode 100644 package-lock.json diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md index 4edfa85d..9ebf3ff6 100644 --- a/docs/src/checks2/type-index.md +++ b/docs/src/checks2/type-index.md @@ -2,12 +2,9 @@ This is an index of common types used across the schema. -
+ This is a bad thing that you should pay attention to. -Warning blocks should be used sparingly in documentation, to avoid "warning -fatigue," where people are trained to ignore them because they usually don't -matter for what they're doing. - -
+Warning blocks should be used sparingly in documentation, to + diff --git a/docus/.gitignore b/docus/.gitignore new file mode 100644 index 00000000..b2d6de30 --- /dev/null +++ b/docus/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/docus/README.md b/docus/README.md new file mode 100644 index 00000000..0c6c2c27 --- /dev/null +++ b/docus/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +``` +$ USE_SSH=true yarn deploy +``` + +Not using SSH: + +``` +$ GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/docus/babel.config.js b/docus/babel.config.js new file mode 100644 index 00000000..e00595da --- /dev/null +++ b/docus/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/docus/blog/2019-05-28-first-blog-post.md b/docus/blog/2019-05-28-first-blog-post.md new file mode 100644 index 00000000..02f3f81b --- /dev/null +++ b/docus/blog/2019-05-28-first-blog-post.md @@ -0,0 +1,12 @@ +--- +slug: first-blog-post +title: First Blog Post +authors: + name: Gao Wei + title: Docusaurus Core Team + url: https://github.com/wgao19 + image_url: https://github.com/wgao19.png +tags: [hola, docusaurus] +--- + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docus/blog/2019-05-29-long-blog-post.md b/docus/blog/2019-05-29-long-blog-post.md new file mode 100644 index 00000000..26ffb1b1 --- /dev/null +++ b/docus/blog/2019-05-29-long-blog-post.md @@ -0,0 +1,44 @@ +--- +slug: long-blog-post +title: Long Blog Post +authors: endi +tags: [hello, docusaurus] +--- + +This is the summary of a very long blog post, + +Use a `` comment to limit blog post size in the list view. + + + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docus/blog/2021-08-01-mdx-blog-post.mdx b/docus/blog/2021-08-01-mdx-blog-post.mdx new file mode 100644 index 00000000..c04ebe32 --- /dev/null +++ b/docus/blog/2021-08-01-mdx-blog-post.mdx @@ -0,0 +1,20 @@ +--- +slug: mdx-blog-post +title: MDX Blog Post +authors: [slorber] +tags: [docusaurus] +--- + +Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). + +:::tip + +Use the power of React to create interactive blog posts. + +```js + +``` + + + +::: diff --git a/docus/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg b/docus/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7764c538bdaf30cc40daee547867cc0525285296 GIT binary patch literal 96119 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 +

My React page

+

This is a React page

+ + ); +} +``` + +A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). + +## Create your first Markdown Page + +Create a file at `src/pages/my-markdown-page.md`: + +```mdx title="src/pages/my-markdown-page.md" +# My Markdown page + +This is a Markdown page +``` + +A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). diff --git a/docus/docs/tutorial-basics/deploy-your-site.md b/docus/docs/tutorial-basics/deploy-your-site.md new file mode 100644 index 00000000..1c50ee06 --- /dev/null +++ b/docus/docs/tutorial-basics/deploy-your-site.md @@ -0,0 +1,31 @@ +--- +sidebar_position: 5 +--- + +# Deploy your site + +Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). + +It builds your site as simple **static HTML, JavaScript and CSS files**. + +## Build your site + +Build your site **for production**: + +```bash +npm run build +``` + +The static files are generated in the `build` folder. + +## Deploy your site + +Test your production build locally: + +```bash +npm run serve +``` + +The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). + +You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). diff --git a/docus/docs/tutorial-basics/markdown-features.mdx b/docus/docs/tutorial-basics/markdown-features.mdx new file mode 100644 index 00000000..35e00825 --- /dev/null +++ b/docus/docs/tutorial-basics/markdown-features.mdx @@ -0,0 +1,152 @@ +--- +sidebar_position: 4 +--- + +# Markdown Features + +Docusaurus supports **[Markdown](https://daringfireball.net/projects/markdown/syntax)** and a few **additional features**. + +## Front Matter + +Markdown documents have metadata at the top called [Front Matter](https://jekyllrb.com/docs/front-matter/): + +```text title="my-doc.md" +// highlight-start +--- +id: my-doc-id +title: My document title +description: My document description +slug: /my-custom-url +--- +// highlight-end + +## Markdown heading + +Markdown text with [links](./hello.md) +``` + +## Links + +Regular Markdown links are supported, using url paths or relative file paths. + +```md +Let's see how to [Create a page](/create-a-page). +``` + +```md +Let's see how to [Create a page](./create-a-page.md). +``` + +**Result:** Let's see how to [Create a page](./create-a-page.md). + +## Images + +Regular Markdown images are supported. + +You can use absolute paths to reference images in the static directory (`static/img/docusaurus.png`): + +```md +![Docusaurus logo](/img/docusaurus.png) +``` + +![Docusaurus logo](/img/docusaurus.png) + +You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them: + +```md +![Docusaurus logo](./img/docusaurus.png) +``` + +## Code Blocks + +Markdown code blocks are supported with Syntax highlighting. + +````md +```jsx title="src/components/HelloDocusaurus.js" +function HelloDocusaurus() { + return

Hello, Docusaurus!

; +} +``` +```` + +```jsx title="src/components/HelloDocusaurus.js" +function HelloDocusaurus() { + return

Hello, Docusaurus!

; +} +``` + +## Admonitions + +Docusaurus has a special syntax to create admonitions and callouts: + +```md +:::tip My tip + +Use this awesome feature option + +::: + +:::danger Take care + +This action is dangerous + +::: +``` + +:::tip My tip + +Use this awesome feature option + +::: + +:::danger Take care + +This action is dangerous + +::: + +## MDX and React Components + +[MDX](https://mdxjs.com/) can make your documentation more **interactive** and allows using any **React components inside Markdown**: + +```jsx +export const Highlight = ({children, color}) => ( + { + alert(`You clicked the color ${color} with label ${children}`) + }}> + {children} + +); + +This is Docusaurus green ! + +This is Facebook blue ! +``` + +export const Highlight = ({children, color}) => ( + { + alert(`You clicked the color ${color} with label ${children}`); + }}> + {children} + +); + +This is Docusaurus green ! + +This is Facebook blue ! diff --git a/docus/docs/tutorial-extras/_category_.json b/docus/docs/tutorial-extras/_category_.json new file mode 100644 index 00000000..a8ffcc19 --- /dev/null +++ b/docus/docs/tutorial-extras/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Tutorial - Extras", + "position": 3, + "link": { + "type": "generated-index" + } +} diff --git a/docus/docs/tutorial-extras/img/docsVersionDropdown.png b/docus/docs/tutorial-extras/img/docsVersionDropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..5605246062fae55439cabcf96ed860e1e5f71df8 GIT binary patch literal 25426 zcmXte1yoes_ckHYAgy#tNK1DKBBcTn3PU5^T}n!qfaD-4ozfv4LwDEEJq$50_3{4x z>pN@insx5o``P<>PR`sD{a#y*fR+FQ1A|!ot;$CX3{3aOiysgB@lH{bUGwAD6I(?s zMGTC(L_&l)&SM?Z4Z`rm~_BGD)`3Wa*Cq5mr=6dHYX z1%X^$ArOei+7;vq4u?Y^kVmVB`-jKJmzNMI6ngtuZf+hP;FlK{*VotQ=jV5KcQDvJ z8ij;jLC+q`>FHx=Cfp~x; z9>XFY5GXYA@bK_4#-knV?hbMZxp)k5a}9rZxW2i4G=2m?B2d@YHz&uZ_YV&j=a;K% zn>RN%_xG@)qa)}Q1c5>z5%ANqvz4_C6cTX3yUjgB>K^6YG!_Bc42CI?)?1X5(3%Z z-#qZ4t9Tce|CQUsMy`@-OcUI`o`A5!2y4$?%ezm z40gA)ybedeq1Vu( z&F$^N(kj5*a%X4f{OpW3RCj54?ez3yd1d4L;v9)W@<-?|uCAL|Sb@Rd$*EZ+3Jrx` zE&gY7wz9G1<>fWAuyk>GxwgIqfk3C`7GBUZF08EI-d;cIvbM3gw6@8>$Z~LWu(7rC znA^j{JrsH^6rsPoz9}Fm{8s&4|KNz6g5vGX?PJ>PFS#L*%W6<73W+^`t-W(~ZEJ94yuP8))y*Tnx5}aLn_7~!sfG3T+MlI^4Zk{z z56_MbGuS1?ybhez> zC+Cu8wVaUK@HB!e{(;a&iB11z|c@$`@?4cAxNXQGn&<;yCZZ^y=o`Md?PAq4`Bl*0Mt8iGfO=-8%C$y*swaN<;Bi@(;{l(1Ntfx%s>4X zh9_31WaCC0wXL7Q7yMOUl_!7sA6d=`)O`l86fKMxg-5Y)8>Yz zkbyX!EJuhXIKi5LzTB3%kI2P3@k`A>V!U*9^S(v)?V4doGfFp>iPT3^uwf@wkzMYU z+Um~GU~XD;k9H-Fq*dhcpVEQEXaj3L5N>0V*KXI~FJ;#aaBpHu2ILL7o8w35+uYVTL_*f?wDZwa`o2z+-{^e7 zOj%(CcZf@^2N{)a0-r2<8hx*-*1Nz8LapbCtNX}fkx+^YZp`u24>N@U$y--?R|nBP zBqf^!K0E>^i#`?jY`P4WbOQ9PrM)y#SLA#@cRnNrkX>u2e!LF!y+3&5)h)VK#;+2z z=-!X$NXQ*^l`Nw$O)~7;ch7v@oeLd1f$_d6vovwPU%g*X`gL|hIz&1=sU**WdePWn2<+p}f=KD1jNi6#2S6}9L?zXk0 zc2#rRuQ^h5xfLo;J5&~^wlSj_c_?UF@lDMUYW>?{#)xNY5hg6QN1ML|_{t5(jpp3& z=iVrI<*V+KC68l7n(-tWBi?tsguDzo;f}HSO{NzXBh#q6c1)VbEE4gj^d-azq6~?j z86B->wt!f5`jarpSZ}WukgP!hQi-fW!Rf9v$vb=~z81cr%Gt$J%`fNv-u!xmiJqY; z6+d{0f57zBzUF;pBreol-r0X%h?F>T*&lPvYCa-(|@F-f7PkHR?2xG=iN0k*CY7s{uScVr(RpAO;J1L*V!dw!D_q( zm?GlX3Xpvw{nL(R!)HWAHZDWTl4CY*Z)qsYTGDc9fVYRQBy1>}Ne&eR>$=&a)U!V) zNS$pnE;rv{8RB8f%A2{KgS%c!SxZ@~k62v4R&NNTbjVFBvngiXas!jbqk|FW5AH9E z7*(%4xu~?>-aOl9{z)UuZFiNp)J$sIHuhGg-ZT6>zFub0QN(7sMMbAUBFG=sJZ;MW z008(?Spe_To@VmUs?O-g2pdwk^Kf`?pJK(}Qd#*WRL2`q0|ZNY!h~myQV#yt-2*QD z_o|fiBt>4zZ_7D$&lJ&b&2q0n1dpA-e(y%r+y!}--zIvLEd8ka>0CkH8Tb+=_pqiR z-`@4bBaL~E3>6ys&fX!Yx;7&0D}!y5KwJ~~MsWu-;jbYM(7Uv>ht}=YYrh}CYhzy} zzASms73@X}e<%@o_q(X6f{=IOovXO*3qQ9)Pf6aKAfL+d?be;B>6*cKb4<=~F7AXU z0zdaYq#(=)#Fa%-zhrP+$B@-{fWQ*kqeLZ6;m-g1WC9Su4^C4w>`W=i+cSk+Gg{@* ziFbJX(bh8uX4aZH5sby^j-gzGgLtOVdo+U+43W5sWICbh3ak3hiWH|vov-ro4o#Ud zLhvRMM7x5n+m$yH8n)C`ZcRTrmU&v)pA$B?#<3X>cvxzoST%;jN@;P6@Qo?FpF0m` z-dfT+ko{8L%*g`C!(MN7+XfPMY00mg&n&XETfVH1(tDtKrz%p6oAdFtRu8ujRg7rN zas)q=h$O-tw<(%NQ3&6eSvn}rQnc3dqv3BJMuFfZm_x^Jrs6zCs*a|k6ZVU7V?jF_ z)=X}_%~xLk1}PJ5co_Q(t#`#Wu{1Aq{fU8JZpu7@3TqXC580)5&r+^#IgyC6E%;z} zm|Pbp>tKM0V)Nz2%;N6`mFFkgX{Jx0h|rs4Z;oB=chI61kqzZ!@Pz8vj!S%-yQf)5j*c8(W$$o2^=lQDA`+&yx<}P9ml7l%vR8G5WK6u$$28mL#i>p)5&t5f( zL}=FPvQh82(tqkXrN(`;@&yMo4DYn36za9|-Xf2^zjQ+7llBL{YrXTQ7p4BwdC~s{Y&T7Ul`?9E`Hi{+i{@DNRT_ zd*HLku)V-%JMFybVXlG<;cuSv+4`ve`+iEp^r~cn{E|Qb=ED#0+aP9ulbc)by6g@YlsTb9qOX$7JBJ*j*iA743 zDsOMkme?1RF!o4DM_y;vxZJF4O0sCjKik?IqKWhN@{9}9 zvKiR*jp3qquW_j#*A|;2)+h1D2==#zy(qQI z>w-hh9B;QzK+8A6;RnFTu={+&r)ZdPzzr0T)WRpPgd3cztxV+Mx7vA{x0aU!)QNt^ zl5pVSoUtx`kdd)2|JpPk4ULEN^p0`bipV8}*g?!_f@1Q20~vd|n7;@N@oX9b&wc%< zSFyBA(?6`j==ls zfKZ*gU1I!&tE+I8vzm4O?Z({jMBHX@pSQD2#qtD7t?DMMCEnJ&K{+N&@=0iNeDaE5 zWOnK}CEN2!2~{&iEKUi!YBzJLMS5NmTS5^*ys#$sy}^OjHs@F3xY|5SV???yNK#nS zW^{&0o}_Suc(=A+1jye{vM;-fQw%i81Scam?gB!(?yenJAzW~moz!^lXaK$um@ykY zqq5yzCodb-$R^n>R;E=HU*(iGUrDj~-UilKWaIfXSMlWL2o&NeqLknpMqmhy`82J+fkP*sAH z6ZLm%Wtj6X`8PfRh{=V{3`Y6mH?#tBga+i}5@M5saZU^Jj(ulpAAFfW|htC`|gBy;b(jumo zA!%ZM8`g?W>H3q#tikL8haT_l?moe)Z-LlXo#YbZz_+-ZpAR_9VL7`ZAF_c$xvu7a zdHNjkExleb_)9V{ztL0@J;S~1yCc$BsK@|Az((Z)d$)VDy4#6YdIFX*K+{N5vnVl= z+?wbFnnmqi%k^9GMUvD_ls?nLzOjSZ>DX zorBVn0n7$I>GApQWlYcJP=TYC9**jdpVqw?KkjhLm7o7fn-|GVV!Qr>qyH9wIrQ3% zK!*R@;ikDF>!;p+P^o3l3k8t6YlweqN>nwUnpyjHU5C!;_(^wCV4s}HRiF)!pQ$Oy zc&XHRr(taGMet{y%X75Ah>|FZt6nqr&)AgSQ|wNsc2**xc* z(g4u3^Xade{^We#AC7VS#oZu?u{XWq#wn~0kyjpc=aq>P3o z-H6P*4(y)>ZB-q6w9Z5dUXx9>B0UY{Ju*-?Kg^wMchgLSWV@X7y09eAS95Fm#4(gs zprMYm1482a?x}UWKzhFS0k9jizU};7*l@R~W0glkvlc~SC^Svxsi3-yli&A;+GZYy z296cYVg1G}b!vg)g2>nOsdGWV$e0}V9|OI$w3cG};OeXBEPM=z#I40-3^M;>RgwN~ z?_w$jTOa}ZRa3A@YgI@Q;Bfi;V~7-7U^wG8Rgni?(N@77IK^^iK%F!DGo$&}r7{2f z0xXZ|XV3d{gdC@}M@`dTKIoP$3@yy4T9_tkDs0VcTjl+}9TGt3FWG2@()hC>YSs}M zTTv8Rs%t$F`CLr_YN<0n#hZ%_N!(*W_7@NG$ zPYhx83EjI1?9_5!vTb+9Na;hIkF$dU91EtZsmouRY|nmV%hcOXUad-rV|195Fyrjn z^AL4k&dYJxvkDP4|MXgzIl)tS>v_~G16TDFSd}+b@=xY&?qS<{gfBk$5<9;`5L?Cl zS%5q+AtbJ|i{|q+J?KI=NZv+nvL%M;y|Z^fNp!~WDcJEL66~Wj6bIQ5LUN)0?!JEs ziwoZPhz2CJyY@|!#EwtZqs zoMH1~+J2u}aZLo?>3l)aI+ALsx}T9gJAmo439T#++PRjnzCFovjzy~1Mo((GlrI-< zsZH&@B=-?mU+T`w&NnSMTHYgmW|NL1#rr-eX+p&oH*QZ^BYo$j_>Wn%SNi0?W9ho6 zk2rU=wNDe}6(;jsLJNU;lC?#2#9Et2Go5D4W2tLb*E2%x6SjN7%~2=FRd&D%ZUvq3#vdwYiNh|gb?`+4{+u*9v{Fzfv-)t4G z<`Z&HD^iiK)t;ny>}V|F?jij|v^V}C7>2tQxZS6gb7(7Zb!Q_UdKG6|eh!}G@4yRA zsGK>w^9N=?AI_bA4t)atVT;5jT!OsI>$s-a z6e<~HQdK48w3HIv&u|eSwhR}K6zT_C!IIaW6L(kA^G{e7cOSvEC`=dJ$UM0kWc z)rVktG*ZbmyznEEE_wk8174Ko^vfA;x32*6z+&npxhvI_p9i1#`_Ea58oJ8b4SNpG z@TPAP9PYVc$R_m-UE~*d4A>lupWGp~O1o)gBH3h^dZ{f%m}sYK?_8H&|EvOpt$Fqj zWNw=SM>@dyBC*I`J1jHOm9D{3g_((ELw$08!c)r-KuOz+E)eoaQrm(Z%ZgQ#+BDfN zG?u9N@DHsLyY|{$#DK7uJj;tq^s8t(#jmDvAE2qTkXX{>Um`IjY}Tt^a<2vht=`}2 zk9-ec*FGmYLcUcf;ZUD%4qvW;;5*)yv=LdiBp23iiI@dM2rNZEvP*qgww8kG3N5y? zv)2aj>3tA(Y6Sct|Mz+2DKFo`uf2u~PX_3GVksJ~L32z3H4w0V4}-Muo{EC?V>{ce^r^_x-eC4KaP+e}*S)BQPd{6u)tS0eiVn_kHR_z== zbpSpdEKihVy(Dr^4Z&Y3UBW4fEYHF{1#QI!SP2J8o_&PRdf1~ydsMND>>xbmlCLoK;@|X~EX~A}eIbu1UV{6f3bZOIu%H+Z&<5Blz zKvnXb>r+XP&6S;f19*>uDD4J|H`*zZlpvP;0zMZp88!9ehASrDzB5SJMMRrcjgzxL zCf=@5=g>k8TJxdH4#@J?$F7@sQl#Qi-E*Wjuf0D}9AYIOS>kl=0z74@+cNwb8{xQv zp~zk2uJQhFdc%8T3`qoDclef)VrF?DO}xJcR-)OPEjbtE*+ArBc(oFePVL4U;tZ)Z z>{p+-=@ZNIfta`dC^YRbxzf1-_Eu9=;^L2clE9*dU+XI0X#cTsYaHa&>@&-HCZ8$TXQ?5qUmXS0Z4=8tVkA5ia1cY@g4fidtX5ZFjsp={(yCkWF zPWlx7f+ZQi?DtQW&kM3vcKLCt>c>mm-!Ct9n@%`+{OrZF(zqC=m;1}Nnu2fhFJ+{S zUeey(JPWUuj2iy+`3sLv1s%-m6R$J`beAT^$5V**>nCPGAvdX?QO=0NsjeHda5Ary_ z4_-@EvFr!^iiY0Nq8AWdIcQ6G47S;E59&OIM$>>~^R0K?v;kf4CD7BiHJ~UQvwK~3 zrp7_jD!3cIcaNM+%)ZFm*c4JU2bYAGAG{~0+%3r!9<85v+(8$(FYdA4*KGZHV)jgf znxIu_#*Wh6u*9%an+UY1$?>sqIj&f>?kG^o{&3cBM&!VAkX{>xKg2W%kR?*;-Xgl{ zl%WS+tbaS6{I&4y18zeCj2^XYXsyfJ*%l$lgK9_rxg8giMavz|ioUthX<5I9BWKo+ z2O~#c8|@Ty@!@xo{Q=WGqm+OSG@L{ zE^%g^S?PCaismxO$zWhLZe#xW?C#qq*iz>rYfpnD(7zy2_XAyG=%HH{7;9E=Q@3=B zWGXclGK`6R#$~wAWsO+2e_HFDZav_^TL)Mj-DS)k$du8Pkp6BB)5t>MU&ZW&2$@iJ zeG-W?YbPRZI-JzlLVHF%1xnCA@}o9$P<4d+8Rg}@Xa`o|HvkkDnN@9v8G^yYfyLHc zavyT;R{8Coa`0E-E?$M0D91!w|(}ZYB;q-jy!&aDiO>N^T?Q zNvVt9gO>rYS}2yRb#T9=z0^dBFJPFcd+jG9wuf#tYuV~^O@ExfGX%3rL^%@TrQz?w z8oxdj@_SA()0pvl4k$v;3wTaCLpcE@v<#WO>4uz`oV#LJlx5I5LmI=gMV zGSfHRar5E9XUEw5_E!g!j$-jgCi7wyBmF%h(wvv5aHg8~n5xj`dDDlUcIW56+e}F3 zOwlr60I++1ne(54U;L81GSVL#=!;T}R3wo*euZ{={~Pk*IsvaJFW5w{jXAyaGi#z* zF!ugM>2mR@Pn$JAja;v@fIGNWQ3%AQ@RIJMN*uXR^lkpv5G}e0!TAjQ?#)shM>gyR z>P%)$Fr;lp4C}?JuTzw%f&HMxmCo};tlvLh)-Ixof}$fOo%&0L1=U7_tuBO&ZU+Lp zXpY7vSaFZ~Y*N3{pl=fAY`C{H(Q*r=4tXf!a`?ylKYB`%^Xd%_pYmi=OK8`LpR)b_ z{cU(}Otm~2!*7y8K$4SbttyNK8$)xwdfqnFI43jSo7ZP zdw{|b4UrfRhDMsd3O448Cn6rxk&@fqzQSd*Q$)c!-m9^P=PIq+2Mjff_^ApE z2;DM$N9hROp^T}UpNy9rvT&o$`iLY0)CV7}4&*$Jc^roNqwLsihS${_GU0 zUr*SF+ZbA|`1IQZyJZo&#UpC2xKWY&TLr-9=1Ae5oFlnDZEStMFc{a)=Jj~fGOzn5 z&*!s&j}%sdX9?Bo^;8g0VEff z^r54~cH}~~mFjS2xbQNtM9UQTJO0&`(_|7B+MV{08;^O@6p|FqX~?FjW@wK8#FI&4 z<&U*JOW#*)%Ck!esh)Sl7w0yT9v3Y!HVup$zO4+CHei||2u%M=LMpGo-R><`sVrgX zg&@iYstctddb9chMWW_F#b(L2t!M#WAq8eb!zWp&35AOIC){=HXZVprGk;VhFmUX9y2*0YZT~8zYt()A=7fA|CDcQGr49ut60^>bOY$knb7|Q@BakQ zY5KtSYOO>wY;u#{pO0p`G*-gc<7S>U?B}}Z6s!^+=VkMoi}>k~W8AOMlaJ5)7FC~? z)=85}NtJ);+q(TICRU^JW zD^q~vA-6m)V~=A*mz-Fql127`(;?+$uLk~901O^HQKkG^N2PF=gijijkScn-L>gNX z3bzs<9+j?~b~h>DgSaU!B&TjAX^+2uI$-+rIU>+)Y~G(`5;Poqx_RVMTWpax%B+;iXT<8OtpZUlW>ZQq@vq>D}q#nb*9&+>k#*q0A>(}2?KTu*>h zipdPQG8;e-e*vEbYb(-^<^xpAwx^_qCgsK@m!mKbq#?ic zO}Za^%uk>pKza-<4P4M6v97inekHpXZ$(AQqRdS z1CQ!^QXH*Zl+ZzIj_zA2@wGSlt3UT%60l7-zY1!rm<$O$PL1b1t}v3QqW5IOWu~&- zdK)Xpi6^cWH=V^$`CE!HiU#kcX;;NQ#pY^am~^5}r2_`emXS*pg~R+pR%{22MAcbi z`J%q@=OCHj81TU79Jx!Z3()N3&>rp$yqgJqdxt(i{8P+FGE`$Hy5DXi4h?@G({C3G zW2Fcknyf_lUMN?-wpPX$j9RtLT^|3Ywcf}T@>6bo{y-i#BSQsHWy~Y%?C{a_ANwY^ zW^0%}cE6K}F**3uf>o4ww)`+6M%*xobDkxm*gDtPqL;(qZpGMvfw~g7gQ{|Xe_mwr z9LK$Q11JFh|FZzETlS+8`ff@ctbT)z!S|$5jZE)0RpPCJr zex*egid(#_7-(fHCsGp={BubzC%_%_(7h}TTx_a;l>p!_4{l8c(07+6=Y;{pzVGPq zW4&I`O}qM%c=`=@NKh2Zjv|ISrOKaICyp|VI)RElzJ^O-e3qL2;K01NwC+LdF+Y zM7gW)!EZ)?MbAu?cDn{ng{*d%ZFHFT%)~QwBX8F;SgV3-0rv5@vE-1m{?bGWpxpK9 z?+_B=I?jHbS^PY`rDO$)oSiA@Us>omM}BkzYSr^3(`^=5++B+HPw5?))zgG;Q|_|| z=fbXEalt}zpzXu9fNXUA&BjbfbqEF9OJ@Bd zlMls82r0->|3S#rd8(oqfVNbY6SDYEj7v{FNck?iH6CQRE|N5O_L~gK@^Mq{m9g_ySMegfvE7Dj- z`#*yAj@GAL41rRo z?aEKqpNU$TK^5Zv=~!Z0ewVXb6+K^zRO%#mk5sbrZttEus09e}b!MQn9YqQyim=bIvV*?cF-5%B9|kO%Wa3YSH(!N zyM;^=6l3wE{EGqu^askH_j(yON=e9=&}0XU>4=MCq;Kff>}P2{=_Zjw@}CmQ0SV@8 z2W_7hq|N41Gm)UOki;~%f6>O5BWG^KcjA1V-4ozJ#y&l z0ldzh)ui_|{y^5sh3Y;rQA~MMDKqsup!725!fSzN$YBf0q`i@q`GU#TRn!fO^CKj*zfy!PMB}20;_M?;_SS4&r^<(Q_6fEh@=+rkRnG-NffIY>TQw0A zOMg95&oq8WuVQLk6cg6^3F_g5ka{<nt)tE5kC7gHuDEK}$Eiooz}WvEVkZLqCkfm}9N_ zE*%Hn5Zi~li||?%y^foiN#b^ETTs!c%dMXJ8|Ni2x*?d zhceiFS~BG4?d&$4?IY`PXpY}EgK}L(;JgDT#K~l3nr{_i9^-nnCe3Ews#4px4UIAS zN>$XB-jwZs|5MZ$Ge{u3u1QM|?g#8e*Cus&r z9J@Zpt;kz&`vIDPpFFrSv*2xA41CaQc~XX{jB`{)))hENq{bhag)L^Qbcv}eL<8_x ztImFIA&e@lHDA@?dQ@^%WZ+eypM9$nXAY?{V!1bZpho07Di? z?%cW-WovCz?2nK)lkx$Iq|IE-r;Gd0oNiddcvEvmQ!~&7Jno?zpvko5YAKYj(lIoz z%_K1v7y3vBkmdcdP;Rrt*3K@h`z1=St|uki*T$CfrHweOp|NMa`ZT`qWUOz`HR#gt zLG8M@*vWY$I-1z|ldu4DXMKH^jPa)Nro}@m4=AQ1s{`rCYZM8wwPiTNS)NVn6{3k+ z=vtTwIHp*OT$|9W;`N^ z#iXLM`7~orv_@=TtJpQ2`?v9$v5nWZMXhYU{%HumShl476ubJHE^O;3)kK2Xj1z?k zu9!D^)bhcSL3htiINrsQ2g-{O&@fU>A6w!^wD3|nep=>|rkEl0R~ew+G--lCKt~la zn#nXUMv)}yUY2Zw@QVahaH;f6nMiK|@8ac(BfjR9$N9*emG$P%kU;6Hn2wAOcY2J; zcy>K@HDcMuJhZco1$wR0y|jf|Hg_CPSeVMnzK@x!=4Chh2R?dru3MSE)(}oXM%R!i z)^8@Vmk1~P`1_xdMbh#wSML&BJy~WDC`Q-@0?wFCC6FO(_LF0pAYh?H81#Vj5r^BO zXWvt*;_xdO)L|x}KP&Ej%2s7@l2qSMHrn{{)LnN@g8L29OVUFwcOHs` zM+nb-FX)SloWAFE5d`w}B1c^nWB~w!ru5X2`hi4%wg9I=^HkK6*+9b|Mbln&WFkC! z1Zx?qQ)brYilt6dsI{eI#pVCR%}71$X9j)7^unA)$U#3%TYY%-AnNQ6nCCB|co3x4 z3I8z?R#!%Ne=M-kh14joLSNrjeTD3qJT$CUSX-mZaz=70zBhy?HNBSp-tu)KFmCXx z68jjZpMvbqv_fRz{MB4U;7yf(Cu;E)ZgA7~xH)BjL541B@Bm${nVLMHQASbNKR7U5peswzD{GJD zYH{*J@IGw|1lqe=A|oBY6P{z?;l-2l28`KFGd}=z;hm1A@&={%6COUIlKT8Ero#q_ zmXGe8&WAPBC+-?dE3g9G5UrQpw1M}$zP0Z0ne81Z$UniS{I&vbc@pVzD?UqM6er5>_+c4a|9bDdKnD zT10Q5k;$IUSEW(9acQ;~5tC_UB7LGW4{5dYzFyRj|rLsQDg>R#EnyveXZ-)`OodUAv6Z&R|#wzRJI zoPE7TR$9|AML8LzyxtZcR)jyos)oDa4d~N*QUc4{;vb)4_@p*IdA@eh9j`BEd=mZV zy}3yom-36GOkTjS(`kmdHRsiy0Zi~Nafyg=5sSY&$zZ)o^-HzLPhKvSQb&iJS$?W(PA%D-nMP`{Sx$56lnN` zJw@-ZZF;cd3#O?ZX3bJlPFN>b|qP%l-)(+tQ!J3|Qu0Evc;7(u~ zQqdOdq=MM9Za|qSCrH`tN&pE2a>Q!Zmux1gSr?V2x7o;@X&Wg{g4W5-@j-Q zx)2#Ee<*S<>8}Tuv1@K|XY4G?3R)&TKQ%ZdW5?NGJ?+(eLP~gMY1IdQw0DRovEuzOWp> zZTb`n%tdyh^?E+5kbg}VIsen}vUBKiM+47Kn$rKtcGqN=^G0`f^d*r!1le6%=Xfhg zj&irhig>V_)AIaQk2)YTr;vtEA}EyP;`wH>-{ANa@8@6K>xJCFpV>ujhW$K0dCME} z)Ixr{`|14B?9FFK8N&OwFc8ZwGX=x!pI2vQb`^v-ubW=<4N5!_Db%2G)*8?h;#quD zh{@WI>pF_jI`tjbwFh(NBycqeCkV#ogwc%2(0zP@d|kLLU~6QGE$kv@y@KvwSEt`5 z|1%b%%5Ih=vA$B{qfoQteUHA(V9UUTxjYPSw)hfyhAG^y5|ANyac0( zONPo{ExvF$uC(~v6H?MG)-}w_yz`52rS5S2Sw;p@pPu-3@epY&l>3&AnzF@*{9yip z`IM6qHW|*RDEFD-0M|2n(RsUhW8WB7kMeFQX6hKU1JFit3lYf_cozOu@(f9Kc_Q~x zdP}-xaL3`X{U&RbDGlWt>7&mg&Ln)bG>m})It_a~3o+>kVD z>I?W#R3BfQ-*Tpg)O-0?XJXGZw0XkSL-{jPss2`!1OH|mzZ?rUK7Dfd2uGjS^MEfT z9;J%_ViH8oJ-@XKB2n8`1FiHnos*TyGmFVPvoYZG`Wo~UV*(GJFLrLR=jrqJ= zB=H{MP@@u&^!q@;J#k8kQlNd~E7P|%zYqLuLR%E}@(t_9v$g|Y?^>c^72wPYUtgf} zw}t732wR0&6K>WWk0$0_&pm3UoODlm9y0EXL?l>w>%}OqHS^h&TJH6>0?R4v*_qGzrKRB2{h5V~P!*{H8 zQ@qWCD9EtXle!l?$g^{*~*Z21NG(9oP85&IaMw!P7tMv-TqZHXc z#xI%8r;>y8@$OsX@884T#M=0cyQO%hMVt>57jr931#5gMCrjg)t#zPves3jA=+cIU zdx0_QFdCk#@462kAC5-wv5dQD7rcFf6XxXd>qA8j{txRlU?83h7tq^jLL_ZV#Da#7 zD@k2W3{>AyWpy-D6-h>_BzLZZ8ufkVUbX*R{fkf(FThPbuMZ5=jqT6fEdH`_EXYIZ zc~5tS4qksW0#*N&8vPjI?swjs-VdR0NNr$OORUtR>XV@6r5QqwJa#f#XeVk<^4WgR zy^eV9Q}f{B#Rfd-3p@V5ajk_(0&(zE(kRPB6|L2~Yf@>E-TIY;{da!RY$t79@78u? ze%x3!ywT!)c7+2Xh<`MVXy6T*k^WcJqFu*R5nmm^!mxeswf@=K$W)X6#bDiI+x!=k zMsWAVmrl_?@K1Rz|Mb3Uu$pJ>eGuJvTHunqsUPBy0Ako3Sg-6w0VGkR#t0yac?EwkNtfpKjP{RZVdUCCdrp_*G<_ zcW_@L^xeszxXdKna23+Tz?|Og9ME=tgfcB-zN`$y%AoncUSdzOnqN!( zzYO63`tv|_<@34tyv267mF*_nnz%t9JLL(6nO(hLtwwnSnC^ebf z-FMJ4q*}si9vDk;2_7-F_zCe4fPoT~H_Bh&Zfxxr-xt7_=zh?F_gvD ziSU|{4~op{~SCW-R4PCifE@A)*$}{X~@(D03vx z?fY}D$@0ss|B1T{6r<(KJG`HUpR9(j?Ej_;=h~j^aUy2TNl*a^G~eS|NEKeVTWQ8gGlEXL85>%;`d@HCN7mr`qXEuz$ZIuLz`ihg> zkDPWH%sVx=4LHYXS9rf=zSMeCQhpsgUut@P@BZtmwA%a#34v~gJRBX!{|lm3dH7ze zWJed)Pa?e?#l7hrra~%Dj1G9B#Bufb6aNKT$u+kdJNsqj2>YAfYWV$?)4^rK^q-do z*AIn&V1+LZnZX=o_V(W^q0*E|SM7_R&Yj`+c6bp}(mwcT-gLsZ!h|1sdPm+ZdC3FL z7eGD+nhm2%zdgI@MOlB4F!bZMYvnCMN7f;yvml*@M8O}d4P5$G0G=1T^k~O7cUO3=knoE?JjzkGB7B)5kW&v(G$;ts$i7XmZ43&Gr`pp{|LHnH z_2QG%X&X@BpgrftYI(dNqtW<8Oq46oU{0%pEMwvLCg$nULEqDw$32m|;c|5x{hBNL`82fg>rPF{P z_}5cpEZ=W%K0IUo$N^Jhk9qc=tH&jsTR3||9P8SYl&oBVhZ^r_P40BDH6V)+$3k9ZA z-=1>fw=-^mE+BBD&)~q;IK`cRlNkU`glVvGLJ{*>%-cvVPosg4y}p!KAJ6~knlEAp z-p`Mx33aV0bbYyj?me%2a_{cB;$ZlXWgSby``$n^X(~RyjIdSiy8s~TUj|5g3sje* ztmn#jiId8ahnW;kpKQoNkq$RTUm}h|=Fy8Vv_=q5SBFrtfUWJfmP!j&tPQMB&*?`W zPb2PqctRh`+vb0Cm?qk|(NR-C(#^K+7UYN^I-|Yf3F5>RDb#A^E_T>0Yr$#K=-;0!WS(M|(kbZV(a5Cl5*y!p$zSVsoV=+k} zYMZAkbeK+`8L;6|D)TRcqOPAN-MaHq4Rz^_2lw-3mAc26o#b_Z-LB(T4h+e{Hq_k> zp3lmHM>LNxy8^QTT$`c+{4GAB$2rrI1;) zz`t)D_afmY+QXK0{WpY$VT4mUn}!SRKT_P^IUBUu$^>%Ss*_&s@%uWschR#_?t;t_ z-`i?OeC}1-ceLb@2oW+Cl7abzZ%_=*PH##2JXzUD6YU&J=eeHB96==gsUK||Fu&5z zYtq-~qs@Ov&aE;>UkVJ**Z?G8-Rw-F=v&Le4;rh}-s6#UzaGaSB0rqHxabE4cQrdG zLm=Vp-Sd*?z4~^11J_ZtBRZL;kxs#iZCIgVi)}tKdA8$8kHXauM0e)KEYQYVi2j#f zk5b@w`jyk*Pct6!4kME~eIIELC4FCLX(pwH{3{3lq$qwBOE5dx<0SQvDH?deKJ*`y z^l}!%`ecScYhrt`)afoafnEbnReyI6N~djyL*q&-@L^V$ z>}G@EmW_MQI9`mE4qxz{%uMT4ZoeS2!U=bf6%6+Flm~R}9<7u*I9=y?x9U+BVV*D# zWqr2~XzTj5+eE*=HmRfBi{nPNkFnK4@i7#d+yd$b|J9r`$Jvm2kOn>UKNlV-#2uVW zc$`tz;k)qzk&&H>pJxAZnTRo)z3_a!G~xI{M;;QqP~h?T>*^ySPyqDAX5l3TLt_)6bMJi8>t`EOM8Vcd}?lPMpu<=hrU-~Hs77n;SRm5>aW+51|~Cf_AA^*Wf7w6YC{RZR>Wu`ije>2#`V`M zOS@A0@ROkIkN9-8gAH#^0SW9H8XyC$3;w&Sz0`Yq8^h}R6AF-&hv#*X`Of5HB#*95 z^Nog?UM**?%>Z~t={jl;!5w3Uz8VP>)ozXImZK$+mwNaNk|Lo9k^3DYd1AAFE123fO_!!+WE&F37(Q7r3eXzqV}3ryE|rmCF=gOpar`Ngdj)j6MmuA>P-Xj z9x>`d{4B+fZUt)0(eCc^-GR%dO)T%$Ua$I3IwBrci%|cinSQA(m){{Rt%e+~-&n(5 zM^Vt*{eeO8ksvxVgIf3OMG+ZTqlQ?V!6R70^Su?RNM1u>7gSq!qQ|2UoX~m01*I<9 zg3E30!@r4r+ZE8+SRLh)JGI~cQI>qoo2x2dcYHcPwKN|^IXEP~9A?eY&ZGs-Zj#ob zu*n&}KY;8xX7pWkH}Rg(dsVI&E5ndGtZRXi)F1=e&o=rsjjOewMTg>0Ot3C4L{mtO z03^DxDp^zaVn`A#^Zx=rBEa3g{FoJMMdi^e>)%nPpPu1_Tc4hXoG<5Hr>G|uU=b`7zc}=Tf;v?l1_7DX+-j1yzj~GdV(y7+RKk ztF1RpXP@8l<d3-<%=lqs0pN=nQ&Jz-$CK#60bgUMm)DRPR3b&AX zmV7FJknyH5`z_}b?nQ;gqvK$Hj=b4-Ttn8NIJ z8ZhU#eED>I`PLRPw~z=`ASz#v+NA=8@hLSP&lYn<0)aV=VF9-VDZjpwT!A^i<;$nz z%h@jP>200A4`(kM%zL6KpNCye2$k*iGK7gct)y<^ImOm3Up^gQj(2Q32=nh~u?^cU zmk(k5pt}jl=M!+BFy#hhLkwog>+Kah8oK4nr{l}zkx%9pP+s=bb0(RNy`RXb`IsGsE7VgLXi*-1n}Q~^Qxpc~I* zpB10n$3ifLn8kKtmONg${T#kLO#Jvw`SO*`6K1%!=jN+#JU9lory_ z^oTKA__pn?pD&NkI3GTx9{2O*5F&!}Y}Z@q5t#BrN@0BWU;wr}H=nyt)W>3pMq+(? z6w~S(J9=l=eCg-QznF18d`f-J&zCoPoepN6*e=2Tworrdo9dug%-(sBE6x)Y94{>x zQE;GO&GXHj>dSpUU;dXF=fkJe|LW(GZDy{madc+0M7>u*svfsA0%3{vf_t%od9eo;-U(7E+=@ zu$qX+adk~+WvxJe?zx%f!>7`J4E8VYn9YjLj^OOrVYvXqRF-=dbGaPua@8PUS*Tsx zNXP2hKiwk=Uw`f|W|?3q6uM1kw(v;$KN^p*{@xy=n1Q3Hk+iqy7TUD{fq4~6#q!v6o6iAkod z3-`V)Ihsr|f94$Kn}5FZpEKY5<0gpT{#<_U=1J-QRv-SG?VSHlpUYp47d?qe%Np&Z zY1rNd;R;@Z6TPb}L@W%~(nQf|B9sHfcXcnX~?Y&xwT7G)17pGoqmU{hl@$TeuhdW1>_^)NFkHbr@oJQ&fyu+EFqyX%Aw(SOpq$6T%wM2KZaE*_ z0LT$>`)Bf(SLvr~_M`1Ujge6u-!xk*3WP_rLpZzhOuqTbepSKx5m37u!_JkZLd5TQ6O$K-OZ`gXihp>7P} zb!Wk(FE{I_8*28W>;jL&AT^zC>PP)c9h39G&{J%M&NDXN0o^AjF-$vEN4o;&)wJ4& zLr}(~FE{I_8*28W>|t>7KDPxmTKzCy;_#Mc57!#=vU6-g5Gcv#aWWhOY@VlE(&UQV z@bp*J`f{^=+N?jX*(>eM!_zSCwC1Dzu5=w$&*f5_#5u*7#7@q!lK^>)k$kCK?pS?Y ze<%d8c^Y$Vd8+m0X8p8Te_pd!+I^TyD{Zk_>3|F8*uxp8$K!4N#XCRG3Vt9KFZjIA zmSLzmn~Qc?q897sCO>?+N?&f)Pn-4UHG75q_{0R>L5?9g-PBZ{vE?`)=M%*k`1oAJ zAGt*NL?7p2m=wyUo3IBZ_awTTEA{1O{j^zsUbC0&&2F4rNk>&zz=itrc0%N$B#DpM z`3^x45|kuD2g+r_+_Cx;92Zwq#px}c{-#1-Zq`qm_2)JFq5YcxZzXaeSBTutoJ%o? zueWu641;o^!=IqUR>{Lbry8!OTAFYYSG7P)>E@S?m-Xdl{j^zsUbC0%$KCv97s*~0 z>d)ik3IH1hCl|%mR`$`j5J4~Zc}0&Tg;NZJ*PBALOT{Tg_b|^(%_V)gSwC&opV#cV z{VPeIvsJCuzq|TTf6mz2fw!erNn#;Fi~zA*NKn6sqJ;9qc7|!Rwa}e3_&M)5B`&6AwcA%PP0P&8xAQOi{x)CPaKZD_ecIhuYV{QEVWm9t7;$Y*(du?3PCxD zMbl*RNtQK5Rum;p_LS^2?mdB_hh+RjDf!Gm+sV;e_TGsJ-rco{_yqzqK6wJT!^h#I ztvEM12}~{s-Io&-%L31EPA8YMp#-d{Kaf{3T_s6adFvYHX=yW_@^qyH`ji3stO5FL zCE`%B@0J(7P!RBcEG(4vK6$w7g|%YwUQ$QnRk2vyFxkrx;o1^#$rlcXpDF>4k1?Df>itD<&TDvM&?bt7 z`sfxKFOs%9ZBAXhvbxHyP6`qK1^e1I;G3JHPkppVMOQ?CeDW8t=ZtD_1JUTjk zZF*(kyE7zHD1qDnePrs~6k=X-^(tr2W|tQXhyOwe8ao@*$UA=h5y1-*jEb=D1%xLV zB(MwxOMXf0I%>Lo>+#;hqwKhGWx=0n*>z~ku~yN3@ZcwhULIs+4ZsGZHSlhD0pNGy z@evc?0QnDBh>tIx8Tf7m5VzwLIgw|D8eIX@pEDVo&&NrKFFOgm0#1G+0mQ=2vm($t zPPHJl)E^7c=jpDr1-7>Gm<+eq-qv<wnlk-TvvC;}CLLr;i{W@W1V#;h_S)tzeN6?l{uQVBEla zC^G{CZEd#z@#{E!IBc~<)$_CkhMj+8!VH7mBy^T@t1R0g_=QB` z!U;bR3p?+V=6xQYGhCm^r6?)@qfj;4hoRy$e;q};1A2DWt38LH8}tIcK3k3YEP6UX zuDkofvf=Lfm-1&BPhZVAgEbA&$ij*Jj6m`hc6?ty;}4z}5UL@~aL__QN3HNYS;n(u zfA=9<4e~)&r(>ue-+-R6$s|;N51e|fqW!0^ZrwosiA>x(uH1>Ej}HzG!rKVKJyIrd zJzv?C8S?0$Ub}sCX=2)X-MyJ7Gqx}YYGjyp8;0bfIPY5>pY%t@J33BucPCCE_vMjLDxy$aPEmWR}-}%sV{0VY&4{XV<-b0Hy#RKH_=*UVgG>tp717Yv`W8f_>|;!Nm`U zpsJey=x%9asDJ;BW1SE)wwPRdD$59YxqS@|*N=(@I72n}5bn4#SjPK57YB_fWvb`2 z;o&{NDOU%`&7IeJm-q?33&;6=Fzh6VQw-PcB)56S@bViAq!Q`Aa3PU6^-oHO%ulj& z;OAcGTr*tCi8`cwpkIwz)FrFCiyxlg!O!iBD~oNI_;2w_$SAK9|42Cr?Rqz@BvK4_X?nO_w~jO ztk_Uwg#3dnZ{sQQYzO?>@d_%viN7vB#u(%t*8hMUE1B@KB4?p7gj{bQI!6VM@(yup z>{yc}sNw(OAbH)WU=-Z{D-ck?|4GbGj?cr!i_0+RJlomV*iWO{CBx)0oKu3n(~I~* z&lwp{bf37~{qN({IJo&33j-qTLOBLUM0Lj~7!jqdp|f3je9qga?c^cme z8Ln;+%wf1*$eNhulLB4@TuENIh!gw)w&IY2C;6K#0w!Rs$?)~Dq9Nptn-EPX+rTz2 z0Ic2h_16aEih_%OK^1_clK+i}unT<2(nyxjh;@Vnb_^la=$ z4h+ZDE*tWnYQNB=k&5C&|l1F1FX4<$1LEiRETa&fxa#!R#p z-I4_S7+Up?-mWAOETvag7bX>FmyxMfCqGI@SxXB;*=o!5&h$eVhAz|pg?*m)B-IZ4 zZ(&YqzRtP#^gidg&-=dTp1c>B4-7W84{{pU9d#}{xqjMqsC#iC-@8%3eB^v}%lR;b z%Y(taGAb$Pdrs{$rA64u_j5(a_sVY}7tad>Bis|}F`p10J8>2#`3mZB@b_5{d3~-} zetVwgY=R=NUEE$l&c^qy13cQ`orFNXi~84i{So`#y}I&vUhpl*bV69J`Ukv^k8m>< z%F(Zhc`c$rO*BXf;Ksu$;@!jC`=j!^PEXiVeO>@BFP}N-+i)-=1uu3UD5-VIWELkrE7kFgZst-XBF2^A3G@1EepOb<~N_7tZqSg zH5U(OpkaVrCH@!43Hs?hy2G|_ZtfHK%kylAi6SVFYOW2;~FrACLJ+WIpk>OG3Wa zKUw|*>LZ%4T*-++v<=NNG}AN+3XVhW;qhlOHO$D@!lZo6Pd-_;;8;BNr#1wgb<6_d zyn#rEt3Cs+&jto7k^}W{$@?q&o4mmeusl>>F)%g&?>rDV>TYjXUw1~iemdXQd2CV5 zarwHYyO@a>ebmI`@$eP;qdn}tsOs+*B}UxV&CSyS{iV}I!MXe!)<*>BM6pEVLEyfP zyriz+W5GyDd69TX+bRMZxxP{`pN|k1D#+RRC)pvS|9*s!-{D6N--EsVtL??<6UYml zM2t+Fz_Doa z>fGf!5R|rx%0m5JAq)WT&JN47ot;;SEd{y2mDqlH|G8*;L?GXuS4h*|eMRi&2{|}B zFOWwx5Zp4@5&j6Q710R!zWym@{687k(HYC4mS~n~nTBPWre&pbLlo01Ju3E*_2bhm zh&Q`tx_o6SKlx(a!MZ%xpA)|Zs!G5gK-f9! zrxfgx{AooyrBPWZzc2U&*nWGjUa`EmnHHJ&4#Ykai3sEx8{bK=8TRl@iwNXsD3I^% zf8X}Pa@9ZBY~bVbRj~RMwtpl92fI=5n#!g0l&MUn;5|2&sUC-jca;~MaoWu?-jM8= zc!$ewryn2&8WHTc*7~N1Z$*7F8A|qlfMPGHOpaB6`S2a521^?`k?TIXz8rOO{WOe0 zz72a@#C|t?=gTKAmQPm4>AZNt@;m5)15;4Bp(5KiH}@R(eLBDIg@m${W#ZYZk$E`! z+u{j6e@HOC!EIa6FezrBix3mrlx+f2gW#=MSLrhpf5yfdoy33d{J4YfUmBJ`ZfFm0 zF*KqRk5j|21aj=Zks9;N94k}+Op0z+c8;xeuKYI0c{a=A_iI;1j9oWu?xY<dRz<5MKR5i$LuEX1IEBvK3ZgC}E#uYWnRvJ+ z9M6mj>WFrlyS5)>AQ-%6M%SC-?5`8f5v?XQH;o z4^IosAdV|*gpZ?72={(^k`Xxoc&7;1bg?(;!am{rk=|I za5J3(*0VaEblo!tf+4oYakqrY@PelFB20&<*cRI)zj?IE$q1;y%?m*{r^F$@Fc3;6 z>nq`sH+hFYwjVA@RtA$vPM+W7Ou!)h8o6Q-bw-z&ILg*0Q!Y${w&7FL=#%RH+Pq5( zEcaZz7$T_x+_$#GtOEBQr8&g^ANx@^X`4*3PlkXFuYgbV44+?@8p~W=QB&BP_(+!T zppk{m9^9hwymR#|+6d&_zR>umhm>GK&ixDI*gpdP71_UR&mxdxd)AmKJ!kHUAN2I@ zYFgLzRBBc)U_F~%%C@#HQAkI|Rpc|N@Gd*aJ2EeP$kh|wHi|+O#6cYLKxt!X0A8SL zjFaR^>Ugrl+tmNT6T96GmUkpO`gpY;O`t7k8*oF5ph>k(Nd{PFtIN|xUvzLS*GcG0 z^+l+9m`>w}#H5~#M5YXqMo-{xYl|tOhu#(iygCUOOq?1@=g1`-8ICq>rUVYN;31HR z!hXwm_~!AhA?$p&UVHUmll5j!zEt%Oe|^0D>ATyjdRV}%ZKwof!pu>fA<}RA-`Yn1 zIlNEre*f(IpL1Ct4yb2|wyysIv|F>SzqE2HhhA`e3{d= zl<{_gIHjgmXgPr}I1VKrw%ZRMFA2svl9kDd`U|lTnoPMGrvmg_+K;-ON1aj0&uu$s zv(+7P^h#v3A(H?jj7dM2L7$uEuh2c?;kcR+I6=row|*(xOm4S+0eWY%&CRXNU$p*nWMrnit9(*2H~D1QL@%PBx?|lXb$Q8e zzP=t^zR@le4=~JkxdvQ)^#c_kIPmp0b--Ww`uM->_TwdXuQwU&4<)&(C4}hI_1R6R z`IMV$qMhqe=d#M*%~eGQI~P85EI9Ha>5|#v^GUhyGhB6Q`^Ay!IYbF@Kn~+h&c{7U z=TFe9y;2wk!v0q|NYaX=l7p3#85}E|*}rc+z+Gxx;=d)58~Uv;H8(eZ)2zyWE`#8c z8#A1t-Qb0U?y`@#u(q?#)~4{`f|cb4_p;yJNc{TNZce!*u;-<>AV7w&eDcJ8_%O_; z*BkT(gY_NW3Z4an|84GiUK&Z$aQ3nXZMupgzZ22D$SyVpvox3(2eRpyJs2`FIi%@= zGJ)*OxQ2A6tq|)FWOSOPrK8ZzbPGd^Y#?#B6V${3vYyleZ6F@v0TmOaJF*nwfV$ z-$22~pWgi>o+UiLemwmuos{ndIPt!(8h76xkN-QKOkbw~bmO!EirdYmb@cb0Jt4yP zmPFvQ6j_1|56k-TA}IdHlAkx-{C&ju*bZyF^ER6)&kEO>NaUdqV{n~`^O)i=zrqq^ zAkOodGEs*;f9YP=4;SWH`X8Sj=Pgm$zxy#zAK~}7S``GPkA#5XkA>32?M>_iR@tR) z8(#I|VmrV*GJ~cmL=SHT=uiHQ7ZX#I^UtOV$3h4s%|SoQ{^c$RjlM&lVR_BuayTdFkQtvN0 z33|op3kc9P^v_K~j5B9K{B|?7IygR?f;LR0LK;lT<%y=mGzE|Yel3+x zjhXea%=3&$D?WHhC#vfU>pH7)_3lBx-!0wr?}qgXhl?ufr(2b_6Apzb7{P#Q^#v>* zbo+-7ft~LIZ$SN3I8^x8t*zDVt?fmizxamHGWOREF*|yvWcoCD-H_8iO^Y)a`TXNe z*pTLtg@2ISAnJvJW!VMeeN_Aa7Byj|E$1J;>0b_d!)?wX#Gi}D$9wXe!lB|+H;GjC>|&1qW;{~_uusI zURhCdk)m3pQHNOfRV2~Re7rx6&sMDh@)sf`u5Q82zX*r~P?bRxGjG)@Pfm22(lcSM zV*01NuCGt8#ZzPGxPII5Bco{;z}2u}FhJmD(jv4?o18W*`_6cwU=$1kpckyp_r9+I zH#pwT6?6AF|C|2h)6=D!`fh0ruUF+^H88~~HjiwXM4p- z(cTj2uMhipJQJjk?#XK)+B%CaNsA~O1nyKP-rI&ni%G)Syrcod5s&eQW9+}nctLK4 z+$}>uEE&xQV>sUF6bjh?#s1^Y@aW_42$k}1{-tTkLf0I{w5T7S_dunPtHdt|HBzse zV<9-okhzJNbJ-h%>r}EEiUVHsQmDp!Xf4AyDOl!3;ohx5SyJ$L^mS?%z2rw+1Owyx z*uNW~^Fu^L5~l5=Yk|FMIV=17t?1sPowJV!pTX?x@QJ$ik#M;j|Dhx2Zje>BAt!Ih z%@P#*Ka6+eW^@R8=k?#(oFAsyRwFAP`*_&w}tHl>ygsd82f|hj75W3vZp~eV=2~0^VWqZ zyWlqInl9b;?}l*9k@AE45g{T0xq#l;`dZj|vVR}~2yrE}n4S2t$46KnuIAL-s0xZl z)Z6~$sAD~S&@hx@SB3-S&SgZvEGtA$Kq$FX_O6N+;F4LGjcb9muPac)x+ zL1`*Q?NTpim;wv39^k3F$NFf`e2-Vr`+Mi^Glx0gJ&oc&_KQUo zyyxz0`6@mtn}`ToD-lX9XQk3w;!Do^%NW1=`PIj_pZ{+Ea@X`hU);Xw@*Xka0NAY0 zXO@;W1tI=gFqo>d_Ao^_u}geoGsJuOeB&?o912dv=uq?KS7rjng-*1-7L@fxOo*{) z5f{#t&JsF*91derlD#`UIezeIfA3szpnmrqKR@ELk;s5F39ADiQ*?WHm z5ZWf~u|+DYmoB&1hJ+8X+b2n6C9a(#Ubd47IIz!7jb{J+xmHR8p5 zsk*+pda>bf*z@!C)qjN-m!~J#OWoz=B?JPwxVX5zy}P-&IXgdxLZNqecjx~Zj|liP zogE(^pPioF+}^xEUtC;1Kf_+QJ-;w|ex|0O zdtvfIU}<@cnwEZLb#r-j0|tX19vmJX9X`WhclURvXQy|!cQ4_f4^RqP`t^4-9v>baUyQrEm;78_UOmB{PEJnmZth+(_R<#mpU>UDg%t?o=JMj| z@66o&-TnUl{_)AlOWoqq+S$c96%E7P-Tl9%)w9#{hx_}Ro7=PVvx9?!i}Uk;%WJFa zo7>ylmzNjk7w4B37e_}&t7}^qmlu0`d%L^4);4xi)3a;qTQl>E=Vxa-J3Cg^whN0Z z$EU|jYa6Q@TT3hJ)3g8n&dk#>FfXpIFD|cAP}7~gWdGzuPv6Mb*Y_EY_&fJ+cJ3c1 zHy_a2?&%pO^G-hQYdm+f!3&eitIN?bFnD~D?~6fEap~RN?ZDvB6$H}T*T1o`!NSJj z>E*4dt;5GJq^hRDA7!w*whXjFa=zm)uQE&E)16TtTkFBR_+VZ#8|L3=i%&gL~@~G%oaY^aO`gFG+U$VQ)%`Jda>vN)Urlo`RdYNv$ z^CQWvAb~FiFFJz3pz~YHJYNh(mnRF#N-;+$Umg&8Bvl1jegEZC)2{fFMG`V|3&sd^ zJ0i?zhZ!_$asxTXI;Dx;$ee8MaZPKkC|3}3vxP2r`FI4LzLI5Fx2O<} z8oDvyFihCSKhw?a`b~a!dGwO{7IT_A-OR0iU!D{+buZpN%-+&-wVwfRke2R}4pFyo z)6z17Ew=VOx43D!Q3RSjAEmibxLoaQM>`fSMKc7L(YW){Epvyu%NdW?r=)*QjS)FcXrVn_tEWJ)w zB|C=pTe-tsGOYW*9t1bP|CNk(tTVS>;)Zjz!o8~Zi56`QyZ^bo_+>O;PK>S2l`s4F zFKsK2oDBsik@Rzga6FsBDBOLk9|Q)+>q+lMf0@D-{pXkJ1r14h({4r2NW;+clF@+V zSC=MY%cKB_Za)4+v0=5XAxi~e?ohkcs>g7_P6rnnO( z@b3(z5mN<$4tK5gMp zZ;MaS?xtwR!s9(|e=rk8yi=iE!Wp3}o(k+CN5H)9wA$0r}UlNZvg4CTpdzCG{U9VxH?k zArCu;Mmu09G6SFHwicHf955g48Z20hOzf)Q;vGav^iT(cGbvdRod2+Ol;;NQC0*_?`_7U(l>9lz-)D19GKZ;*2kp>^qKw(6 z{}qbsqQ(*0>B2M$_&#zW5ungx5PU_sY*~v{0k&o}5hT!J0&R83=)Q7HJwZBYxcW>A z99lRk-wXWQ&H1g8QO)dla}*ECilK@;^gf-b*Eu)wsO3Q>I2%9v+z{&71vZB25SV1f zQ=v9qc$wRw`ww2IB$&solLAmht&K)amZ@%pb1t}!TTzd<-}#KH&vKjRBj5DtAN_tP z@_)Z=0IjWF*v79wCkgntqh14O{XD=>H4x_(PxrMh-HYF#$hm4VKWXnaY;L?XT)NLWx3*7Lxs~-fr zOY54uKY)K(*tK}VQyQ1Tal}GmO0?pGg%;AxU^=bMYQR76fQ1?xubI?2Ptw2$Z}5)H zQF~m8IzBgCEDv=>I0HF;1=HAktJTZgUX=%oL5e2njvjmeUO|32mm0%PZS6I>G#fa!aCeGrM%x3q&EKVhDKlPXEL^9@^>!igN95P4Z6n_Pdq05=K z!|$|+iCD0dD5tqBDdA#Jp{sqUC+{Ix+`uupa$8|RFa#uEj4vLtu@oIISYe4B5Nk`B z9{ZO;_mVzt=56dw=8FhGH2$sz!3y6)L>?o4(M*;UQV+7V?sTu1jo2!-D|;r(jn6WZ z$|Pv&v=9shb3gDvPk(?yu@cfys`^&EusI&hW%{nf2fcIsg-J#H$>UWfM^T0&)2EY& zAD1tEpi&Be%8idI%5^L5#1s$I_JP%J+U?|#b{KVb7n!cNtGzu+HE)_s(15%znsv&< z!=c9*fw9hC2`5Evs`ISgc;v9nGBb2BT8@w;ZLOAkF-}yDC*9EMA%RBjhWwT;P}C`< z(C3wrVQgj22>5MB8m}Ukq)%U!!RXJD0ealFlEPKz$5v(#9@>x^-*G3`1ttz4aCj1h zdn|5N3hS)L?Ke}q?lo#<+s(Z|kbeF+u{iy>^BjenPU9cQG|G-@i`EYxV*{$p|C)mt z;L+AH)X^+7Go4{r4|@A8g9}G&0YlRgA$W~qFvbq8AHb1=Yu=%|^cQ-Q{C6A z8#(6CC?_*j>~2u_XCfiCVmF1!S6W2}kExeSdylveDtlXm9DlH>_J!7sE3Jt#{H$gE z>|{o|jfaVbxPU#PPN#9&+qzVNpI@og*6S^0Mg}})kES4_?y?hylz-`pnZovF6q3m; zm>Oj)PN3giOc+z!_p@d@eVg;;cNQ-Wa59W8gz-xZ@Op)zO%+&GyNJ0U&GCo1AbydG z{hi#^+fQXQzvwvW95dDQy?b1mz(>^{V&m$_8JBw-=Ek8?{FqgZ)C`!0aHP4FKBqlKJ7ADALurOLMax!_kdnfUzuA zt?yki`o1BJ(i+l#>3T!-9(rcl^QpSJE;@2h)l{*dLCu>%PrFT7MJ(}2Jvp~K=dx4T zLctT6$O?_xsp)OM?zFLovBo8qWZIP&=hv&!O%aYp{zPnvU;+4i56Dw`*q`j20>KlU zFEhsR>{|^Kr93HD3?zL^K@{^#OIx>(e^6hUl%*m6M;_|4t{Z0r#{AR;)|6tUgyQrV zYd*?G^|%CD2w%&o1Sji4Np&!K=aVmV_GxDw6!M``t?|fZ9vm1d?%3-dv2defNBZxm z#pk)b!5lCFl_f%`mI@CcxEOQ4e-*T8o~cD8=mC%Y`Ciic83Rb%j768!eDg*KB&%bN z*H5K!+JkWXeNQFEYHFTVan=eagsmLy-3+|0-S|wv{&oC*oKB34R|*{H^Yyl2PPSlFa&n@Yf=AEzcS*J)1|DI-y~1!B+!R43 zn%}iR_XTlMP5_kNgMPl+hyBECES}~%TVtDuRs}1 zDXi2%tvB0h-v{}JGL94FimYqZF1`HOlsF9cwDC3%He~IJe3*ALXZ?&A@a%+WV|HA0 zi4z;}+Lu6lYq_U)FqkvrpcT?pK$<<78+r~dN$6)dkW_OAWPbGM!ZDOsZnm(|%0i1I?5tQnG;^3F`L`#0 zpPhv>%VcfY(sog@dz!s_^yqni_+_(e+i+I<*<)X91<{LJs^_Ej&iCsn?f?%X@sSp=5( z6<%x@RQ!BvLdGPzqQLtq0f2Yp=jyl9*`%G7#uc}M1MhP(To-Z%I7=Sm zLapKI*Uvz2v3r~o5cgj3sGtLPU_0F7O1b>JlBiQkY*-Sib1TULyf*ywjyeDjDm|yiPw=mO| zLV3C;o)7Aibe(A}1G&J9Z>0EhWkxwI`w_lt;19uskvp6y7@+(P_Q@S_1AWoBp3f9Y z>fH+;?pb3-89H9$9e9j`ubd%#f(NknK%;)Da7U=!bNZ?kL0)j;#QQd?u-=x(Z zbgt!illm=rwB`2arez7{4}wSdiK@C8_RQ>q_iSR0*V%gt4w8J zIMj@C2G#FR-1d$roshQ#HI>YUe6)q_1^IBNdW$G>9D?m~|51dCi#wt%6}jfDHIZT9 z>6r#8T$nU=IQvW{cFYJ#f~c%QG(P+lUs;TRi@>eP`{wcAJdP>3VJwQkUF@XR8pn}` z5so8`PF-gQBf@6qfd!;?aey7PTp^iMgWTLVtUUC!jv^xR5@RD`J*;7^-Q+_X$(koI zC=!o+MGnE(Eyh~2ZA78kmnRTVAxHiuRcIJ(T&Smo{UuE40(zK_WsWm%67J8!mF%e3 z7Rb8eWon&GKvYP`4^q>Xd{snlf|8^ep7m?B@H_u{>%E}Uq_^ezj}xE}S4U32SJ>kB zJN)UOFMo8*1=mASwWC|V-$odoa7)1pS%KM-s_ zvQelGlbe1xpqcOw2wXOVN&XfdY$7>4L%MkdUNwN+Cnbu^!?4v|n`EJ`*&@R+o2)m~ zv08^x-B;+3^HAy^hk7R?I_=-4Ruy64kd_j%%e{*!rX#b}Lq*y!3*n;!gW3H~eTjp0 z`E2Y)U51uo-wyNbv{!({{?`rBgSLQIez-(Ur3ZF3YV!%lt@x4R1hNPj-*Snfph)2p z{yiCE8-g5vvn#qR($fK|ND|hRF{eJW(bF&?X?O&C$YuFx=4Y97--Cn9eS#6Tab&^U z%~s-!OAfL_q5lYyNbig7#h)zr^Ojv%yMi{Amo<+bQGqUfu}rPQ;{#a$C2Eew$Tj@xS& z&#G)q4n$tnBiaNJ77#{f5;9(GmASI5U`?H<{w(>70>yFklLd(Esmh_sZesn-R-RUb z2?89SHhUtjFbV-t+6h~RQl(l61fdV4X)7SrQQM{Jo#dpw7*l7{;mdV;#G8=7=h&J* z7wK@=-hJTn0ry}qBFN+3$$pj1+bW^5R%)kq12FKpc19htKlsM_n`<6QVSX)qMqe60T2k+RQ2udjlpMd3vXY$1iPSd1=i(^fJ~x^f17} zCwF4F+dp51Hq12CQ-m@vhce-;W|(OSakW`ryXzJnvcU6P#3d5o_Zn z(y5JWf=fYMwRE>b!IeJ{O|esvqrJ6!;1+35Ir^14_QV96sOIz#hOVpDUrF&b=Yh}l zs|A>HkP#hwT*X3Lr3EQ`1qQXqtg$({<8o{x;L3B6QoT8jbkvwAUA+ zZ_BLU!~4eFfA!w)b})yjEPN@mS3Xx7S_zkWdLuJL;w0lK#l1gsj3&|?P?FgVOnSF= zL>1|E3}duqcs;h~fOWH7{rPy1eXmk#z%WorX$Q8fym~)&5kPVnK=_Nr@ndpt5-C`v zs;NMw?fYK3rYfUhS6TT#ZyjV5fXbghppo|*nKdA>EP??SuKjj&C`a9US79yPQoL#6 zT&O3s&M=d=mLGwPN>tg*`FG`v-=b%Eqj_Ridjd!#)xEvp#=P|N^u+d&=WiTvjNtE8 zk6bxD@*EK!F{3#^jcWXKck9E&ehylM+)bnXE8H0ol3X@Q7$Dl?-sJaU$I zooixUp$dq!ZjNmG^k>Tt=TD~T{q2(w~?uoj@I%Veq=)*4X&{qg< zyV)f#5*|Y?fdhjpC0CB{mX3^79Z31y!xrqRA};(PJ(%nWiuO1*FaNB_xJk2Fc#4Jn z-<5-OsD3$I`{R`SPe)EYd)auN)`J!IRa) zjg}cUu~lw_LPe$=OyNrJx~xZJ=#ZNBQU}}@7^Ie(EGt>h$~rW`5%>nH=|Lp05XB_F z3;-jSj^G1qGQo zg;s>=Ojx!6eBh~?!O+3`Ey>Vsd~1XJ|DZE`0%0)wyC@U{Vi z`Ic)g>#-wo__yagJR5Ozwy-U~-i=xl&z;FuUZkSkc(iCk#0oTOwo4AG7H;dZL#XU{< zYqCRDQ&vzd@_19Q5T508<~Kf-(9#3$3h~sKBu6@{5q(T7>-9PR5@s znArO5S`Bh$RZf%u=aacIOpa2NU1U+cyi+kRYWMaUESp090mhj`CRvxW>AjUZ zH0^$bwB?AWPoZZHs2GVO4uWr}?*|sIeW0@zy#mF2?{Ktn^)!DiR`$w!FtRpoeG~Cu z6x)QzPyjbXy5>gjICJ$6mUTxIb*XHnIA>N7?i@n`LOuqfa}8DS$alr>2}1fRRjV4G zWJ2%W^-L)B?X(b@1#Bkde|>h_2#v$1>d?j6<6^9f=uz%e9Zwp?mMT>8cl>k9bVG zWdc%#^8V$1)M|zb5SxFo_UGVu__)kGd0`NIxgL|I>L9l-%G}fFcr2)4%EInC1M>;_ znD}0oBA+^*{jjmxtP$QMS9SSUq7M839s>da1{JHpmv?4_$Fzqn%26kcE<_hAd}=8@vB_iQ#med3IpS(PLDX{Z zajNuZv?>SS1At&-3U=G~%z$A2o>+64EJ_j%wg|G0b4u71n4JDIX&xr&#&cd*=JGww zu!hCyx`vcVJNTzghiTvOnwBz_n$L_QNuVrHrL9r(mb-|@_=vg{TFP@uJvF9RBPQMUwo{~ z=8b6PDa#^lo?iOi+!q2g&Z$V4hi}G{fWMZ5_zF=IWevk z3T(~?Br0<`s+S)QLR{tI(f<^xY6!VL69L}K(lN^yB$xAJ;>jfthS(Hox26=zvwV5> zItuI2ZG$sH?-Rnl!aE;n@)1&DT#xeb7$UYTrB;P^j>JQMLsIE@9Wax4b|n{j&Kc=v zoon(wx_%T+2-c3CHOY#51*k+JQZ)T1dh0>7NW%U_b3dk)7bzThsJ@VWBKmtwc7I^5 zU2T!En37aXy0IJuGe%srUoz^-7vY(~f zpJCinls|+87=>g4F~NjNl2_-%=+lx;OZZ~(k@TGpVZ&g4eA-z7!mw6fW z12 z1P^qSg0GErS&H-&qkr=4T74NzA$R=NY^E93F$+51hCBTg`kFW2Nd7L4MCRGQ=X38; z5zH!j!D%!wbeQs!`?!u63OnhMYUJDpzVJA?&%vLPz9jK(K~!jal&{rNr*_g-e_8|k znN$lFa`ACg@Ow4h7BO2jH$=GeT4fg3Y=Uf$s{yZkMTbidLg;Z!X9}BpG>o_o9k~+> z&+_0t9e_2(w@Sa9F9Qh}pdlmiNo~VOc5+w|l`HjMcDef}dUZEnr^V|3{f6E)luVa~ zA&8T@YY|%$$yTb@`JF$3UKZiYp3H6E1YSbwUL?KT;gk*yIh-o!*}WY3 z%Il5?sbdP8XfPtXK9V;i3|^R=6Wj~IlL?gnB`NWIvI;sscI_?EHgh-NH2P`E%JawQ znc>j`)BO8Lv_w%~@)12d$#uNn zkPZ7>_O9dx=-d-pC*E;T-=Re*^TkW;#C(T+``^J>M1$nm0i;N&nkX8g86BYeiC9#s zH0jNUHhm6j_+}Z+TdXoQ@X{?bkk6k8)C~2O!27pwEM_?(OStlj7KWH9dITf?yDL8k zO9#A_!lj}wXUGe(9P{{E3bx(!o=i!m|1n!EK};sBq}=Tr2F>={@L77Ef7%o1XR8q- z(k!~I@HZ7s-cG#Di+Jm5JW&>PnNPq**+6c+@`dW|z$2)0J&W$Og|X!wZ;N`j3)L)( z$ja=dse4GfWt~IZG*{>eS^3%K5OjI@*4g0uf z&j8x~E5!5xKtp%OhHF{aS$sBm1Z;Vlos#nK2owJK(5(_`McXOBl4|BWJTL6awn#qB z_?36FrVh#s+WNZr_W#!c{M!8d-R5UgO6m+M;1Bx36&dW1k=-!JHJ`^48-0P4Y>LMw z2=adU3S)&W*!8MK0|uN;n&c&yl0b;CcMs4h{zJPH8VvLA9kodRP%$%|UQ{SCzre)Y zgFnWvdDQb8)bO-$2EQR8yVZ)v$2*SM9->u<#Dc{Y{bZe=%@H{04?wGYmAY??nL;eKTAdwgcZ?-Hqb{TOG(n69ErK3RYKVh*jbQ)dCyJ_HN2ZU4-sDE#D=`P%-+ zvu?_415vgG4n6faMFbxn&4*Xit_GrKyx!8Q^|$L0wWdjJwv`>(mNoYo_NI1`5kh?w zAw$$BA-DkVqg$g=fba9po;(wnX*v4`vWpnuuz50{>?w66!IFwrg%-$9D zP>buM)G0EYuXX!sDa?H`0@qJ@4ICaLxNebZc+OJBWm6MVdUc5z?|Cjv9oUw9%n}2J zf5hikG8TJyY^|G>cZyo4;dq!LFkk{xnGs&!hKbE#{CBSUhOFHie2e zrH|=QM7&R%{}08NO=Mc~u&q|fq^g6H@aCYIxt|#vQLjsa7E<;KmG*F>-+C3rrLj^l zpIqY5%usJw(mCVWE=<97z9;1@Ae&~Hg%#{t&_}cYeSFK-qLHMNECxmYZcb#Rp>n$Co1i|J z5M-rhEzmh`D^ahN#ZK4i+H+XNPG|!d5|Qmx5G@&ySXkj;vR8j%zFxM*!;{R@`3_N` zPg6dt0QRizBShO+T%@vsy*|{|i&u(YRB^6FL9&yy|=zIUubahy}xl=wpUM-}8 zawDstZ0FKK;`#hIS@TkQ0^^zExk&;M7;=38=#+6{&qsMGp6vAiI}8Py)wj2OzFrCZ zj`2@r?4zlWT1dX^E6B%Jk30fFjoy0ltBlHsR4t=mxR%|u+5S&^wI7BX7;kjA`a}(u z@y4xOon(MAz3f&X(T#x$Bu9vX?Gt;2I#eEYtcrPC=+BbUe(vtLj9xj zs$|GKMLu(zzm=TO(r5ogPCSn=riS~}*D>QjJ)l{VUN}XiN4?`9S@%-{q7TwCj}CE) zLDR}C-v~qO&uwDiE!J6-Tk%f@cW7`4fD*CdqtLD*A0799?u=y3m#(0stxs=X`yFpx z6BP8&4E~NSNobL>IO=h2kSzOK@?5141gtrP=0Dy@vmS;HdRJJ5<~$zjQ8o@c@5Wgg zyft)0RM74xO~fm&Ohm0tk%nr8RnSGGSEf6?OL+$s=$Q;|--R@^tI+$}bqD4zKgcL@ zuuP&Y6kOuHPQBQp+xQY2dIUc`>X{3Rb?51_*s*FbOoK^e@$5sc>~OR4UU=3;xT<7q zVytg)y%n{^^Hlt^)*>hCr^Tohrh!QN1?0Z|JqnY69I#!v+K~w#~uA_v+uR3 zS6EXzu)_}5*#e6SgKkA zC_8&hew1td1CgUQuc%Q4OFnon`hl<{+zWU~2L-g5E@z#PP~%5FI|&LRKE499K{CkC zq)(61Zp4%n=e#LsERseVpf+*kg#mrv3#~#ZU_y;na(r(7g#^d3EopMQ_S}))6fB;Cx1~SbuT;sZTP=Eti~eezyF0 zS?a;}<&77TJ(ctBv4`z;51$(C6i=YwwwB#bs;el zgbtK;JFx$Q>z7Cc0eA^wm%K?V*P3$`2(aNnf?L)i#cswSZBFqkGH<(5GBJcKzRm25 zF=}zOaHpx-5f`DpYdVQMz?Ru-xxHa;mvJ-dE4Lle`6WA0lq*6@hy<5vo+I|SoIX>d z`ib_-#0tC+$j5x~T_@|p$i#Zd!vBR>5U1NplVG<3g$TyNBPmS0;I`2(h_hGu)m%~r zI6h)&!sID9h_kd2qezFB+H=F;y-EP|O$ZJc^+U*V-t=e$7z0EA?=%2fs&U8V`hMZp zs;oe1?JG*%uX7P!G0|nG zqZ_hvA!z$&_1!;ms~`rqclx*Fej2hbIy~9$6Y;O*3xH_60-GoInby^`_@-6bsRi%u zfX=UYsr|NO_V0%|4HZiZWGoz*)Php&0aZJYktC2z2t1gbhgXY-7qA6`I4rWMW8AIS?gNMh^Fl*9Fq%q2v?H>^|(a|KaIfcg3!hY5+1WJXl zh@qxb->R7Gqge=qDukT9EKOchgI-=bm23`jjr=XP zbEE#s&&c(#`r~3(`HRw#;EU`Xa7>arEG%)G+G~1#p9R|tw|pdzpY}CV08>;mmlFNG zi&&Cu;rhAxjTk*tJf1S$tFjN{ZA>|!Of<%D;kYix>`m*(M-%Sq2M8meLeq-lE#(kO z9PGq7WM0VDfz%Jb=qj&%MO`YhE2dm)p8KbBj-&+I*8n^%Vtmg(vuuOk3{=0x;TAzF^5IYRlJr zw#cBL8z}ZBIz{!fn>Hr?&`~H75&2dZg|l83E7yf_h&7Jvv+b-9s$}MB>Mg^_%?u)p ziOngk*!#P*%Jf6B7-*dd203{`Ai6G|c~Kp|*5e9)WMF(6es5USfQg#7)l{-Iy`vGH zP+sGp;p=|=(FQHsoE`6GXKm|iq=T}TlpVA7z1jF{+N4D3;+x0mS%)OSBYpyB+5iTy zkN7az_U|**bxLIxPwm?6#e~RUo0_+6xF(+ zSmo8Tzh7%9eN*_vi4TY?smXyl5o_FJe_(Ood$#+xBx7UA-<3s6UyIXABSJeR&96DJ z?>@ZE+d1}XbRFDQ8S$YZh?1BpptYyIB6`h}HiEs#hlIn>BlI`PFJ@`IH=p4|2mw$z6DmwJ)++For9yzCk4N>B|WY=KKTEAB; zSe;ZrV=u)e85yEfY|c1^^9hTK=YP5IH}67qDacA~llXMs^kJdZBTEs3SF4GMb@#hn zgjVa?_tRqLI6xV^-Mn51tyw`?2{r#KO$Ma#|tS+&{6j7n?1t$G{`v z&^=kmta%raM)uHI_@E9?&Uy(TBYP3$x<=6PWC(R0*c~quf!v<>@g;bbH_9WN9>5@y3mLQ&Ae{%2!XeIrT0a7QapuR{=!vLrMS{n4!LC( z^V>ws0`-2vc{{7WKdAx>kaM3n)kN5;t!#NJ-su2|7GCk3hD};MNw-b1Jh1b%0hoU% zcoda%Q)+1TyY*TutlTaj8h>qB%_IIf#P>)Inhi4E#C4marKz+0NPSI=)}2^$VEp<- zE$9P-@WKGDbH%IE-^a|fOqcCg@nT^D{n%YlvW&@mqz5s#sCyXf(uw7TS zjfkO2(uDyDqS&iBdrTlme;@iv4 z7;BacAK+Z>yq|A6pj_&`+M{r7{(XDH(^(Kb_XPE9jvd$4QCqwx(Dhof6g7MAsNA~; zmCliJj9KM3B3ufdaj4VAEKl)yrfDMlKhlzQ3nT^Ca_2u{dr4qIZcvVhGuVHaX^>Ja1~^lFks51WYZ4$cUS68a(Be!y&<&boXWq&bmSfM${{JESwq`jM_wUIBW(%BnFL^!u;CR{ znVweE6@2OS+c7=q3+ugf+!QX(x5@%jE{P0-Ts~5|kH&nwW?%~LFQ>IBwQxO`{Pwsd zO;Z%M#A;Xm0-$K{-g+id-Ru!HDTJf}(PsON^!b|wk2}8%Lu&&&y?%ic(ff5-V1ng~ zbmf10PW3tq?g~an@C7zUy^@Xr);5HXIh=1UT;;O)lkhmYV2RNhk7UukUw?vL7atqo z2^fW&cqV^dvCkdbFIp%)!aV~_)?r5Wpbmw8t#W@!4I8^`%hur@IzFik|M;q~VI2~J z7$7nC2V9xCQH*F~5~W?^aTc_j-3X-f4t2UNSjg0C;O1e2%2yx>LqSQ#Qj1Ff!r@n5 z+JPty+Lo1!b*L{vlaQlM&cyuNtgnl5$|5oWv!jU-7s#IvxosR-;&^YD;`fS8|K~W%zR1 z$h?g) zcIpvgHPS=49MJ#R8ed+xG#5N&F&Ag*b(W>< zD&l5(5sY!M^K)RxjM^=$bKymH+rL`F2aEOJoQC0x7r70(G&bMtxqLhC+iNnx>g-gT zs`s8V(xQw?R%%ML=5{zyNt3w!=L@)MWrp&*yU51^3*YHrdl*ft~u4hMVqgDNMWW z@c4a(mw_D8snHVMeJeIDq&kQbZkTSKK`N)168I=N2L#)d-F=Yq_o>vn-P_#j-J5qh ztS7G`3l>@Gm!K}|t&ZQ)-aaM0*2VH;({E6T`(gHcI}>;oE^*114xic(4H5T$jLaE} z9hM18jNxjSeAM_LlE{wpI_;zt%c$>=eG5gMpF9`?dcvJReflXZ1TjS@Ti5Ldz5cOz zBgDL4`4#iFToQC(|H&lLc!|H=ZgTFCeChxaA6g+TnECcQ#zq7j+V5&xqr-Hvur3)A zz!w`s*kz1kz@dgu(y9s^bZH8B*>jk|+#=T^O`>9~pkX}sX4)F?n+hdlQzJ#$-z>QgHV!m3)W_8x8p)kVwz!dh@0z)32rne#sk#mu_TYuul-E~eg}Ym_7D=E1K9|(urst%WPV$+ zd|=gvP=|j*tDwG@RyU}Y795gKBe>ZCP{%Mgh~=|e5;u_cQyma%hYs%&yKZ4r>uFHL+~&9aK8~W)*pt;HOI(m^y|2GiDQLOwLY5R!1o2@^8r{mDSqgxB8*)nho7H;q36$ux4KJ z7kKDJf>S`Lyq+tel4pJX19;qPJqYr2FLN>B&lAzXF2tQiK@|nl!$-Y*!x(Ek2vz8| z+x0Zz+e16NK7ZWhK8ljVPGgV(L-@NzKiO#rQ|QSl^M-TR{X-!gy>IZ$<#^M6kk(R0 zrZ8GOqFx+&0(q|$6r(}nq2U;^P6Wa&6r8-AnMOmLj>`jqSA%}*V@ zuXj;U9{;k(jPI%=^;Xv=VhhrsPGM=RSt*0gz~@kzUay9xwJEnPH)U>A%N-~zuvTYRG_t< zn&=Qr8t-=w56>lfyGXe&2i2r$$)Ooh*3;-^ z^dywR*};;Y$HflgqLN#nukTs^K&5z@`!Ri{*xcUpx|PNg z_`Vyxrwv&<`&Wn9>ImxDwWwwL#&(xBb+OuEv*H&`KJNL%=-p-n8L|2CrD!2?(5v8o z0=@6cA{*k;3VXWURt^QZ-6`!-(J~jrn8@(4{l@y?A(;0%lg{&ngG7?Cf9B`-aoawr zoh~N;g`8RFu>hcl+PP&^e-j(cH$X5H`jA3^Rq{=7OONGJF#@1r^Ki$;p$A(J2;AUJ z6x{(&$$IK(*kqOm@O-&Edmfb|C;|KK7CV^c&I|O{?`}U;Cg+0S%wm7r5Y7IiElO~uZ z$9P~Fz_XyEaj`-fgUljo43JTysA@*tzU)u6*X@ST78obi!2RBlxhLXs54sTlyX!BL zp2`D1NhHq{8$B0q62v4?w)lleTO`3h;W)*jF562xGy{q-A&rIrQf%+W(9#HA-Z#4a z8B>`FJ&QO9W7@x+_h(T+)zjY-ui+FuB97_wTvH!*D!D*=JfYA9-7NGgb{lyH*dM## z+P8R0*4Xt7tUkX(S0^&b{$@xv1y95K>LwhSHgE<6Vu^5gu!n3MyQ-5U_pT#zK{CaB zW2MCH1pbY0{xAytC{|ASB;->!j2b${nn zgC>YXgyS7R!bs}sDS+$|z+*<2xo|am&9@qw^%h$Uuii3UPF(?S0Dy@PIPzYb$h;WY zi@ROb(RYZf5MgYcy!!w)KNhNr=HYtI?rFt4s7z#>)R~w zz3T1Zqdw@-Lr+QTkF1{c5e4$BI`G$?9L@NTBc6COh!zAUoZt9`29|jU2H+;m&)}t8 zN@^?801^oFlC8A=tZcU-{TllChC8qL|BCwVa5kW}eTrH&O080>)LunxYP43(*4|X@ zy@`aP_O8aBMb+LrYL6iH9yKCnjTi~R=Y7B5`2U<|Ki74x^W5h?zW-HCI;6`ec4F#c zieV5M?0H?NsC*+05R*9fFFWKFlVVVpksHe*5Z2q!;ocxiQ~0dfP^p$v)sFV8RnmEe zA8x8<*|+&3LsTOo=Ybahr*|{!DXl%7bAVcl7LA++R|0uLBkO>no?Jfehh;&`^S|gN+(Vk40)FvQvJ#U`*Hcl}q-CMT+2O|>atkRA97A{Yr zPxCBBkrD2zdF0(0Du8H`&V|Mg#;Mlu+>K(L!Hck|$QXOVL66a%ML)edvfCe2$KQR$ zolu18VjU1Gr7-K-qEyqlecIN-1(e%U-u0#+>Q^EGtqqmU@Qu5@bGve$0I!r-=Z#GRb?wCFwo0^T8h% z4QU6xTyKV5#%R5C(&Yy4%(|B#E7Mus z<9<821`!_T?fOpBs@;^XR{R|0X`gU1`J+1^B(;RH`A0JLpQGfW>9iS+q|sz z%HVR*<)KGP3r4bdBBvL$L#CM1*i}5r3O^V&S2Tn($1D9sjBGVFcAi`or4@7U!rsj5 zSIm~uD_B^V1ffbR8%M^GgN+AbbAAZ6>?tZha)U(`_ zt$e(uUy(Mpx_XhOW=nG+>a>R*pFZlG9mz_Y_rI;Ot*kiyCsX~&9D)_RY;3%`v>NoO ztRvu(>2jQ@A)YsJD}_|VGR$;T<)sL-muq-(>o0;1W_8rxCDA55-uIS_{1rXW9_wuD zN!QCixXO}L=J-^^+@onkuK39;rpeaKKizE;n7^8;C@d*Z)L|0YR<5oFG`}ai8!F8C zj%y0`S=_!Kf8c3>b-*yd7GT(chSG0tb8k-oKzFC(Y4YQ>y!5wr>o*p)t_Ub!mqL3s z#g9imFH(%YN~}6e%4<>|jsBwMwg#J+MIK^Ai1@ePeZpaO$6u8fr+xs(P9sO!z(&&& za=(c>UCtO!Q(uf+<{PvCQKXmkR3GI+?_3kJL|+%u_?rhnF*WM*ZuDQsE=g9MA1fE< zj!Svp4&*MDEGsu%(Ez^u9~15`AkF$Ju`#}1ibV%lRSc(6Pvh)0GU{?+MAI!)3fm7x ztg$NWkw3yO6#ZRA;+mfJ@}P+3JZ=uPw^mUsu!DSw+L7-1lUE;+*jeZDv8oAE`{90`Vp1<)KKJo-> zKoZ?*t#=1|?$Qr@c5Q#>uzAG63j-C}ICgRONcgdX&fqo2EXQun=Ladb*KcmhXN~}^ z?(p?VtNNDmcheiT&y9CGJoEwCEK=$CmE zR@7_?+cc@z{i3(vrxmcu$CsPgaV^wk=8`S4?4vXyc}V|l@w;@DV?-A`5ykVFbn{yi@YH!tqPSHJEZZWm+i}cwl8B^)R|OaNAX(xIrB}7c)Uz zFA^RB%>W|`)g7YcJ&qs+Bbpb-EOHNwX2QB7X)+FbbOLSa)0~>8t z|K3dSG?WiRf*fa7Q_&x%e_fs~M*Z%X+CP6TbK5`~R11wTKN5wO6dYev$$?~lf?CtP zye7L=ZU%3_WGA!03WO#T$Sg=bA>y2y;yd^0e6-?t{RB_8K}7J?vt?9nc||W6^tV3Q zd`|tR--e;3mg*)x@CFs)%4;5Uhe^B=01I4$BNe9=|0`}Aig<`Xrd1Q~3-yI(7$0y} z>CMDb*@qCs_D2M#A}M2Gu8qrGEha0!2!ZX2b>Hnx7fdjhyxfIi^SN?NOI_0EKm8}W zI+Sjq#aFk`jM2}Zqr1KlPhPn1!l(CGZlU-nN1foy)A?;f-rI%0Y47@W;@<$Ys3lYS ze%BnIH525es+ejfM#J9k2Q#;7J~7_Z*;}VlGI%P>WyAF%4SKwLEfx7Vuk#XvPP&7$ zNIErrk(k7MkznaHFSvutDu<^vb-b2wF?lj*{!bP}WcSeB_^5r7XID4D7|}~#=v2|d zk0aw|gY^f#iqHhzU)+Zd;MCh_kH7`Tnas#fhLVXIkaJwviMh1_ZhbNMq z88TH~-xVG_d}x$Hb!+iwJl~?}M}lh04QLN%*@bF&Svcl9(9%Dose!GriKPgy2>vbT zUX%W>#IE<|57`b+7xTz|bj|h(SPNgr+F>sx?M)KViAHcu4&RDGr z)u(399%}2!;h9&bN4Q03(c@WZqup(2MDV=GK@Vi6jJBp)Ec|v?HRE8QJ46W3DgXpUZH6aP@az4gy2pgE z1~T}rAARD?pxUosRVFZ!3 zkX_%wj6JM2DYi?lJ5z{xMW~#@Q)4g%{oVF(Cj>Fo9CJqBo?L94IGyoXWC~Qf>XD6h z=2ZU>$b;YvDr6(Ss6m4q$Tw-J%2T=FQL=+{V}@y+%Od&Nq+3IIAO{FWWjqK??^};eeEi@49i8vkOfOWak5H)gb3>oOwxGu=EIZT@6R*@@d_wPOFDVzcGg<`x zC2!Mf_=U2xtiUlpi zGe6h=3f-eK2_3L)bcui6N3~GO0oDe{Dx&&QlxbImX%a!yb7f|mdS`GkorkJEH`TA8 z9ouODm`lrbTUPUyd5Go~u=~9pG19fxHg(Q@rG1AaLZ8u>Eu%e?tDhD2Xa6Wvh?>-? ze;}dy@l-~bm~=S8nlsuZfqmZk`Rgq0-BbXYWUK4m83K?IVIo!*Yjoxpds)qwP)m?< zcFuN*Qot-K;`8^78>%*WQYU9>fl>sztT0!3W8i8NvXs&{b`_;$um?k;v*2_VSP(#X zZ7n8Kj6J>b(F@538!j@Ds|FS2z7Pg3)~|NmdB{TY6a(6@+wD)!AuE3CR}%#*UhE45 zzYAuXc1laRa>Ff_(PyXkUO)`xb#{&bS^uuH1?3UNcHV$mjfL(M6iT=LTLAJ`o7{iV z@G}Ya_qOo9I;4Q_5dgjFH120nd*>%*Va}#j?tj<8p{``9#mBAv&+Z>=Ok&FQ3OANb zjdyPhL1fHw8R+MiFLzaRFy?1bd1s#w3P?Xo%Vx>~R5nmY$Mpc!%#6o*2MzN0q`iJo z@{@5-xMVPTT{`Ks*~%{DNx4^||MAQk;NO6IE1iw8hy%`q(zyyRm303R<1#p~vv$|l z^iu%IFqz^%X{Yjn9*|C}24x_*pCAbr&m)5_nkoP>ow)fA{a2gbG?Q1%HT&A%xiAwH zHg(yfL7mq9evual$c-g>>1@@Yq}&TcH`gW2(73}C2$$afuz;UjH9?mRyK?@A{loMk zPK}rAt%Os*pW96;D3||w&3+BA&*4Z&aURDVBNg@&FniUjfTe03NOY(A?6w$5wcdH8 zbr;YU(xAI6e8QmWyVHrNHW(1i!ABTNWz8D$l0TYqBkpDudoU*7`yixjWHpgyhjeei)h+05nz2UCHwm#jt4YPM5=E7s`kmvYb=M@`A%$=|VmzxgZ?*){nl-yCvtiUw*Zg35aX^1cJkUmmV zdPGR-!La>F+$x#;Q5hHa8AVk3>}3r;IZ4rKS(Ks6PweD;=4U>nNgIRg#MnO{>Fg=F zZctody;w{up^)dZHi;48Lu=|-VQ;wnW#ec^b-kjd}YTqo;1IDVb6!NOzxUqb7rcl|D_^!(dkM(PYCKBUy&Z^CO?tm2X)TP+K#3N`@4ay*94Yw@*B01hN{ z3_ZPrK?(=e%7oT7v=uesl|jR74rPQKrP0TkX!n+n&TLj2!w5<}q4B_~kuYiz$Abee zNqntsa2B$342`h6WWAYBOKbVcz|#6jU!S7fk(op51dt8@a8A)i8&UvzHnv(Me`?&v z8c#SKW-8ru#r}V#-N40!FrHPXH?T~6G-CF{P{5g2*MtOnjCFkfpcI3=a>bwrUB#)xMeW_zS)1^}vO1etPK>ftdm7 z7A<|W<`YQe=G2Z`Iubh?N0%u4zumCqtiy50n>T?OpC)6&cyOB{v$L*CBnc+G<*l+;B|-2Flz?UizF;AIm2^_w)4F79^jbrpa~A` za9S2CI&YKA017YV9)mHDVm&y;>t`;{a$qohNsh|ot~)+ZNQL8v$51Puh{8g5|dM6dn32u3LG%8E!ww= zRFRmym@0GnZ{?qH^w(bP8pO9tlUPPs~>`Gw#MxQ@0)iEEPbf*8AaXg ze7#z`n4XekLcmbC?+4#+wx600^3rcZq3}Qy-VGDxZnoI;U+q^3tS7w#?Ks9W-MadC z2O>P&-E*HcNQce{|6ZpzsXmdD$fvC4KsfhD$Om6$c{NFtnJO$jKtW<6c*ZbA$_j{d zS_cO2b~3&@DeS!1l(weV-gORyn@dOfH?>1Wlru zj8={ZjKZ^b<3690E7+DwZ*Sf}@`Ca&SDZ$|oJ_B@u9e}5?Kgqq?SMMfx@wU0!d=RX zE&=|KiZ9K-_~%`9Zbx=(z~=w#rneWkYxP9~!J?ZQwjEdu2YGDUFZd{j9L+n;K~x3_ zK^{@r#dfO2x%>}RRr?#4O9DmYfvw5k=CmS8&BA*^D95Fl)OMTQxD5b5OIvCyIzPbU zc-;GLe1%Bj+R=p=i6o8VUS9(q?&Ix;-;x&Pj;%?UX|jq@ZJveBU9o5RE9T|q)#1Pp zBiHw}d3U!5X7fU4-o~L?SD>GC2D05XmBoAAF}w#II0YfyK^>i)IAIowAC37*$)C0O z-yTs_`%y=d~z;FwlH1y`WS~#I;iMPE8?80TX{E*F^0KZ0vGHi_RET znlYNDtH>0}-ZXeM%^u`@X`ajcgWAF2`&Q&9s9FlLIZeOj3lwzgN*#O7s09HQ{pr~C zdfr~GRt~+iXw0+!>@Wx%1^mOSMDaZ4YHZHK{;f0XKJh`n^v9wc_sQt8SgtKeo+$IN zi{LLqS@S6(z2$X~Qf!yHW~a%gd#B9icc{GS8~O=-+fLl=w^%Tbzl?)s>_Q7f11_%J zsO`q<$}s(oRAkyTas4I4+_!JeM#f;oV^)us4bdB|Y~3OBT3Qq?EA1_YjV5=&m)#|J z^;{hPtaS06=cL5VSVR*#fGsD84!N`xy%eh?vzR<{yf$xzx<>hTFUkj>(xNM^TZLK< zhK6gSaB#5qKJDU-)RmFnmQGM*Cf_O%Z3VXB+(-`Jghd{cnFjr?tM!S1c--4z?pVgw z2ako-QD^^RU+U>h3wXBP+-m)sI!}OLMrCVDMnsHdSwPK@v7{p44s6*z!d5TnJru=; zP-nJKU@77J@KG|wIV39@+nz}G>Y!}H*>=$B=CISH$-W_$FyO^J`3ID{ewPtBW_ufV zMTXYldVtk8B`Z?Z6%|glA#qk}^pn%9USQ$o%hMKrAwy#Rmp$%wd;zLYY}^x4 zbNjj{sab<~`{ZbcEOGJksPUZ0Jiq0i$IIuyU#TlAA(|TAE}jZ*D)`>J!oq_y@$NFI zGK&?NL@tC4A2LljpGa9ji_dcaX46313cYydj`>f_etfnL*HJ@q%)WB2F2NJt+YW%m zi!grjs^B!1b^YzJoAca){`DeuCcKz^8*}sY@LUXSNJ>X|TZX?tVjM4`SD`5tr>AfK z_m!k1|In2ZbXYQ{rJ4w(S5TA}#g3{;#9x1}lU<0Ftk75TiujZ!+&}#)!h?2xvbSG+ zTkGTJ#o$UmJ{TY{#h8HT+rEMQR@I#K{PUJ{5!{kaWgG(ohfAG zV<#grMcT8s=Cz=rV;ReA7G+pS5Zkjy=gDx}YZFpqrUG5ycm7foaBx7n@6tK&xaoHbXE&mQ&WdpY=DF|iYg-Xv@V_0 zigmq|5Cna+NcBtoKyO8j^kxR@{KGLlyHxrJJS`{l;zNn}SEX}^VLnXuF%jObLKF~( z?ra_WTK}FZIpoudvegv!wwAX&?=MK*tvYp|_cr$R*$q~SfX*@}RBnPAYblc8Z4JQe z2l0^=))4Wv$yDmgCXefl$Z8Ol0!%qefX7cY4!Hz zcxLb15IXGQ@rrXOOq_`0wtf~a%=hSmE~7F>PIZxCfn?SP8)ya>JFHm3CcenR^bV!v2HzRq>^qjg*N8+ zIQaFqz28$?2)1W=tUSXavY4--`gIz&EWCki*d$dJRjU;=?ll29(WN^)P4})TnW|AY$d^{<;bj5EQv@8{>{9tQM{7B=yF91x)Kpn4jICcN1mp921CCmb ztTuhzG|sHP){To@qVk319;nVnp8Wty3uvuJezvo-kWYAFyB>L!CoCx!kk5<{wM66v zgg+IZ5a=6WngCF3$FOYogLDbdJP3}A0@=<`oE*`lgneFIQ-Qq~Y|}@Vy$kp~f&!;I z+&$i+a_AbwRW89`9%Wa44N+l!ZtLeMxamnCWwg?4vb(q?oX`%iv={E)VB1QpEHB2Y z3rFn{RAq9#PEX;tC;lFb0rCiH&9KmMuw6_Qa1OZhb8E7069J+#NGWlvzwcImPv*>s zIKPQv+8C;OVL)*Po_v{9XmN+zD@z|wv|Wb`13hn-QB{@`!lD{VOuQetN@U>({kd1? zW@*a=>P|Eynh|v66>g3DFE+V^O%io(=h1l;JR26KfN zs=HR0vs)Oa3D}zcX8pK;xj0a!&>c1^1XZ=)3{Cq^b8*f8G=I!C|IB6vl^g@d=e;^! zX$?LmIP*UL*WKMs;-h-!jw?Y0<#Yb&-9fLHlt`Pjg}VB;4s2st= zt;_vM0dC?YQ7^9zrM)hW)1Oi=W?gdJJ(+9byB581Of~xw*36sn?djId%>x%ah;+

=_bmLv#=QE`8(m}xLlam9TugG1_Dr__3YjJbETKm9(5q`pd= z`y&X01bGu*VUP`XTr4!c#VQy_L?n3O&dgZ8%2zhvNHz`CnCzXIgp7J5k&wu9dbmHp zB45urG~MwY2EiTp^zXj4e`QY8`073X$ElF!s&g>bp)AKmQSCU(&+=3jNkiPx`$uGv1sA2JFNI_yJ?4)34$Gv_O zMxr2R^}H|s;f_qa`D+c7m9VpVbIOf!;@d|y3c_yuB_vhv-j8sP(El0SKW%> zjJy%&b@GDM^_rFEakmDR#?b8LJ)`8T+vT)FD8st+5*h(JjZUI8!|}vE-}&aDkZZ!R zjo}nE{Ff&Rxjzn)c)^L|-ua!&QlmGk#D$0HhjKfP%OzAJGP{RgY?`?+JuqWkdgX~Z zHZXn>;#|Y=>g$RqNrybIY+f&dwq|^;)gLe2;IQ`Me36rl{{5oO(>IZ&s36^Yfe)=% z=VsGw?}{hEGss3HQbF)pf(zEIu*VKAq|=mIG=jOZvuI0OL(O%w#+g>E`m3d4cZkB5 z08E)FN$}Rdi?kj{f?BO79Clu6;c*idR=%KY)Cz1s(ugufCm~UfB=i|&WCN7NVkC>+ zCLF74yoc_I9TRLeAE$|EKtIQ1hWb=#^FC8}_k7;EG$lfvyP(eZ8>~tw_|GI|{;3?~ zMpJmGd)I7$n0w;K=adz8Jbw-VO{D@ap@DTu=j{T!Lzr|V86Hh&s`2P+y8OZ8XzfBT zktgR9nf;9RkIG|t(=t2>rS+bK{hTAj2!NaIB&%o>e6o!+jk1!dOe1)<*mIh`7dVZi zosTAq2tKh8<5xKP7n`*?xb`dYUsp@j;cSaWi+TIaMK8?a9#We!2_@^M$jB}^_-rTR z2e>;^%(dvfyv@r6fIbS4pILJ$H`G3AP>fJ`;Kd!0F1;ZSqc@?iU*NNji~~wP%~%J- z>@8JnJ7HUoQrAxoZAeg-Qq*`T$&;4*`2OO5sui+WEAy|PUx=R4l;k@f!vWI|bn7h* z1_+Cu;nx(hr%Mg-P8QnZj=0vh%k6^{`#)wAmLH1PN}E;eg<nDys)6QAvIW1Z*k?|KxK z+!zlU_3*e1EG$B)|NIf~i;S`oYHuKK!)1T|QRL%D7=_wn)&eElZ=wrK%-59{=b`L9 z_Sv<})BwPp*gkOq`3Whu+jlj*JOu;|&7PpdWUk{q|1>a+kvxWj^}&JFjk4*Y!-pv% zN&cQhmY3BMAtgRUHnLafuh$b2qe?}elfo*cuim7c3A;0I24(NlpG3cD@7>`N1&JwB zneB=NC%rCar6%>>a4R?}|0$ZhzkONK|0mpk#&eNeq|=0ZQda(?S?@AF+37&}xvQCE z8AH69ao%){waxxG5PHGcuTaZL{M_#;E1rtmx1XQdWWNRT#aF&olxnix=;-EQFkC)9 zo#z3FTlT+j&K{{Nt!FtnT#j92tD%vRePG_e0YU6@aw2Zd(Z3;%J}f#uDKMK( zr;Jz8BJW^xN72slr59$>HCzH~nrP8h<5STpWC1s3Sm3K|)1%H!L#XZbRV5#ubWh~k zT(6H0eS?pa2x~e;7Pu%wbz0Qct~KR#OX2J8ho|LJL&GdvmD+vZ48{}VtLGyX%pNr| zLpoYpOkw;u#YXNj+9Xo1{%LIemRK7EJ7!||HXn5&Q9$h* zK9NU$&VD0}`#tBU7y0n!aqx;rLh>F+jo_Us4cV%}VXo$=LKE z>`hG-`2}2~Lz^3MbZ{wp7L7MLa)}ceIPxr`YvoD72GCDrNNJ8SNV4Gem5axoxxSFy zEW%xaf802-f=0mXx0hjo8HFWspR3fVTjHo;vE*u}?%3|idU4X7JSMVtf7J0|z`k2R z$x|jD0?9JoieNG^AT)Q+*$z0mM0>_7K6!);D0XamJc0NQ|j7kNM&|4V(YNMESq|zq|-mUpM5=kI|Ytz%sebQ=B zOqD9*Ubr~bGBdq1j#VR-&ppuRCvMrh#Z6EVXRb z{yHH2PMX0{wx+Q~d|g$qowI}sp*iC8S(3930zZfVdNbJv>!0jB<@Z#as+Zu?Y#ek z`SE!g5dfoA+^rM)timu@KY`3fNFNV&K=|DQW>0HH852X#oUyV)n?+Bg-B*xzJD8G6 z&y0&J$2*BGki;%Y{cyU>`tg-h@{;~n6dgEzJX*+ZF-9Jcnw3VjDlQJZ&Y|CZlbUri z797_dWnOo;_=`O-!Yn%GI`}L91tRdx{?+kg7*o2=pFlA5O)9n&s}N@6=mnt3@JSNr zdy@EN`$S&tlG=x_zp|*}w)VGt9S%P_mMn3?lL%jsDoXdr##^yL26t5_00ZG4_v>1ga+R zK~22-5JE$I>yKFOhk>ijg0_P;<%u)#Ic$$fS+jm`FEeSHkc2G80)Ah6 zL<5KPHV288MbtShIT7v#ZB)%Bp$Y95AHx;WI$xG}2$gtZzYoh|)j3!_dc~HYt9czt z`OXwKbTaSSkETEU>p?|#jaz}RG4ZeFlA<6!Ks|B~#u1*_JJ_7(Uue<(vLtE?WIEh8 z%S+WhbI8$QI(nBjh-Y`FL2x|_YvMzWE^Zc}ZlN1L|Mct;9e4ck##$&Qt=fnk*_W;i z!7G1?&F&zn_*RDeSiv@B>=n{fn=#Gc(3@W?ki)c2whOMyIRuk^cVlR*Yi4nI{APof z%1a^(-uYLOuG%34v*Id$UGox39<;oprGkC4oK*ul{MCp$n%7muqJ0?q1z(fk?|U+n z2hVyu!t^=#=>7rAg4#Q?*Xuy7Ri(NvrALA`L*Yax5<^J(Z!#(m+>yPzb;I6#;kK0A zq-N3cW<=_%B!DQz&&*=9j{k~-3#%34pYR&NEUoyn;49JK@u=^SMRwV?_pZF4q^v4# z_+CE79v6}JU5+M)16gkSm^>5oX&r@f{8QW1;xtCJSzN)hOgg=_^F?yCC+& z=&`Q|=0$#yBX8Ll&e7b*@4RZC4{(3z;g6+8qKEYJ*u5tqfx=ZjQj{8%orlLSc=g97 zRb)ZrLdIz#!x?%Ka)KN>+kCUla(53Q&(#QZ&@9O@JM?qMROKZOfq&3kY=Kc6K#gRN zHH!ouz(%scN}lEcz1$u7FKLC*cI|WVj{=5Zy}(_sQ?KVa?~B~$Y;<`GFB3-|ZIhh^ z&U9OsE*(7^^}T!tIu@|_+10$1am@Tpo-k2DeH?MyZmLt1hu#@@z<#&px=gzbCD}sJ zZnbg3x(7Ufz|9ic`1*z(fy$q42mkbRt> IVEOfb05;1v*Z=?k literal 0 HcmV?d00001 diff --git a/docus/docs/tutorial-extras/manage-docs-versions.md b/docus/docs/tutorial-extras/manage-docs-versions.md new file mode 100644 index 00000000..ccda0b90 --- /dev/null +++ b/docus/docs/tutorial-extras/manage-docs-versions.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 1 +--- + +# Manage Docs Versions + +Docusaurus can manage multiple versions of your docs. + +## Create a docs version + +Release a version 1.0 of your project: + +```bash +npm run docusaurus docs:version 1.0 +``` + +The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. + +Your docs now have 2 versions: + +- `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs +- `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** + +## Add a Version Dropdown + +To navigate seamlessly across versions, add a version dropdown. + +Modify the `docusaurus.config.js` file: + +```js title="docusaurus.config.js" +export default { + themeConfig: { + navbar: { + items: [ + // highlight-start + { + type: 'docsVersionDropdown', + }, + // highlight-end + ], + }, + }, +}; +``` + +The docs version dropdown appears in your navbar: + +![Docs Version Dropdown](./img/docsVersionDropdown.png) + +## Update an existing version + +It is possible to edit versioned docs in their respective folder: + +- `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` +- `docs/hello.md` updates `http://localhost:3000/docs/next/hello` diff --git a/docus/docs/tutorial-extras/translate-your-site.md b/docus/docs/tutorial-extras/translate-your-site.md new file mode 100644 index 00000000..b5a644ab --- /dev/null +++ b/docus/docs/tutorial-extras/translate-your-site.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 2 +--- + +# Translate your site + +Let's translate `docs/intro.md` to French. + +## Configure i18n + +Modify `docusaurus.config.js` to add support for the `fr` locale: + +```js title="docusaurus.config.js" +export default { + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + }, +}; +``` + +## Translate a doc + +Copy the `docs/intro.md` file to the `i18n/fr` folder: + +```bash +mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ + +cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md +``` + +Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. + +## Start your localized site + +Start your site on the French locale: + +```bash +npm run start -- --locale fr +``` + +Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. + +:::caution + +In development, you can only use one locale at a time. + +::: + +## Add a Locale Dropdown + +To navigate seamlessly across languages, add a locale dropdown. + +Modify the `docusaurus.config.js` file: + +```js title="docusaurus.config.js" +export default { + themeConfig: { + navbar: { + items: [ + // highlight-start + { + type: 'localeDropdown', + }, + // highlight-end + ], + }, + }, +}; +``` + +The locale dropdown now appears in your navbar: + +![Locale Dropdown](./img/localeDropdown.png) + +## Build your localized site + +Build your site for a specific locale: + +```bash +npm run build -- --locale fr +``` + +Or build your site to include all the locales at once: + +```bash +npm run build +``` diff --git a/docus/docusaurus.config.ts b/docus/docusaurus.config.ts new file mode 100644 index 00000000..4058eac5 --- /dev/null +++ b/docus/docusaurus.config.ts @@ -0,0 +1,133 @@ +import {themes as prismThemes} from 'prism-react-renderer'; +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +const config: Config = { + title: 'My Site', + tagline: 'Dinosaurs are cool', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://your-docusaurus-site.example.com', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'facebook', // Usually your GitHub org/user name. + projectName: 'docusaurus', // Usually your repo name. + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + blog: { + showReadingTime: true, + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + ], + + themeConfig: { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'My Site', + logo: { + alt: 'My Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Tutorial', + }, + {to: '/blog', label: 'Blog', position: 'left'}, + { + href: 'https://github.com/facebook/docusaurus', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Tutorial', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Twitter', + href: 'https://twitter.com/docusaurus', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: '/blog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/docus/package-lock.json b/docus/package-lock.json new file mode 100644 index 00000000..01663dca --- /dev/null +++ b/docus/package-lock.json @@ -0,0 +1,14796 @@ +{ + "name": "docus", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "docus", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/preset-classic": "3.2.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "yaml": "^2.4.2", + "zod": "3.23.4" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.2.1", + "@docusaurus/tsconfig": "3.2.1", + "@docusaurus/types": "3.2.1", + "@types/node": "20.12.7", + "ts-node": "10.9.2", + "typescript": "~5.2.2" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.3.tgz", + "integrity": "sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==", + "dependencies": { + "@algolia/cache-common": "4.23.3" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.3.tgz", + "integrity": "sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A==" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.3.tgz", + "integrity": "sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==", + "dependencies": { + "@algolia/cache-common": "4.23.3" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.3.tgz", + "integrity": "sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==", + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.3.tgz", + "integrity": "sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==", + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.3.tgz", + "integrity": "sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==", + "dependencies": { + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.3.tgz", + "integrity": "sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==", + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-search": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.3.tgz", + "integrity": "sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==", + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" + }, + "node_modules/@algolia/logger-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.3.tgz", + "integrity": "sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g==" + }, + "node_modules/@algolia/logger-console": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.3.tgz", + "integrity": "sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==", + "dependencies": { + "@algolia/logger-common": "4.23.3" + } + }, + "node_modules/@algolia/recommend": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.3.tgz", + "integrity": "sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.23.3", + "@algolia/cache-common": "4.23.3", + "@algolia/cache-in-memory": "4.23.3", + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/logger-console": "4.23.3", + "@algolia/requester-browser-xhr": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/requester-node-http": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.3.tgz", + "integrity": "sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==", + "dependencies": { + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.3.tgz", + "integrity": "sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw==" + }, + "node_modules/@algolia/requester-node-http": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.3.tgz", + "integrity": "sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==", + "dependencies": { + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.3.tgz", + "integrity": "sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==", + "dependencies": { + "@algolia/cache-common": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.1.tgz", + "integrity": "sha512-QXp1U9x0R7tkiGB0FOk8o74jhnap0FlZ5gNkRIWdG3eP+SvMFg118e1zaWewDzgABb106QSKpVsD3Wgd8t6ifA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", + "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", + "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-typescript": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", + "dependencies": { + "@babel/compat-data": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-syntax-import-attributes": "^7.24.1", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.1", + "@babel/plugin-transform-async-generator-functions": "^7.24.3", + "@babel/plugin-transform-async-to-generator": "^7.24.1", + "@babel/plugin-transform-block-scoped-functions": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.1", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.1", + "@babel/plugin-transform-dotall-regex": "^7.24.1", + "@babel/plugin-transform-duplicate-keys": "^7.24.1", + "@babel/plugin-transform-dynamic-import": "^7.24.1", + "@babel/plugin-transform-exponentiation-operator": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-for-of": "^7.24.1", + "@babel/plugin-transform-function-name": "^7.24.1", + "@babel/plugin-transform-json-strings": "^7.24.1", + "@babel/plugin-transform-literals": "^7.24.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", + "@babel/plugin-transform-member-expression-literals": "^7.24.1", + "@babel/plugin-transform-modules-amd": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-modules-systemjs": "^7.24.1", + "@babel/plugin-transform-modules-umd": "^7.24.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.24.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.1", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.1", + "@babel/plugin-transform-parameters": "^7.24.1", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.1", + "@babel/plugin-transform-property-literals": "^7.24.1", + "@babel/plugin-transform-regenerator": "^7.24.1", + "@babel/plugin-transform-reserved-words": "^7.24.1", + "@babel/plugin-transform-shorthand-properties": "^7.24.1", + "@babel/plugin-transform-spread": "^7.24.1", + "@babel/plugin-transform-sticky-regex": "^7.24.1", + "@babel/plugin-transform-template-literals": "^7.24.1", + "@babel/plugin-transform-typeof-symbol": "^7.24.1", + "@babel/plugin-transform-unicode-escapes": "^7.24.1", + "@babel/plugin-transform-unicode-property-regex": "^7.24.1", + "@babel/plugin-transform-unicode-regex": "^7.24.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", + "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-react-display-name": "^7.24.1", + "@babel/plugin-transform-react-jsx": "^7.23.4", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz", + "integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-syntax-jsx": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-typescript": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.4.tgz", + "integrity": "sha512-VOQOexSilscN24VEY810G/PqtpFvx/z6UqDIjIWbDe2368HhDLkYN5TYwaEz/+eRCUkhJ2WaNLLmQAlxzfWj4w==", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.0.tgz", + "integrity": "sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==" + }, + "node_modules/@docsearch/react": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.0.tgz", + "integrity": "sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==", + "dependencies": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.6.0", + "algoliasearch": "^4.19.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.1.tgz", + "integrity": "sha512-ZeMAqNvy0eBv2dThEeMuNzzuu+4thqMQakhxsgT5s02A8LqRcdkg+rbcnuNqUIpekQ4GRx3+M5nj0ODJhBXo9w==", + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/generator": "^7.23.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@babel/preset-react": "^7.22.5", + "@babel/preset-typescript": "^7.22.5", + "@babel/runtime": "^7.22.6", + "@babel/runtime-corejs3": "^7.22.6", + "@babel/traverse": "^7.22.8", + "@docusaurus/cssnano-preset": "3.2.1", + "@docusaurus/logger": "3.2.1", + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "@svgr/webpack": "^6.5.1", + "autoprefixer": "^10.4.14", + "babel-loader": "^9.1.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "clean-css": "^5.3.2", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "copy-webpack-plugin": "^11.0.0", + "core-js": "^3.31.1", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^4.2.2", + "cssnano": "^5.1.15", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "html-minifier-terser": "^7.2.0", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.5.3", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "mini-css-extract-plugin": "^2.7.6", + "p-map": "^4.0.0", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.5", + "shelljs": "^0.8.5", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "url-loader": "^4.1.1", + "webpack": "^5.88.1", + "webpack-bundle-analyzer": "^4.9.0", + "webpack-dev-server": "^4.15.1", + "webpack-merge": "^5.9.0", + "webpackbar": "^5.0.2" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.1.tgz", + "integrity": "sha512-wTL9KuSSbMJjKrfu385HZEzAoamUsbKqwscAQByZw4k6Ja/RWpqgVvt/CbAC+aYEH6inLzOt+MjuRwMOrD3VBA==", + "dependencies": { + "cssnano-preset-advanced": "^5.3.10", + "postcss": "^8.4.26", + "postcss-sort-media-queries": "^4.4.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.1.tgz", + "integrity": "sha512-0voOKJCn9RaM3np6soqEfo7SsVvf2C+CDTWhW+H/1AyBhybASpExtDEz+7ECck9TwPzFQ5tt+I3zVugUJbJWDg==", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz", + "integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==", + "dependencies": { + "@docusaurus/logger": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.2.1.tgz", + "integrity": "sha512-FyViV5TqhL1vsM7eh29nJ5NtbRE6Ra6LP1PDcPvhwPSlA7eiWGRKAn3jWwMUcmjkos5SYY+sr0/feCdbM3eQHQ==", + "dependencies": { + "@docusaurus/react-loadable": "5.5.2", + "@docusaurus/types": "3.2.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.2.1.tgz", + "integrity": "sha512-lOx0JfhlGZoZu6pEJfeEpSISZR5dQbJGGvb42IP13G5YThNHhG9R9uoWuo4IOimPqBC7sHThdLA3VLevk61Fsw==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/logger": "3.2.1", + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "cheerio": "^1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.2.1.tgz", + "integrity": "sha512-GHe5b/lCskAR8QVbfWAfPAApvRZgqk7FN3sOHgjCtjzQACZxkHmq6QqyqZ8Jp45V7lVck4wt2Xw2IzBJ7Cz3bA==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/logger": "3.2.1", + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/module-type-aliases": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.2.1.tgz", + "integrity": "sha512-TOqVfMVTAHqWNEGM94Drz+PUpHDbwFy6ucHFgyTx9zJY7wPNSG5EN+rd/mU7OvAi26qpOn2o9xTdUmb28QLjEQ==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.2.1.tgz", + "integrity": "sha512-AMKq8NuUKf2sRpN1m/sIbqbRbnmk+rSA+8mNU1LNxEl9BW9F/Gng8m9HKlzeyMPrf5XidzS1jqkuTLDJ6KIrFw==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^1.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.2.1.tgz", + "integrity": "sha512-/rJ+9u+Px0eTCiF4TNcNtj3kHf8cp6K1HCwOTdbsSlz6Xn21syZYcy+f1VM9wF6HrvUkXUcbM5TDCvg2IRL6bQ==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.2.1.tgz", + "integrity": "sha512-XtuJnlMvYfppeVdUyKiDIJAa/gTJKCQU92z8CLZZ9ibJdgVjFOLS10s0hIC0eL5z0U2u2loJz2rZ63HOkNHbBA==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.2.1.tgz", + "integrity": "sha512-wiS/kE0Ny5pnjTxVCs8ljRnkL1RVMj59t6jmSsgEX7piDOoaXSMIUaoIt9ogS/v132uO0xEsxHstkRUZHQyPcQ==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.2.1.tgz", + "integrity": "sha512-uWZ7AxzdeaQSTCwD2yZtOiEm9zyKU+wqCmi/Sf25kQQqqFSBZUStXfaQ8OHP9cecnw893ZpZ811rPhB/wfujJw==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/logger": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.2.1.tgz", + "integrity": "sha512-E3OHSmttpEBcSMhfPBq3EJMBxZBM01W1rnaCUTXy9EHvkmB5AwgTfW1PwGAybPAX579ntE03R+2zmXdizWfKnQ==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/plugin-content-blog": "3.2.1", + "@docusaurus/plugin-content-docs": "3.2.1", + "@docusaurus/plugin-content-pages": "3.2.1", + "@docusaurus/plugin-debug": "3.2.1", + "@docusaurus/plugin-google-analytics": "3.2.1", + "@docusaurus/plugin-google-gtag": "3.2.1", + "@docusaurus/plugin-google-tag-manager": "3.2.1", + "@docusaurus/plugin-sitemap": "3.2.1", + "@docusaurus/theme-classic": "3.2.1", + "@docusaurus/theme-common": "3.2.1", + "@docusaurus/theme-search-algolia": "3.2.1", + "@docusaurus/types": "3.2.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/react-loadable": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.2.1.tgz", + "integrity": "sha512-+vSbnQyoWjc6vRZi4vJO2dBU02wqzynsai15KK+FANZudrYaBHtkbLZAQhgmxzBGVpxzi87gRohlMm+5D8f4tA==", + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/module-type-aliases": "3.2.1", + "@docusaurus/plugin-content-blog": "3.2.1", + "@docusaurus/plugin-content-docs": "3.2.1", + "@docusaurus/plugin-content-pages": "3.2.1", + "@docusaurus/theme-common": "3.2.1", + "@docusaurus/theme-translations": "3.2.1", + "@docusaurus/types": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.43", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.2.1.tgz", + "integrity": "sha512-d+adiD7L9xv6EvfaAwUqdKf4orsM3jqgeqAM+HAjgL/Ux0GkVVnfKr+tsoe+4ow4rHe6NUt+nkkW8/K8dKdilA==", + "dependencies": { + "@docusaurus/mdx-loader": "3.2.1", + "@docusaurus/module-type-aliases": "3.2.1", + "@docusaurus/plugin-content-blog": "3.2.1", + "@docusaurus/plugin-content-docs": "3.2.1", + "@docusaurus/plugin-content-pages": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.2.1.tgz", + "integrity": "sha512-bzhCrpyXBXzeydNUH83II2akvFEGfhsNTPPWsk5N7e+odgQCQwoHhcF+2qILbQXjaoZ6B3c48hrvkyCpeyqGHw==", + "dependencies": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.2.1", + "@docusaurus/logger": "3.2.1", + "@docusaurus/plugin-content-docs": "3.2.1", + "@docusaurus/theme-common": "3.2.1", + "@docusaurus/theme-translations": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-validation": "3.2.1", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.2.1.tgz", + "integrity": "sha512-jAUMkIkFfY+OAhJhv6mV8zlwY6J4AQxJPTgLdR2l+Otof9+QdJjHNh/ifVEu9q0lp3oSPlJj9l05AaP7Ref+cg==", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/tsconfig": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.2.1.tgz", + "integrity": "sha512-+biUwtsYW3oChLxYezzA+NIgS3Q9KDRl7add/YT54RXs9Q4rKInebxdHdG6JFs5BaTg45gyjDu0rvNVcGeHODg==", + "dev": true + }, + "node_modules/@docusaurus/types": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.1.tgz", + "integrity": "sha512-n/toxBzL2oxTtRTOFiGKsHypzn/Pm+sXyw+VSk1UbqbXQiHOwHwts55bpKwbcUgA530Is6kix3ELiFOv9GAMfw==", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.1.tgz", + "integrity": "sha512-DPkIS/EPc+pGAV798PUXgNzJFM3HJouoQXgr0KDZuJVz1EkWbDLOcQwLIz8Qx7liI9ddfkN/TXTRQdsTPZNakw==", + "dependencies": { + "@docusaurus/logger": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "@svgr/webpack": "^6.5.1", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.1.tgz", + "integrity": "sha512-N5vadULnRLiqX2QfTjVEU3u5vo6RG2EZTdyXvJdzDOdrLCGIZAfnf/VkssinFZ922sVfaFfQ4FnStdhn5TWdVg==", + "dependencies": { + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/types": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/types": { + "optional": true + } + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.1.tgz", + "integrity": "sha512-+x7IR9hNMXi62L1YAglwd0s95fR7+EtirjTxSN4kahYRWGqOi3jlQl1EV0az/yTEvKbxVvOPcdYicGu9dk4LJw==", + "dependencies": { + "@docusaurus/logger": "3.2.1", + "@docusaurus/utils": "3.2.1", + "@docusaurus/utils-common": "3.2.1", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", + "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.25", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", + "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "dependencies": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.0" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", + "dependencies": { + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", + "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", + "dependencies": { + "@babel/core": "^7.19.6", + "@babel/plugin-transform-react-constant-elements": "^7.18.12", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@svgr/core": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "@svgr/plugin-svgo": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + }, + "node_modules/@types/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", + "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.3.tgz", + "integrity": "sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.23.3", + "@algolia/cache-common": "4.23.3", + "@algolia/cache-in-memory": "4.23.3", + "@algolia/client-account": "4.23.3", + "@algolia/client-analytics": "4.23.3", + "@algolia/client-common": "4.23.3", + "@algolia/client-personalization": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/logger-console": "4.23.3", + "@algolia/recommend": "4.23.3", + "@algolia/requester-browser-xhr": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/requester-node-http": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.18.0.tgz", + "integrity": "sha512-ZXvA8r6VG46V343jnIE7Tei8Xr0/9N8YhD27joC0BKxeogQyvNu7O37i510wA7FnrDjoa/tFhK90WUaBlkaqnw==", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001614", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", + "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.4.tgz", + "integrity": "sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz", + "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.0.tgz", + "integrity": "sha512-d3BrpyFr5eD4KcbRvQ3FTUx/KWmaDesr7+a3+1+P46IUnNoEt+oiLijPINZMEon7w9oGkIINWxrBAU9DEciwFQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", + "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", + "dependencies": { + "cssnano": "^5.1.8", + "jest-worker": "^29.1.2", + "postcss": "^8.4.17", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", + "dependencies": { + "autoprefixer": "^10.4.12", + "cssnano-preset-default": "^5.2.14", + "postcss-discard-unused": "^5.1.0", + "postcss-merge-idents": "^5.1.1", + "postcss-reduce-idents": "^5.2.0", + "postcss-zindex": "^5.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.750", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.750.tgz", + "integrity": "sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.0.1.tgz", + "integrity": "sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz", + "integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.1.1.tgz", + "integrity": "sha512-5mvUrF2suuv5f5cGDnDphIy4/gW86z82kl5qG6mM9z04SEQI4FB5Apmaw/TGEf3l55nLtMs5s51dmhUzvAHQCA==", + "dependencies": { + "@types/estree": "^1.0.0", + "is-plain-obj": "^4.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.2.tgz", + "integrity": "sha512-PldBy71wO9Uq1kyaMch9AHIghtQvIwxBUkv823pKmkTM3oV1JxtsTNYdevMxvUHqcnOAuO65JKU2+0NOxc2ksA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", + "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", + "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==" + }, + "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", + "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", + "dependencies": { + "inline-style-parser": "0.2.3" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.0.tgz", + "integrity": "sha512-9qcrTyoBmFZRNHeVP4edKqIUEgFzq7MHvTNSDuHSqkpOPtiBkgNgcmTSqmiw1kw9tdKaiddvIDv/eCJDxmqWCA==", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", + "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-remove-position": "^5.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", + "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", + "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.0.tgz", + "integrity": "sha512-61OI07qpQrERc+0wEysLHMvoiO3s2R56x5u7glHq2Yqq6EHbH4dW25G9GfDdGCDYqA21KE6DWgNSzxSwHc2hSg==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", + "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", + "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", + "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", + "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", + "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-unused": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", + "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-merge-idents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", + "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", + "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", + "dependencies": { + "sort-css-media-queries": "2.1.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.16" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/postcss-zindex": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", + "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", + "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-json-view-lite": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.3.1.tgz", + "integrity": "sha512-zvnfdUW6sL+4FfiwbYnYdwfxKZum0MbbXcMN5XhxhG405QpTW20ILIUjwJ/AXPg8V7BFUoNZKXopPxCcGR/Dhw==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", + "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "dependencies": { + "@types/react": "*", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", + "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", + "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rtl-detect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", + "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==" + }, + "node_modules/rtlcss": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", + "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz", + "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz", + "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", + "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.30.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", + "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", + "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.91.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", + "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.16.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz", + "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.3", + "pretty-time": "^1.1.0", + "std-env": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.4.tgz", + "integrity": "sha512-/AtWOKbBgjzEYYQRNfoGKHObgfAZag6qUJX1VbHo2PRBgS+wfWagEY2mizjfyAPcGesrJOcx/wcl0L9WnVrHFw==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/docus/package.json b/docus/package.json new file mode 100644 index 00000000..86825f7d --- /dev/null +++ b/docus/package.json @@ -0,0 +1,51 @@ +{ + "name": "docus", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "typecheck": "tsc" + }, + "dependencies": { + "@docusaurus/core": "3.2.1", + "@docusaurus/preset-classic": "3.2.1", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "yaml": "^2.4.2", + "zod": "3.23.4" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.2.1", + "@docusaurus/tsconfig": "3.2.1", + "@docusaurus/types": "3.2.1", + "ts-node": "10.9.2", + "typescript": "~5.2.2", + "@types/node": "20.12.7" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/docus/sidebars.ts b/docus/sidebars.ts new file mode 100644 index 00000000..acc7685a --- /dev/null +++ b/docus/sidebars.ts @@ -0,0 +1,31 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ +const sidebars: SidebarsConfig = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +export default sidebars; diff --git a/docus/src/components/HomepageFeatures/index.tsx b/docus/src/components/HomepageFeatures/index.tsx new file mode 100644 index 00000000..50a9e6f4 --- /dev/null +++ b/docus/src/components/HomepageFeatures/index.tsx @@ -0,0 +1,70 @@ +import clsx from 'clsx'; +import Heading from '@theme/Heading'; +import styles from './styles.module.css'; + +type FeatureItem = { + title: string; + Svg: React.ComponentType>; + description: JSX.Element; +}; + +const FeatureList: FeatureItem[] = [ + { + title: 'Easy to Use', + Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + description: ( + <> + Docusaurus was designed from the ground up to be easily installed and + used to get your website up and running quickly. + + ), + }, + { + title: 'Focus on What Matters', + Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + description: ( + <> + Docusaurus lets you focus on your docs, and we'll do the chores. Go + ahead and move your docs into the docs directory. + + ), + }, + { + title: 'Powered by React', + Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + description: ( + <> + Extend or customize your website layout by reusing React. Docusaurus can + be extended while reusing the same header and footer. + + ), + }, +]; + +function Feature({title, Svg, description}: FeatureItem) { + return ( +

+
+ +
+
+ {title} +

{description}

+
+
+ ); +} + +export default function HomepageFeatures(): JSX.Element { + return ( +
+
+
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/docus/src/components/HomepageFeatures/styles.module.css b/docus/src/components/HomepageFeatures/styles.module.css new file mode 100644 index 00000000..b248eb2e --- /dev/null +++ b/docus/src/components/HomepageFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 200px; + width: 200px; +} diff --git a/docus/src/css/custom.css b/docus/src/css/custom.css new file mode 100644 index 00000000..2bc6a4cf --- /dev/null +++ b/docus/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #2e8555; + --ifm-color-primary-dark: #29784c; + --ifm-color-primary-darker: #277148; + --ifm-color-primary-darkest: #205d3b; + --ifm-color-primary-light: #33925d; + --ifm-color-primary-lighter: #359962; + --ifm-color-primary-lightest: #3cad6e; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/docus/src/pages/index.module.css b/docus/src/pages/index.module.css new file mode 100644 index 00000000..9f71a5da --- /dev/null +++ b/docus/src/pages/index.module.css @@ -0,0 +1,23 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/docus/src/pages/index.tsx b/docus/src/pages/index.tsx new file mode 100644 index 00000000..400a3e19 --- /dev/null +++ b/docus/src/pages/index.tsx @@ -0,0 +1,43 @@ +import clsx from 'clsx'; +import Link from '@docusaurus/Link'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Layout from '@theme/Layout'; +import HomepageFeatures from '@site/src/components/HomepageFeatures'; +import Heading from '@theme/Heading'; + +import styles from './index.module.css'; + +function HomepageHeader() { + const {siteConfig} = useDocusaurusContext(); + return ( +
+
+ + {siteConfig.title} + +

{siteConfig.tagline}

+
+ + Docusaurus Tutorial - 5min ⏱️ + +
+
+
+ ); +} + +export default function Home(): JSX.Element { + const {siteConfig} = useDocusaurusContext(); + return ( + + +
+ +
+
+ ); +} diff --git a/docus/src/pages/markdown-page.md b/docus/src/pages/markdown-page.md new file mode 100644 index 00000000..9756c5b6 --- /dev/null +++ b/docus/src/pages/markdown-page.md @@ -0,0 +1,7 @@ +--- +title: Markdown page example +--- + +# Markdown page example + +You don't need React to write simple standalone pages. diff --git a/docus/src/plugin/index.ts b/docus/src/plugin/index.ts new file mode 100644 index 00000000..ce1e82d3 --- /dev/null +++ b/docus/src/plugin/index.ts @@ -0,0 +1,28 @@ +import type { LoadContext, Plugin } from "@docusaurus/types"; +import { z } from "zod"; + +const PluginOptions = z + .object({ + dashieSchemaPath: z.string(), + }) + .strict(); + +type PluginOptions = z.infer; + +export function validateOptions({ options }: { options: unknown }) { + return PluginOptions.parse(options) +} + +export default function dashiePlugin(context: LoadContext, options: PluginOptions): Plugin { + return { + name: "docus-plugin-dashie", + async contentLoaded({ content, actions }) { + const { addRoute } = actions; + addRoute({ + path: "/dashie", + component: "@theme/Dashie", + exact: true, + }); + }, + }; +} diff --git a/docus/src/plugin/source.ts b/docus/src/plugin/source.ts new file mode 100644 index 00000000..d59e546b --- /dev/null +++ b/docus/src/plugin/source.ts @@ -0,0 +1,364 @@ +import { z } from "zod"; +import * as yaml from "yaml"; +import * as fs from "fs"; + + +// type foo = z.ZodObject< +// { +// title: z.ZodOptional; +// description: z.ZodOptional; +// $ref: z.ZodOptional; +// default: z.ZodOptional; +// ... 4 more ...; +// required: z.ZodOptional<...>; +// }, +// "strip", +// z.ZodTypeAny, +// { +// title?: string | undefined; +// description?: string | undefined; +// $ref?: string | undefined; +// default?: unknown; +// type?: string | undefined; +// format?: string | undefined; +// deprecated?: boolean | undefined; +// examples?: unknown[] | undefined; +// required?: string[] | undefined; +// }, +// { +// ...; +// } +// > + +const SchemaBase = z.object({ + title: z.string().optional(), + description: z.string().optional(), + $ref: z.string().optional(), + default: z.unknown().optional(), + + type: z.string().optional(), + format: z.string().optional(), + deprecated: z.boolean().optional(), + examples: z.array(z.unknown()).optional(), + + required: z.array(z.string()).optional(), + + // #[serde(flatten)] + // pub(crate) object_schema: Option, + + // #[serde(flatten)] + // pub(crate) array_schema: Option, + + // #[serde(skip_serializing_if = "Option::is_none", rename = "enum")] + // pub(crate) enum_schema: Option>, + + // #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] + // pub(crate) one_of: Option>, +}); + +type Schema = z.infer & { + properties?: Record; + items?: Schema; + oneOf?: { schema: Schema; name?: string }[]; + enum?: ({ value: unknown; name: string } | { value: string } | string | number)[]; +}; + +const Schema: z.ZodType = SchemaBase.extend({ + properties: z.lazy(() => z.record(Schema)).optional(), + items: z.lazy(() => Schema).optional(), + oneOf: z.lazy(() => z.array(Schema.extend({ name: z.string().optional() })).optional()), + enum: z.lazy(() => + z.array( + z.union([ + z.intersection( + z.object({ + description: z.string(), + }), + z.union([ + z.object({ + value: z.unknown(), + name: z.string(), + }), + z.object({ + value: z.string(), + }), + ]) + ), + z.union([z.string(), z.number()]) + ]), + ).optional() + ) +}); + +const RootSchema = Schema.extend({ + definitions: z.record(Schema), +}); + +type RootSchema = z.infer; + + +const schema = fs.readFileSync("../deny.schema.yml", { encoding: "utf-8" }); + +const parsed = yaml.parse(schema); +const result = RootSchema.parse(parsed); + +console.log(); + +// pub(crate) struct SchemaEntry<'a> { +// pub(crate) schema: &'a Schema, +// pub(crate) level: usize, +// } + +// impl Schema { +// pub(crate) fn is_primitive(&self) -> bool { +// self.object_schema.is_none() +// && self.array_schema.is_none() +// && self.enum_schema.is_none() +// && self.one_of.is_none() +// } + +// /// Returns all schemas stored inside of this one. It doesn't resolve +// /// references. +// pub(crate) fn entries<'a>(&'a self) -> impl Iterator> { +// let mut stack = vec![SchemaEntry { +// schema: self, +// level: 0, +// }]; + +// std::iter::from_fn(move || { +// let entry = stack.pop()?; +// let schema = entry.schema; + +// let object_properties = schema +// .object_schema +// .iter() +// .flat_map(|object| object.properties.values()); + +// let one_of_variants = schema +// .one_of +// .iter() +// .flatten() +// .map(|variant| &variant.schema); + +// let array_items = schema.array_schema.iter().map(|array| array.items.as_ref()); + +// let new_entries = std::iter::empty() +// .chain(object_properties) +// .chain(one_of_variants) +// .chain(array_items) +// .map(|schema| SchemaEntry { +// schema, +// level: entry.level + 1, +// }); + +// stack.extend(new_entries); + +// Some(entry) +// }) +// } + +// pub(crate) fn traverse_mut(&mut self, visit: impl Fn(&mut Schema) -> Result<()>) -> Result<()> { +// visit(self)?; + +// if let Some(object) = &mut self.object_schema { +// object.properties.values_mut().try_for_each(&visit)?; +// } + +// if let Some(array) = &mut self.array_schema { +// visit(&mut array.items)?; +// } + +// if let Some(one_of) = &mut self.one_of { +// one_of +// .iter_mut() +// .map(|variant| &mut variant.schema) +// .try_for_each(&visit)?; +// } + +// Ok(()) +// } + +// fn try_downcast_as<'a, T>(&'a self, schema: &'a Option, label: &str) -> Result<&'a T> { +// schema +// .as_ref() +// .with_context(|| format!("Expected {label} schema, but got {self:#?}")) +// } + +// fn try_downcast_into(self, schema: Option, label: &str) -> Result { +// schema.with_context(|| format!("Expected {label} schema, but got {self:#?}")) +// } + +// pub(crate) fn try_as_array(&self) -> Result<&ArraySchema> { +// self.try_downcast_as(&self.array_schema, "array") +// } + +// pub(crate) fn try_into_array(self) -> Result { +// let array_schema = self.array_schema.clone(); +// self.try_downcast_into(array_schema, "array") +// } + +// pub(crate) fn try_as_object(&self) -> Result<&ObjectSchema> { +// self.try_downcast_as(&self.object_schema, "object") +// } + +// pub(crate) fn try_into_object(self) -> Result { +// let object_schema = self.object_schema.clone(); +// self.try_downcast_into(object_schema, "object") +// } + +// pub(crate) fn try_as_enum(&self) -> Result<&[EnumVariantSchema]> { +// self.try_downcast_as(&self.enum_schema, "enum") +// .map(Vec::as_slice) +// } + +// pub(crate) fn try_into_enum(self) -> Result> { +// let enum_schema = self.enum_schema.clone(); +// self.try_downcast_into(enum_schema, "enum") +// } + +// pub(crate) fn try_as_one_of(&self) -> Result<&[OneOfVariantSchema]> { +// self.try_downcast_as(&self.one_of, "one-of") +// .map(Vec::as_slice) +// } + +// pub(crate) fn try_into_one_of(self) -> Result> { +// let one_of_schema = self.one_of.clone(); +// self.try_downcast_into(one_of_schema, "one-of") +// } + +// pub(crate) fn try_description(&self) -> Result<&str> { +// self.description +// .as_deref() +// .with_context(|| format!("Expected description for schema, but found none: {self:#?}")) +// } + +// pub(crate) fn referenced_definition(&self) -> Option<&str> { +// self.reference.as_ref()?.strip_prefix("#/definitions/") +// } + +// pub(crate) fn is_undocumented_primitive(&self) -> bool { +// matches!( +// self, +// Self { +// ty: _, +// format: _, +// deprecated: false, +// examples, +// object_schema: None, +// array_schema: None, +// enum_schema: None, +// one_of: None, +// title: None, +// description: None, +// reference: None, +// default: None, +// x_taplo: None, +// } +// if examples.is_empty() +// ) +// } +// } + +// impl RootSchema { +// pub(crate) fn definition(&self, definition: &str) -> Result<&Schema> { +// self.definitions +// .get(definition) +// .with_context(|| format!("Reference to unknown definition: `{definition}`")) +// } + +// fn referenced_definition(&self, schema: &Schema) -> Result> { +// let Some(definition) = schema.referenced_definition() else { +// return Ok(None); +// }; + +// let definition = self +// .definition(definition) +// .with_context(|| format!("inside of schema: {schema:#?}"))?; + +// Ok(Some(definition)) +// } + +// pub(crate) fn inline_referenced_definition(&self, schema: &Schema) -> Result { +// let Some(definition) = self.referenced_definition(schema)? else { +// return Ok(schema.clone()); +// }; + +// let mut output = definition.clone(); + +// // Values from the schema should take priority +// merge_json_mut(&mut output, schema); + +// output.reference = None; + +// Ok(output) +// } +// } + +// impl OneOfVariantSchema { +// pub(crate) fn name(&self) -> Result<&str> { +// self.name +// .as_deref() +// .or_else(|| { +// self.schema +// .reference +// .as_deref()? +// .strip_prefix("#/definitions/") +// }) +// .or(self.schema.ty.as_deref()) +// .with_context(|| format!("Expected name for one-of variant, but got: {self:#?}")) +// } +// } + +// impl CustomEnumValue { +// fn to_json_value(&self) -> Value { +// match self { +// CustomEnumValue::Named { value, name: _ } => value.clone(), +// CustomEnumValue::Inferred { value } => value.clone().into(), +// } +// } +// } + +// impl EnumVariantSchema { +// pub(crate) fn value_and_description(&self) -> (Value, Option<&str>) { +// match self { +// EnumVariantSchema::Documented(schema) => { +// let value = schema.value.to_json_value(); +// let description = schema.description.as_str(); +// (value, Some(description)) +// } +// EnumVariantSchema::Undocumented(value) => (value.clone(), None), +// } +// } +// } + +// fn merge_json_mut(dest: &mut T, src: &T) { +// let mut dest_value = serde_json::to_value(&*dest).unwrap(); +// let src_value = serde_json::to_value(src).unwrap(); + +// merge_json_values_mut(&mut dest_value, src_value); + +// *dest = serde_json::from_value(dest_value).unwrap(); +// } + +// pub(crate) fn merge_json_values_mut(a: &mut Value, b: Value) { +// use serde_json::map::Entry; + +// match (a, b) { +// (Value::Object(a), Value::Object(b)) => { +// for (key, b_value) in b { +// match a.entry(key) { +// Entry::Occupied(mut a_value) => { +// merge_json_values_mut(a_value.get_mut(), b_value); +// } +// Entry::Vacant(entry) => { +// entry.insert(b_value); +// } +// } +// } +// } +// (Value::Array(a), Value::Array(b)) => { +// a.extend(b); +// } +// (a, b) => *a = b, +// } +// } diff --git a/docus/static/.nojekyll b/docus/static/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docus/static/img/docusaurus-social-card.jpg b/docus/static/img/docusaurus-social-card.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ffcb448210e1a456cb3588ae8b396a597501f187 GIT binary patch literal 55746 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
sH`pxVp$E*LSx0bY$^ho1gZ(Ce+BX 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 fgzs%Vr*-jYG(YMS<ttdtee# literal 0 HcmV?d00001 diff --git a/docus/static/img/docusaurus.png b/docus/static/img/docusaurus.png new file mode 100644 index 0000000000000000000000000000000000000000..dafcd1f95a678101f95907ef57e3696e1862c717 GIT binary patch literal 5141 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 literal 0 HcmV?d00001 diff --git a/docus/static/img/favicon.ico b/docus/static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c01d54bcd39a5f853428f3cd5aa0f383d963c484 GIT binary patch literal 3626 zcmb`Je@s(X6vrR`EK3%b%orErlDW({vnABqA zcfaS{d+xbU5JKp0*;0YOg+;Fl!eT)XRuapIwFLL`=imZCSon$`se`_<%@MB=M~KG+ z=EW^FL`w|Bo>*ktlaS^(fut!95`iG5u=SZ8nfDHO#GaTlH1-XG^;vsjUb^gWTVz0+ z^=WR1wv9-2oeR=_;fL0H7rNWqAzGtO(D;`~cX(RcN0w2v24Y8)6t`cS^_ghs`_ho? z{0ka~1Dgo8TfAP$r*ua?>$_V+kZ!-(TvEJ7O2f;Y#tezt$&R4 zLI}=-y@Z!grf*h3>}DUL{km4R>ya_I5Ag#{h_&?+HpKS!;$x3LC#CqUQ8&nM?X))Q zXAy2?`YL4FbC5CgJu(M&Q|>1st8XXLZ|5MgwgjP$m_2Vt0(J z&Gu7bOlkbGzGm2sh?X`){7w69Y$1#@P@7DF{ZE=4%T0NDS)iH`tiPSKpDNW)zmtn( zw;4$f>k)4$LBc>eBAaTZeCM2(iD+sHlj!qd z2GjRJ>f_Qes(+mnzdA^NH?^NB(^o-%Gmg$c8MNMq&`vm@9Ut;*&$xSD)PKH{wBCEC z4P9%NQ;n2s59ffMn8*5)5AAg4-93gBXBDX`A7S& zH-|%S3Wd%T79fk-e&l`{!?lve8_epXhE{d3Hn$Cg!t=-4D(t$cK~7f&4s?t7wr3ZP z*!SRQ-+tr|e1|hbc__J`k3S!rMy<0PHy&R`v#aJv?`Y?2{avK5sQz%=Us()jcNuZV z*$>auD4cEw>;t`+m>h?f?%VFJZj8D|Y1e_SjxG%J4{-AkFtT2+ZZS5UScS~%;dp!V>)7zi`w(xwSd*FS;Lml=f6hn#jq)2is4nkp+aTrV?)F6N z>DY#SU0IZ;*?Hu%tSj4edd~kYNHMFvS&5}#3-M;mBCOCZL3&;2obdG?qZ>rD|zC|Lu|sny76pn2xl|6sk~Hs{X9{8iBW zwiwgQt+@hi`FYMEhX2 \ No newline at end of file diff --git a/docus/static/img/undraw_docusaurus_mountain.svg b/docus/static/img/undraw_docusaurus_mountain.svg new file mode 100644 index 00000000..af961c49 --- /dev/null +++ b/docus/static/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docus/static/img/undraw_docusaurus_react.svg b/docus/static/img/undraw_docusaurus_react.svg new file mode 100644 index 00000000..94b5cf08 --- /dev/null +++ b/docus/static/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docus/static/img/undraw_docusaurus_tree.svg b/docus/static/img/undraw_docusaurus_tree.svg new file mode 100644 index 00000000..d9161d33 --- /dev/null +++ b/docus/static/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docus/tsconfig.json b/docus/tsconfig.json new file mode 100644 index 00000000..7ba415ad --- /dev/null +++ b/docus/tsconfig.json @@ -0,0 +1,11 @@ +{ + // This file is not used in compilation. It is here just for a nice editor experience. + "extends": "@docusaurus/tsconfig", + "compilerOptions": { + "baseUrl": ".", + "strict": true, + "module": "CommonJS", + }, + // "exclude": ["../node_modules"], + "files": ["src/**/*.ts"] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..c5a51929 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "cargo-deny", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 786f6c125c79d434dca88041a6e5afaa9275786b Mon Sep 17 00:00:00 2001 From: Veetaha Date: Wed, 1 May 2024 22:46:26 +0000 Subject: [PATCH 15/20] Implement an mdbook preprocessor --- Cargo.lock | 869 +++++++++++++++++- Cargo.toml | 2 +- {xtask => dashie}/Cargo.toml | 11 +- {xtask => dashie}/src/cli.rs | 8 +- .../src/cli/codegen/json_schema.rs | 8 +- dashie/src/cli/codegen/mod.rs | 22 + dashie/src/cli/mdbook/mod.rs | 19 + dashie/src/cli/mdbook/preprocessor/mod.rs | 61 ++ .../src/cli/mdbook/preprocessor/preprocess.rs | 258 ++++++ .../source.rs => dashie/src/dashie_schema.rs | 9 +- {xtask => dashie}/src/entrypoint.rs | 4 +- dashie/src/lib.rs | 14 + {xtask => dashie}/src/main.rs | 2 +- .../mod.rs => dashie/src/md_doc/hir/doc.rs | 182 ++-- .../dom.rs => dashie/src/md_doc/hir/mod.rs | 26 +- .../src/md_doc/mir}/mdast.rs | 0 .../src/md_doc/mir/mod.rs | 105 +-- dashie/src/md_doc/mod.rs | 2 + docs/book.toml | 4 + docs/src/SUMMARY.md | 21 +- docs/src/checks2/advisories/README.md | 1 - docs/src/checks2/advisories/cfg.md | 1 - docs/src/checks2/advisories/diags.md | 1 - docs/src/checks2/bans/README.md | 1 - docs/src/checks2/bans/cfg.md | 1 - docs/src/checks2/bans/diags.md | 1 - docs/src/checks2/graph/cfg.md | 1 - docs/src/checks2/licenses/README.md | 1 - docs/src/checks2/licenses/cfg.md | 1 - docs/src/checks2/licenses/diags.md | 1 - docs/src/checks2/output/cfg.md | 1 - docs/src/checks2/schema.md | 9 - docs/src/checks2/schema/root.md | 27 - docs/src/checks2/schema/type-index.md | 3 - .../checks2/schema/type-index/Advisories.md | 204 ---- .../type-index/AdvisoriesIgnoreAdvisory.md | 21 - .../schema/type-index/AdvisoriesIgnoreItem.md | 17 - .../type-index/AdvisoriesIgnoreYanked.md | 13 - docs/src/checks2/schema/type-index/Bans.md | 13 - .../checks2/schema/type-index/BansAllow.md | 13 - docs/src/checks2/schema/type-index/Graph.md | 105 --- .../checks2/schema/type-index/IgnoreReason.md | 5 - .../checks2/schema/type-index/LintLevel.md | 9 - docs/src/checks2/schema/type-index/Output.md | 21 - .../checks2/schema/type-index/PackageSpec.md | 73 -- docs/src/checks2/schema/type-index/Target.md | 11 - .../schema/type-index/TargetAdvanced.md | 32 - .../checks2/schema/type-index/TargetString.md | 22 - docs/src/checks2/sources/README.md | 1 - docs/src/checks2/sources/cfg.md | 1 - docs/src/checks2/sources/diags.md | 1 - docs/src/checks2/type-index.md | 10 - docs/src/checks2/type-index/Advisories.md | 142 --- .../type-index/AdvisoriesIgnoreAdvisory.md | 20 - .../type-index/AdvisoriesIgnoreItem.md | 17 - .../type-index/AdvisoriesIgnoreYanked.md | 11 - docs/src/checks2/type-index/Bans.md | 12 - docs/src/checks2/type-index/BansAllow.md | 13 - docs/src/checks2/type-index/Graph.md | 105 --- docs/src/checks2/type-index/IgnoreReason.md | 5 - docs/src/checks2/type-index/LintLevel.md | 11 - docs/src/checks2/type-index/Output.md | 21 - docs/src/checks2/type-index/PackageSpec.md | 73 -- docs/src/checks2/type-index/Target.md | 11 - docs/src/checks2/type-index/TargetAdvanced.md | 31 - docs/src/checks2/type-index/TargetString.md | 22 - docus/src/plugin/source.ts | 41 +- xtask/src/cli/codegen.rs | 24 - xtask/src/lib.rs | 4 - 69 files changed, 1395 insertions(+), 1417 deletions(-) rename {xtask => dashie}/Cargo.toml (76%) rename {xtask => dashie}/src/cli.rs (75%) rename {xtask => dashie}/src/cli/codegen/json_schema.rs (90%) create mode 100644 dashie/src/cli/codegen/mod.rs create mode 100644 dashie/src/cli/mdbook/mod.rs create mode 100644 dashie/src/cli/mdbook/preprocessor/mod.rs create mode 100644 dashie/src/cli/mdbook/preprocessor/preprocess.rs rename xtask/src/cli/codegen/source.rs => dashie/src/dashie_schema.rs (97%) rename {xtask => dashie}/src/entrypoint.rs (92%) create mode 100644 dashie/src/lib.rs rename {xtask => dashie}/src/main.rs (68%) rename xtask/src/cli/codegen/md_doc/mod.rs => dashie/src/md_doc/hir/doc.rs (67%) rename xtask/src/cli/codegen/md_doc/dom.rs => dashie/src/md_doc/hir/mod.rs (85%) rename {xtask/src/cli/codegen/md_doc/rendering => dashie/src/md_doc/mir}/mdast.rs (100%) rename xtask/src/cli/codegen/md_doc/rendering.rs => dashie/src/md_doc/mir/mod.rs (84%) create mode 100644 dashie/src/md_doc/mod.rs delete mode 100644 docs/src/checks2/advisories/README.md delete mode 100644 docs/src/checks2/advisories/cfg.md delete mode 100644 docs/src/checks2/advisories/diags.md delete mode 100644 docs/src/checks2/bans/README.md delete mode 100644 docs/src/checks2/bans/cfg.md delete mode 100644 docs/src/checks2/bans/diags.md delete mode 100644 docs/src/checks2/graph/cfg.md delete mode 100644 docs/src/checks2/licenses/README.md delete mode 100644 docs/src/checks2/licenses/cfg.md delete mode 100644 docs/src/checks2/licenses/diags.md delete mode 100644 docs/src/checks2/output/cfg.md delete mode 100644 docs/src/checks2/schema.md delete mode 100644 docs/src/checks2/schema/root.md delete mode 100644 docs/src/checks2/schema/type-index.md delete mode 100644 docs/src/checks2/schema/type-index/Advisories.md delete mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md delete mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md delete mode 100644 docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md delete mode 100644 docs/src/checks2/schema/type-index/Bans.md delete mode 100644 docs/src/checks2/schema/type-index/BansAllow.md delete mode 100644 docs/src/checks2/schema/type-index/Graph.md delete mode 100644 docs/src/checks2/schema/type-index/IgnoreReason.md delete mode 100644 docs/src/checks2/schema/type-index/LintLevel.md delete mode 100644 docs/src/checks2/schema/type-index/Output.md delete mode 100644 docs/src/checks2/schema/type-index/PackageSpec.md delete mode 100644 docs/src/checks2/schema/type-index/Target.md delete mode 100644 docs/src/checks2/schema/type-index/TargetAdvanced.md delete mode 100644 docs/src/checks2/schema/type-index/TargetString.md delete mode 100644 docs/src/checks2/sources/README.md delete mode 100644 docs/src/checks2/sources/cfg.md delete mode 100644 docs/src/checks2/sources/diags.md delete mode 100644 docs/src/checks2/type-index.md delete mode 100644 docs/src/checks2/type-index/Advisories.md delete mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md delete mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreItem.md delete mode 100644 docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md delete mode 100644 docs/src/checks2/type-index/Bans.md delete mode 100644 docs/src/checks2/type-index/BansAllow.md delete mode 100644 docs/src/checks2/type-index/Graph.md delete mode 100644 docs/src/checks2/type-index/IgnoreReason.md delete mode 100644 docs/src/checks2/type-index/LintLevel.md delete mode 100644 docs/src/checks2/type-index/Output.md delete mode 100644 docs/src/checks2/type-index/PackageSpec.md delete mode 100644 docs/src/checks2/type-index/Target.md delete mode 100644 docs/src/checks2/type-index/TargetAdvanced.md delete mode 100644 docs/src/checks2/type-index/TargetString.md delete mode 100644 xtask/src/cli/codegen.rs delete mode 100644 xtask/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 82882aeb..444584dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,34 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "ammonia" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170" +dependencies = [ + "html5ever", + "maplit", + "once_cell", + "tendril", + "url", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.13" @@ -206,6 +234,21 @@ dependencies = [ "serde", ] +[[package]] +name = "buildstructor" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3907aac66c65520545ae3cb3c195306e20d5ed5c90bfbb992e061cf12a104d0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "str_inflector", + "syn 2.0.53", + "thiserror", + "try_match", +] + [[package]] name = "bumpalo" version = "3.15.4" @@ -336,6 +379,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.4", +] + [[package]] name = "clap" version = "4.5.3" @@ -356,6 +411,16 @@ dependencies = [ "anstyle", "clap_lex", "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +dependencies = [ + "clap", ] [[package]] @@ -367,7 +432,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -530,6 +595,35 @@ dependencies = [ "serde", ] +[[package]] +name = "dashie" +version = "0.1.0" +dependencies = [ + "anyhow", + "buildstructor", + "camino", + "clap", + "fs-err", + "indexmap", + "itertools", + "mdbook", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "semver", + "serde", + "serde_json", + "serde_yaml", + "toml 0.8.12", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "deranged" version = "0.3.11" @@ -562,6 +656,18 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "elasticlunr-rs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571" +dependencies = [ + "regex", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -577,6 +683,29 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -672,12 +801,31 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -685,6 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -699,6 +848,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -719,6 +879,8 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", + "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -1127,7 +1289,7 @@ checksum = "1dff438f14e67e7713ab9332f5fd18c8f20eb7eb249494f6c2bf170522224032" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -1556,7 +1718,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1564,6 +1726,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -1574,6 +1750,30 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http 0.2.12", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http 0.2.12", +] + [[package]] name = "heck" version = "0.4.1" @@ -1601,6 +1801,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "http" version = "0.2.12" @@ -1612,6 +1826,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1619,7 +1844,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -1635,6 +1860,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.28" @@ -1646,7 +1877,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", @@ -1666,13 +1897,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.12", "hyper", "rustls", "tokio", "tokio-rustls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.5.0" @@ -1683,6 +1937,22 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "ignore" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.6", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1694,6 +1964,26 @@ dependencies = [ "serde", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "insta" version = "1.36.1" @@ -1757,6 +2047,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "krates" version = "0.16.7" @@ -1818,6 +2128,32 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1835,7 +2171,42 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", +] + +[[package]] +name = "mdbook" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c33564061c3c640bed5ace7d6a2a1b65f2c64257d1ac930c15e94ed0fb561d3" +dependencies = [ + "ammonia", + "anyhow", + "chrono", + "clap", + "clap_complete", + "elasticlunr-rs", + "env_logger", + "futures-util", + "handlebars", + "ignore", + "log", + "memchr", + "notify", + "notify-debouncer-mini", + "once_cell", + "opener", + "pathdiff", + "pulldown-cmark", + "regex", + "serde", + "serde_json", + "shlex", + "tempfile", + "tokio", + "toml 0.5.11", + "topological-sort", + "warp", ] [[package]] @@ -1859,6 +2230,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1875,12 +2256,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", + "log", "wasi", "windows-sys 0.48.0", ] [[package]] -name = "nu-ansi-term" +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "normpath" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.5.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "notify-debouncer-mini" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43" +dependencies = [ + "crossbeam-channel", + "log", + "notify", +] + +[[package]] +name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" @@ -1947,6 +2374,17 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opener" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" +dependencies = [ + "bstr", + "normpath", + "winapi", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -1988,12 +2426,63 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "pest_meta" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -2004,6 +2493,64 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2043,6 +2590,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "proc-macro2" version = "1.0.79" @@ -2101,6 +2660,36 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.9.0" @@ -2187,7 +2776,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-rustls", @@ -2364,6 +2953,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -2387,7 +2982,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -2449,7 +3044,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -2498,6 +3093,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha1_smol" version = "1.0.0" @@ -2530,6 +3136,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2555,6 +3167,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -2610,6 +3228,42 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str_inflector" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0b848d5a7695b33ad1be00f84a3c079fe85c9278a325ff9159e6c99cef4ef7" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + [[package]] name = "strsim" version = "0.11.0" @@ -2635,7 +3289,18 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.53", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] @@ -2687,7 +3352,7 @@ dependencies = [ "crossbeam-channel", "gix", "home", - "http", + "http 0.2.12", "libc", "memchr", "rayon", @@ -2727,6 +3392,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -2736,6 +3412,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.58" @@ -2753,7 +3439,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -2827,9 +3513,21 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.48.0", ] +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -2840,6 +3538,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.10" @@ -2854,6 +3564,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.7.8" @@ -2924,6 +3643,12 @@ dependencies = [ "winnow 0.6.5", ] +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + [[package]] name = "tower-service" version = "0.3.2" @@ -2936,6 +3661,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2949,7 +3675,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] @@ -2997,6 +3723,45 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "try_match" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ae3c1941e8859e30d28e572683fbfa89ae5330748b45139aedf488389e2be4" +dependencies = [ + "try_match_inner", +] + +[[package]] +name = "try_match_inner" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a91713132798caecb23c977488945566875e7b61b902fb111979871cbff34e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -3013,6 +3778,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicase" version = "2.7.0" @@ -3079,6 +3850,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" @@ -3116,6 +3893,34 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http 0.2.12", + "hyper", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3143,7 +3948,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.53", "wasm-bindgen-shared", ] @@ -3177,7 +3982,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3235,6 +4040,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -3404,25 +4218,6 @@ dependencies = [ "tap", ] -[[package]] -name = "xtask" -version = "0.1.0" -dependencies = [ - "anyhow", - "camino", - "clap", - "indexmap", - "itertools", - "pulldown-cmark", - "pulldown-cmark-to-cmark", - "serde", - "serde_json", - "serde_yaml", - "toml 0.8.12", - "tracing", - "tracing-subscriber", -] - [[package]] name = "yaml-rust" version = "0.4.5" @@ -3449,7 +4244,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 48800ea5..e9152f9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["xtask"] +members = ["dashie"] [package] name = "cargo-deny" diff --git a/xtask/Cargo.toml b/dashie/Cargo.toml similarity index 76% rename from xtask/Cargo.toml rename to dashie/Cargo.toml index fadd68b1..3220b7c0 100644 --- a/xtask/Cargo.toml +++ b/dashie/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "xtask" +name = "dashie" version = "0.1.0" edition = "2021" @@ -8,7 +8,7 @@ edition = "2021" anyhow = "1.0" # Much nicer paths -camino = "1.1" +camino = { version = "1.1", features = ["serde1"] } # Amazing CLI arg parser clap = { version = "4.3", features = ["derive"] } @@ -31,3 +31,10 @@ toml = "0.8" # Awesome logging tools tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +mdbook = "0.4" +semver = "1.0" + +# Renaming `fs-err` to just `fs` for convenience +fs = { package = "fs-err", version = "2.11" } +buildstructor = "0.5" diff --git a/xtask/src/cli.rs b/dashie/src/cli.rs similarity index 75% rename from xtask/src/cli.rs rename to dashie/src/cli.rs index 330305bc..3094fbb2 100644 --- a/xtask/src/cli.rs +++ b/dashie/src/cli.rs @@ -1,5 +1,7 @@ mod codegen; +mod mdbook; +use crate::prelude::*; use clap::{Parser, Subcommand}; #[derive(Parser, Debug)] @@ -12,12 +14,16 @@ struct Cli { #[derive(Subcommand, Debug)] enum Command { Codegen(codegen::CodegenCommand), + + #[command(subcommand)] + Mdbook(mdbook::MdbookCommand), } -pub(crate) fn run() -> anyhow::Result<()> { +pub(crate) fn run() -> Result { let cli = Cli::parse(); match cli.command { Command::Codegen(cmd) => cmd.run(), + Command::Mdbook(cmd) => cmd.run(), } } diff --git a/xtask/src/cli/codegen/json_schema.rs b/dashie/src/cli/codegen/json_schema.rs similarity index 90% rename from xtask/src/cli/codegen/json_schema.rs rename to dashie/src/cli/codegen/json_schema.rs index b60e3939..b0664aa3 100644 --- a/xtask/src/cli/codegen/json_schema.rs +++ b/dashie/src/cli/codegen/json_schema.rs @@ -1,8 +1,8 @@ -use super::source::{EnumVariantSchema, RootSchema, Schema}; -use anyhow::Result; +use crate::dashie_schema::{EnumVariantSchema, RootSchema, Schema}; +use crate::prelude::*; /// Generate the JSON schema based on the input YML schema. -pub(crate) fn gen(root: &RootSchema) -> Result<()> { +pub(crate) fn gen(root: &RootSchema) -> Result { let ctx = GenContext::new(root); let root = ctx.gen()?; @@ -51,7 +51,7 @@ impl<'a> GenContext<'a> { /// Normalize the [`EnumSchema::Custom`] to [`EnumSchema::Standard`] format /// plus generate some extensions for specific TOML language servers - fn normalize_enum(&self, schema: &mut Schema) -> Result<()> { + fn normalize_enum(&self, schema: &mut Schema) -> Result { let mut inlined = self.root.inline_referenced_definition(schema)?; let Some(enum_variants) = &mut inlined.enum_schema else { diff --git a/dashie/src/cli/codegen/mod.rs b/dashie/src/cli/codegen/mod.rs new file mode 100644 index 00000000..49000433 --- /dev/null +++ b/dashie/src/cli/codegen/mod.rs @@ -0,0 +1,22 @@ +mod json_schema; + +use crate::dashie_schema; +use crate::prelude::*; +use camino::Utf8PathBuf; + +/// Update generated code that is checked in to source control. +#[derive(clap::Args, Debug)] +pub(crate) struct CodegenCommand { + /// Path to file containing the Dashie schema that we need to process. + dashie_schema: Utf8PathBuf, +} + +impl CodegenCommand { + pub(crate) fn run(self) -> Result { + let dashie_schema = dashie_schema::RootSchema::from_file(self.dashie_schema)?; + + json_schema::gen(&dashie_schema)?; + + Ok(()) + } +} diff --git a/dashie/src/cli/mdbook/mod.rs b/dashie/src/cli/mdbook/mod.rs new file mode 100644 index 00000000..2c27c38b --- /dev/null +++ b/dashie/src/cli/mdbook/mod.rs @@ -0,0 +1,19 @@ +mod preprocessor; + +use crate::prelude::*; + +/// Update generated code that is checked in to source control. +#[derive(clap::Subcommand, Debug)] +pub(crate) enum MdbookCommand { + /// Implements an proprocessor for the mdbook. + /// Details: + Preprocessor(preprocessor::PreprocessorCommand), +} + +impl MdbookCommand { + pub(crate) fn run(self) -> Result { + match self { + Self::Preprocessor(cmd) => cmd.run(), + } + } +} diff --git a/dashie/src/cli/mdbook/preprocessor/mod.rs b/dashie/src/cli/mdbook/preprocessor/mod.rs new file mode 100644 index 00000000..ea65b198 --- /dev/null +++ b/dashie/src/cli/mdbook/preprocessor/mod.rs @@ -0,0 +1,61 @@ +mod preprocess; + +use crate::prelude::*; +use std::io::Write; + +#[derive(clap::Args, Debug)] +pub(crate) struct PreprocessorCommand { + #[command(subcommand)] + subcommand: Option, +} + +#[derive(clap::Subcommand, Debug)] +enum PreprocessorSubcommand { + /// Check if a renderer is supported by this preprocessor + Supports(SupportsCommand), +} + +impl PreprocessorSubcommand { + fn run(self) -> Result { + match self { + Self::Supports(cmd) => cmd.run(), + } + } +} + +impl PreprocessorCommand { + pub(crate) fn run(self) -> Result { + self.subcommand + .map(PreprocessorSubcommand::run) + .unwrap_or_else(Self::preprocess) + } + + fn preprocess() -> Result { + let input = std::io::read_to_string(std::io::stdin())?; + + let (ctx, book) = serde_json::from_str(&input) + .with_context(|| format!("Unable to parse the input at stdin: ```\n{input}\n```"))?; + + let processed_book = preprocess::run(ctx, book)?; + let output = serde_json::to_vec(&processed_book)?; + + std::io::stdout().write_all(&output)?; + + Ok(()) + } +} + +#[derive(clap::Args, Debug)] +struct SupportsCommand { + renderer: String, +} + +impl SupportsCommand { + pub(crate) fn run(self) -> Result { + info!( + self.renderer, + "Any renderer is supported. Responding with a yes." + ); + Ok(()) + } +} diff --git a/dashie/src/cli/mdbook/preprocessor/preprocess.rs b/dashie/src/cli/mdbook/preprocessor/preprocess.rs new file mode 100644 index 00000000..9f43d8b6 --- /dev/null +++ b/dashie/src/cli/mdbook/preprocessor/preprocess.rs @@ -0,0 +1,258 @@ +use crate::md_doc::mir; +use crate::prelude::*; +use crate::{dashie_schema, md_doc}; +use camino::Utf8PathBuf; +use mdbook::book::{self, Book}; +use mdbook::preprocess::PreprocessorContext; +use mdbook::BookItem; +use serde::Deserialize; + +const ROOT_PLACEHOLDER: &str = "{{ dashie-root }}"; +const TYPE_INDEX_PLACEHOLDER: &str = "{{ dashie-type-index }}"; + +pub(super) fn run(ctx: PreprocessorContext, book: Book) -> Result { + Context::new(ctx)?.run(book) +} + +struct Context { + config: Config, + ctx: PreprocessorContext, +} + +impl Context { + const NAME: &'static str = "dashie"; + + fn new(ctx: PreprocessorContext) -> Result { + let config = Config::from_ctx(&ctx)?; + + let book_version = semver::Version::parse(&ctx.mdbook_version)?; + let version_req = semver::VersionReq::parse(mdbook::MDBOOK_VERSION)?; + + if version_req.matches(&book_version) { + warn!( + "The {} preprocessor was built against version {} of mdbook, \ + but we're being called from version {}. There could be breaking \ + changes in mdbook API, which may lead to errors down the line", + Self::NAME, + mdbook::MDBOOK_VERSION, + ctx.mdbook_version + ); + } + + Ok(Self { config, ctx }) + } + + fn run(&self, mut book: Book) -> Result { + let schema_path: Utf8PathBuf = self + .config + .dashie_schema + .as_ref() + .map(|path| self.ctx.root.join(path).try_into()) + .transpose()? + .unwrap_or_else(|| "dashie.schema.yml".into()); + + let schema = dashie_schema::RootSchema::from_file(schema_path)?; + + let doc = md_doc::hir::Dom::builder().schema(schema).build()?.lower(); + + let mut placeholder = PlaceholderChapter::find(&mut book.sections, ROOT_PLACEHOLDER) + .with_context(|| { + format!( + "Could not find a draft chapter with the placeholder \ + '[{ROOT_PLACEHOLDER}]()'. This placeholder must specify a place \ + where the root documentation of the schema will be output", + ) + })?; + + let root = mir::NamedDocument::new(&placeholder.name, doc.root); + Self::replace_draft_chapter(root, placeholder.chapter())?; + + let placeholder = PlaceholderChapter::find(&mut book.sections, TYPE_INDEX_PLACEHOLDER); + match (doc.type_index, placeholder) { + (None, None) => {} + (Some(_), None) => { + bail!( + "The schema has a type index, but no {TYPE_INDEX_PLACEHOLDER} \ + placeholder was found in SUMMARY.md" + ) + } + (None, Some(placeholder)) => placeholder.remove(), + (Some(document), Some(mut placeholder)) => { + let document = mir::NamedDocument::new(&placeholder.name, document); + Self::replace_draft_chapter(document, placeholder.chapter())?; + } + } + + Ok(book) + } + + fn replace_draft_chapter(document: mir::NamedDocument, chapter: &mut book::Chapter) -> Result { + let section_number = chapter.number.as_mut().with_context(|| { + format!( + "Expected a placeholder draft chapter '{}' to be a numbered chapter", + chapter.name + ) + })?; + let section_number = std::mem::take(section_number); + + *chapter = Self::mir_into_mdbook(document, &chapter.parent_names, section_number); + + Ok(()) + } + + fn mir_into_mdbook( + document: mir::NamedDocument, + parent_names: &[String], + section_number: book::SectionNumber, + ) -> book::Chapter { + let parent_names: Vec<_> = parent_names + .iter() + .cloned() + .chain([document.name.clone()]) + .collect(); + + let sub_items = document + .data + .children + .into_iter() + .enumerate() + .map(|(i, child)| { + let section_number = section_number.iter().copied().chain([i as u32]).collect(); + let chapter = Self::mir_into_mdbook(child, &parent_names, section_number); + book::BookItem::Chapter(chapter) + }) + .collect(); + + let content = document.data.section.to_markdown(1); + let path = document.name.clone().into(); + + book::Chapter { + name: document.name, + content, + number: Some(section_number), + sub_items, + path: Some(path), + source_path: None, + parent_names, + } + } +} + +struct PlaceholderChapter<'book> { + name: String, + parent: &'book mut Vec, + index: usize, +} + +impl<'book> PlaceholderChapter<'book> { + fn find(items: &'book mut Vec, placeholder: &str) -> Option { + // It is this ugly because of a borrow checker limitation. We can't + // recursively call `find` in the same loop where we already have a + // return statement that returns the entire `items` vector in it. + // + // The workaround is to split the search by direct children and nested + // children into two loops + for (index, item) in items.iter_mut().enumerate() { + let chapter = match item { + mdbook::BookItem::Chapter(chapter) => chapter, + _ => continue, + }; + + if chapter.name.contains(placeholder) { + let name = chapter.name.replace(placeholder, "").trim().to_owned(); + return Some(Self { + name, + parent: items, + index, + }); + } + } + + items.iter_mut().find_map(|item| { + let chapter = match item { + mdbook::BookItem::Chapter(chapter) => chapter, + _ => return None, + }; + Self::find(&mut chapter.sub_items, placeholder) + }) + } + + fn chapter(&mut self) -> &mut book::Chapter { + match &mut self.parent[self.index] { + BookItem::Chapter(chapter) => chapter, + _ => unreachable!(), + } + } + + fn remove(self) { + self.parent.remove(self.index); + } +} + +#[derive(Default, Deserialize, Debug)] +struct Config { + /// Path to file containing the Dashie schema that we need to process. + /// If a relative path is provided, it is resolved relative to the root of + /// the config file itself. + dashie_schema: Option, +} + +impl Config { + fn from_ctx(ctx: &PreprocessorContext) -> Result { + #[derive(Deserialize, Debug)] + struct BookToml { + preprocessor: Option, + } + + #[derive(Deserialize, Debug)] + struct PreprocessorConfig { + dashie: Option, + } + + // HACK: we read the original `book.toml` file source to provider better + // error reporting, because `toml::from_str` inserts code snippets and + // line numbers in the error messages this way. This is in contrast to + // deserializing the config from a dynamic `toml::Map` already present + // in PreprocessorContext, which would not provide such nice error messages + let path = ctx.root.join("book.toml"); + let config = fs::read_to_string(path)?; + + let config: BookToml = toml::from_str(&config)?; + + let config = config + .preprocessor + .and_then(|preprocessor| preprocessor.dashie) + .unwrap_or_default(); + + Ok(config) + } +} + +// pub(crate) fn gen(root: &dashie_schema::RootSchema) -> Result<()> { +// let out_dir = "docs/src/checks2"; + +// let header = "config"; +// let body = "\ +// The top level config for cargo-deny, by default called `deny.toml`. + +// ## Example - cargo-deny's own configuration + +// ```ini +// {{#include ../../../deny.toml}} +// ```"; + +// let renderer = Renderer { +// root_file_base: Section::leaf(header, body), +// }; + +// let options = DocOptions { +// root: root.clone(), +// max_nesting_in_file: 2, +// }; + +// let files = renderer.doc(&Doc::new(options)?); + +// files.iter().try_for_each(|file| file.write(out_dir))?; + +// Ok(()) +// } diff --git a/xtask/src/cli/codegen/source.rs b/dashie/src/dashie_schema.rs similarity index 97% rename from xtask/src/cli/codegen/source.rs rename to dashie/src/dashie_schema.rs index d68c4a83..38bee3b7 100644 --- a/xtask/src/cli/codegen/source.rs +++ b/dashie/src/dashie_schema.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Result}; +use camino::Utf8Path; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -146,7 +147,7 @@ impl Schema { } /// Returns all schemas stored inside of this one. It doesn't resolve - /// references. + /// references. The iterator is depth-first. pub(crate) fn entries<'a>(&'a self) -> impl Iterator> { let mut stack = vec![SchemaEntry { schema: self, @@ -288,6 +289,12 @@ impl Schema { } impl RootSchema { + pub(crate) fn from_file(path: impl AsRef) -> Result { + let input = fs::read_to_string("deny.schema.yml")?; + let input: Self = serde_yaml::from_str(&input)?; + Ok(input) + } + pub(crate) fn definition(&self, definition: &str) -> Result<&Schema> { self.definitions .get(definition) diff --git a/xtask/src/entrypoint.rs b/dashie/src/entrypoint.rs similarity index 92% rename from xtask/src/entrypoint.rs rename to dashie/src/entrypoint.rs index f367b99b..f8790037 100644 --- a/xtask/src/entrypoint.rs +++ b/dashie/src/entrypoint.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use crate::prelude::*; use std::process::ExitCode; use tracing_subscriber::prelude::*; @@ -11,7 +11,7 @@ pub fn run() -> ExitCode { ExitCode::FAILURE } -fn try_run() -> Result<()> { +fn try_run() -> Result { let env_filter = tracing_subscriber::EnvFilter::from_env("XTASK_LOG"); let fmt = tracing_subscriber::fmt::layer() diff --git a/dashie/src/lib.rs b/dashie/src/lib.rs new file mode 100644 index 00000000..395bed15 --- /dev/null +++ b/dashie/src/lib.rs @@ -0,0 +1,14 @@ +mod cli; +mod dashie_schema; +mod entrypoint; +mod md_doc; + +pub use entrypoint::run; + +mod prelude { + pub(crate) use anyhow::{bail, Context as _}; + pub(crate) use itertools::Itertools as _; + pub(crate) use tracing::{info, warn}; + + pub(crate) type Result = std::result::Result; +} diff --git a/xtask/src/main.rs b/dashie/src/main.rs similarity index 68% rename from xtask/src/main.rs rename to dashie/src/main.rs index 91971740..e8102365 100644 --- a/xtask/src/main.rs +++ b/dashie/src/main.rs @@ -1,3 +1,3 @@ fn main() -> std::process::ExitCode { - xtask::run() + dashie::run() } diff --git a/xtask/src/cli/codegen/md_doc/mod.rs b/dashie/src/md_doc/hir/doc.rs similarity index 67% rename from xtask/src/cli/codegen/md_doc/mod.rs rename to dashie/src/md_doc/hir/doc.rs index 41f93d72..c9dc8023 100644 --- a/xtask/src/cli/codegen/md_doc/mod.rs +++ b/dashie/src/md_doc/hir/doc.rs @@ -1,79 +1,75 @@ -mod dom; -mod rendering; - -use self::dom::*; -use self::rendering::*; - -use super::source::{ArraySchema, ObjectSchema, OneOfVariantSchema}; -use crate::cli::codegen::source; -use anyhow::Result; -use itertools::Itertools; +use super::*; +use crate::dashie_schema::{ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; +use crate::prelude::*; +use buildstructor::buildstructor; use std::collections::BTreeMap; -struct DocOptions { - root: source::RootSchema, - max_nesting_in_file: usize, -} - -pub(crate) struct Doc { - root: SchemaNode, - type_index: BTreeMap, +pub(crate) struct Dom { + pub(crate) root: SchemaNode, + pub(crate) type_index: BTreeMap, } -struct GenerateDoc { - options: DocOptions, -} +#[buildstructor] +impl Dom { + #[builder] + pub(crate) fn new(schema: RootSchema, max_nesting_in_file: Option) -> Result { + let ctx = Context { + root: schema, + max_nesting_in_file: max_nesting_in_file.unwrap_or(2), + }; -impl Doc { - fn new(options: DocOptions) -> Result { - // let all_schemas = || { - // let schemas_in_root = root.schema.entries(); - // let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); - // itertools::chain(schemas_in_root, schemas_in_defs) - // }; - - // let definition_ref_counts = all_schemas() - // .map(|entry| entry.schema.referenced_definition()) - // .flatten_ok() - // .process_results(|iter| iter.counts())?; - - // let unused_defs: Vec<_> = root - // .definitions - // .iter() - // .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) - // .collect(); - - // anyhow::ensure!( - // unused_defs.is_empty(), - // "Found unused definitions: {unused_defs:#?}", - // ); - - // let repeated_references: BTreeMap<_, _> = definition_ref_counts - // .into_iter() - // // For schemas that are repeatedly referenced, we want to include them in the - // // "Type Index". This is separate page where common types are defined such - // // that we don't duplicate their docs all over the place. - // .filter(|(_, count)| *count > 1) - // .map(|(def_name, _)| { - // let schema = root.find_definition(def_name)?; - // anyhow::Ok((def_name.to_owned(), schema)) - // }) - // .try_collect()?; - - // let flattened = all_schemas() - // .filter(|entry| entry.level % max_level == 0) - // .map(|entry| { - // let schema = entry.schema; - // }) - // .collect(); - - let doc = GenerateDoc { options }.run()?; - - // doc.flatten(max_level)?; + let doc = ctx.generate()?; Ok(doc) } + // pub(crate) fn new(ctx: DocContext) -> Result { + // let all_schemas = || { + // let schemas_in_root = root.schema.entries(); + // let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); + // itertools::chain(schemas_in_root, schemas_in_defs) + // }; + + // let definition_ref_counts = all_schemas() + // .map(|entry| entry.schema.referenced_definition()) + // .flatten_ok() + // .process_results(|iter| iter.counts())?; + + // let unused_defs: Vec<_> = root + // .definitions + // .iter() + // .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) + // .collect(); + + // anyhow::ensure!( + // unused_defs.is_empty(), + // "Found unused definitions: {unused_defs:#?}", + // ); + + // let repeated_references: BTreeMap<_, _> = definition_ref_counts + // .into_iter() + // // For schemas that are repeatedly referenced, we want to include them in the + // // "Type Index". This is separate page where common types are defined such + // // that we don't duplicate their docs all over the place. + // .filter(|(_, count)| *count > 1) + // .map(|(def_name, _)| { + // let schema = root.find_definition(def_name)?; + // anyhow::Ok((def_name.to_owned(), schema)) + // }) + // .try_collect()?; + + // let flattened = all_schemas() + // .filter(|entry| entry.level % max_level == 0) + // .map(|entry| { + // let schema = entry.schema; + // }) + // .collect(); + + // doc.flatten(max_level)?; + + // Ok(doc) + // } + // fn flatten(&mut self, max_level: usize) -> Result<()> { // FlattenDoc { // ty_index: &mut self.type_index, @@ -151,13 +147,17 @@ impl Doc { // } // } -impl GenerateDoc { - fn run(self) -> Result { - let root = PathedSourceSchema::origin(PathOrigin::Root, self.options.root.schema.clone()); +struct Context { + root: RootSchema, + max_nesting_in_file: u8, +} + +impl Context { + fn generate(self) -> Result { + let root = PathedSourceSchema::origin(PathOrigin::Root, self.root.schema.clone()); let root = self.schema_node(root)?; let definitions = self - .options .root .definitions .iter() @@ -169,7 +169,7 @@ impl GenerateDoc { }) .collect::>()?; - Ok(Doc { + Ok(Dom { root, type_index: definitions, }) @@ -202,12 +202,7 @@ impl GenerateDoc { // fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { let path = schema.path; - let ty = Type::from_source_schema( - &self - .options - .root - .inline_referenced_definition(&schema.inner)?, - ); + let ty = Type::from_source_schema(&self.root.inline_referenced_definition(&schema.inner)?); let schema = schema.inner; @@ -235,7 +230,7 @@ impl GenerateDoc { let doc = if let Some(reference) = schema.reference.clone() { SchemaDoc::Ref(SchemaDocRef { reference, data }) - } else if path.segments.len() % (self.options.max_nesting_in_file + 1) == 0 { + } else if path.segments.len() % (usize::from(self.max_nesting_in_file) + 1) == 0 { SchemaDoc::Nested(data) } else { SchemaDoc::Embedded(data) @@ -301,32 +296,3 @@ impl GenerateDoc { Ok(variants) } } - -pub(crate) fn gen(root: &source::RootSchema) -> Result<()> { - let out_dir = "docs/src/checks2"; - - let header = "config"; - let body = "\ -The top level config for cargo-deny, by default called `deny.toml`. - -## Example - cargo-deny's own configuration - -```ini -{{#include ../../../deny.toml}} -```"; - - let renderer = Renderer { - root_file_base: Section::leaf(header, body), - }; - - let options = DocOptions { - root: root.clone(), - max_nesting_in_file: 2, - }; - - let files = renderer.doc(&Doc::new(options)?); - - files.iter().try_for_each(|file| file.write(out_dir))?; - - Ok(()) -} diff --git a/xtask/src/cli/codegen/md_doc/dom.rs b/dashie/src/md_doc/hir/mod.rs similarity index 85% rename from xtask/src/cli/codegen/md_doc/dom.rs rename to dashie/src/md_doc/hir/mod.rs index d61672bc..e01e3b16 100644 --- a/xtask/src/cli/codegen/md_doc/dom.rs +++ b/dashie/src/md_doc/hir/mod.rs @@ -1,5 +1,9 @@ -use crate::cli::codegen::source; -use anyhow::Result; +mod doc; + +pub(crate) use doc::*; + +use crate::dashie_schema; +use crate::prelude::*; use serde_json::Value; use std::fmt; @@ -143,11 +147,11 @@ pub(crate) struct Field { pub(crate) struct LeafType { pub(crate) ty: Option, pub(crate) format: Option, - pub(crate) enum_schema: Option>, + pub(crate) enum_schema: Option>, } impl LeafType { - fn from_source_schema(schema: &source::Schema) -> Self { + fn from_dashie_schema(schema: &dashie_schema::Schema) -> Self { Self { ty: schema.ty.clone(), format: schema.format.clone(), @@ -166,13 +170,13 @@ pub(crate) struct Type { } impl Type { - pub(crate) fn from_source_schema(schema: &source::Schema) -> Self { - let inner = LeafType::from_source_schema(schema); + pub(crate) fn from_source_schema(schema: &dashie_schema::Schema) -> Self { + let inner = LeafType::from_dashie_schema(schema); let array_items_ty = schema .array_schema .as_ref() - .map(|array| LeafType::from_source_schema(&array.items)); + .map(|array| LeafType::from_dashie_schema(&array.items)); Self { inner, @@ -184,19 +188,19 @@ impl Type { #[derive(Clone, Debug)] pub(crate) struct PathedSourceSchema { pub(crate) path: Path, - pub(crate) inner: source::Schema, + pub(crate) inner: dashie_schema::Schema, } impl PathedSourceSchema { - pub(crate) fn new(path: Path, inner: source::Schema) -> Self { + pub(crate) fn new(path: Path, inner: dashie_schema::Schema) -> Self { Self { path, inner } } - pub(crate) fn origin(origin: PathOrigin, inner: source::Schema) -> Self { + pub(crate) fn origin(origin: PathOrigin, inner: dashie_schema::Schema) -> Self { Self::new(Path::new(origin), inner) } - fn inline_referenced_definition(mut self, root: &source::RootSchema) -> Result { + fn inline_referenced_definition(mut self, root: &dashie_schema::RootSchema) -> Result { self.inner = root.inline_referenced_definition(&self.inner)?; Ok(self) } diff --git a/xtask/src/cli/codegen/md_doc/rendering/mdast.rs b/dashie/src/md_doc/mir/mdast.rs similarity index 100% rename from xtask/src/cli/codegen/md_doc/rendering/mdast.rs rename to dashie/src/md_doc/mir/mdast.rs diff --git a/xtask/src/cli/codegen/md_doc/rendering.rs b/dashie/src/md_doc/mir/mod.rs similarity index 84% rename from xtask/src/cli/codegen/md_doc/rendering.rs rename to dashie/src/md_doc/mir/mod.rs index 19d5b928..96c939d8 100644 --- a/xtask/src/cli/codegen/md_doc/rendering.rs +++ b/dashie/src/md_doc/mir/mod.rs @@ -1,22 +1,31 @@ mod mdast; -use self::mdast::MdNode; -use super::{ - Doc, LeafType, Path, PathOrigin, PathSegment, Schema, SchemaDoc, SchemaDocData, SchemaNode, +use super::hir::{ + self, LeafType, Path, PathOrigin, PathSegment, Schema, SchemaDoc, SchemaDocData, SchemaNode, Type, }; -use anyhow::{Context, Result}; +use crate::prelude::*; use camino::{Utf8Path, Utf8PathBuf}; use itertools::Itertools; use serde_json::{json, Value}; use std::collections::BTreeMap; -pub(crate) struct Renderer { - pub(crate) root_file_base: Section, +impl hir::Dom { + pub(crate) fn lower(&self) -> Dom { + let context = Context {}; + context.doc(self) + } +} + +pub(crate) struct Dom { + pub(crate) root: Document, + pub(crate) type_index: Option, } -impl Renderer { - pub(crate) fn doc(&self, doc: &Doc) -> Vec { +pub(crate) struct Context {} + +impl Context { + pub(crate) fn doc(&self, doc: &hir::Dom) -> Dom { // let root_sections = doc.root.children.iter().map(|schema| { // let key = &schema.doc.path; // let header = format!("`[{key}]`"); @@ -40,26 +49,12 @@ impl Renderer { // }); let type_index = self.type_index(&doc.type_index); - let root = NamedDocument { - name: "root".to_owned(), - document: self.schema_node(&doc.root), - }; - let children = itertools::chain([root], type_index).collect(); - - let schema = NamedDocument { - name: "schema".to_owned(), - document: Document { - section: self.root_file_base.clone(), - children, - }, - }; - - println!("{}", schema.summary().to_markdown()); + let root = self.schema_node(&doc.root); - schema.files() + Dom { root, type_index } } - fn type_index(&self, type_index: &BTreeMap) -> Option { + fn type_index(&self, type_index: &BTreeMap) -> Option { if type_index.is_empty() { return None; } @@ -68,7 +63,7 @@ impl Renderer { .iter() .map(|(name, schema)| NamedDocument { name: name.clone(), - document: self.schema_node(schema), + data: self.schema_node(schema), }) .collect(); @@ -77,12 +72,7 @@ impl Renderer { "This is an index of common types used across the schema.", ); - let document = Document { section, children }; - - Some(NamedDocument { - name: "type-index".to_owned(), - document, - }) + Some(Document { section, children }) } fn schema_node(&self, node: &SchemaNode) -> Document { @@ -364,7 +354,7 @@ impl Section { } /// Render the schema as markdown with the headers starting at the given level - fn to_markdown(&self, level: usize) -> String { + pub(crate) fn to_markdown(&self, level: usize) -> String { let header = self.header.clone(); let sharps = "#".repeat(level); let header = format!("{sharps} {header}"); @@ -379,30 +369,17 @@ impl Section { } } -struct NamedDocument { - name: String, - document: Document, +pub(crate) struct NamedDocument { + pub(crate) name: String, + pub(crate) data: Document, } impl NamedDocument { - fn summary(&self) -> MdNode<'_> { - // TODO: unhardcode root path - let path = Utf8PathBuf::from("checks2"); - let node = self.summary_imp(path); - MdNode::unordered_list([node]) - } - - fn summary_imp(&self, path: Utf8PathBuf) -> MdNode<'_> { - let url = path.join(format!("{}.md", self.name)); - let link = MdNode::link([MdNode::text(self.name.as_str())], url.into_string()); - - let children = self - .document - .children - .iter() - .map(|child| child.summary_imp(path.join(&self.name))); - - MdNode::many([link, MdNode::unordered_list(children)]) + pub(crate) fn new(name: impl Into, data: Document) -> Self { + Self { + name: name.into(), + data, + } } fn files(&self) -> Vec { @@ -416,18 +393,18 @@ impl NamedDocument { fn files_imp(&self, path: Utf8PathBuf, files: &mut Vec) { let file_name = format!("{}.md", self.name); - let file = File::new(path.join(file_name), self.document.section.clone()); + let file = File::new(path.join(file_name), self.data.section.clone()); files.push(file); - for child in &self.document.children { + for child in &self.data.children { child.files_imp(path.join(&self.name), files); } } } -struct Document { - section: Section, - children: Vec, +pub(crate) struct Document { + pub(crate) section: Section, + pub(crate) children: Vec, } impl Document { @@ -441,23 +418,23 @@ impl Document { pub(crate) struct File { path: Utf8PathBuf, - rendered: Section, + section: Section, } impl File { - fn new(path: impl Into, rendered: Section) -> Self { + fn new(path: impl Into, section: Section) -> Self { Self { path: path.into(), - rendered, + section, } } - pub(crate) fn write(&self, prefix: impl AsRef) -> Result<()> { + pub(crate) fn write(&self, prefix: impl AsRef) -> Result { let path = prefix.as_ref().join(&self.path); std::fs::create_dir_all(path.parent().unwrap())?; - std::fs::write(&path, self.rendered.to_markdown(1)) + std::fs::write(&path, self.section.to_markdown(1)) .with_context(|| format!("Failed to write to file: {path}")) } } diff --git a/dashie/src/md_doc/mod.rs b/dashie/src/md_doc/mod.rs new file mode 100644 index 00000000..a48f72a5 --- /dev/null +++ b/dashie/src/md_doc/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod hir; +pub(crate) mod mir; diff --git a/docs/book.toml b/docs/book.toml index 6a244a3b..32ec9cc6 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -5,6 +5,10 @@ multilingual = false src = "src" title = "cargo-deny" +[preprocessor.dashie] +command = "./target/debug/dashie mdbook preprocessor" +dashie_schema = "../deny.schema.yml" + [output.html] # Disabled until https://github.com/Michael-F-Bryan/mdbook-linkcheck/issues/25 diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index c87ba305..d4007400 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -20,22 +20,5 @@ - [sources](checks/sources/README.md) - [config](checks/sources/cfg.md) - [diagnostics](checks/sources/diags.md) -- [Type Index](checks2/type-index.md) -- [Checks2](checks/README.md) - - [schema](checks2/schema.md) - - [root](checks2/schema/root.md) - - [type-index](checks2/schema/type-index.md) - - [Advisories](checks2/schema/type-index/Advisories.md) - - [AdvisoriesIgnoreAdvisory](checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md) - - [AdvisoriesIgnoreItem](checks2/schema/type-index/AdvisoriesIgnoreItem.md) - - [AdvisoriesIgnoreYanked](checks2/schema/type-index/AdvisoriesIgnoreYanked.md) - - [Bans](checks2/schema/type-index/Bans.md) - - [BansAllow](checks2/schema/type-index/BansAllow.md) - - [Graph](checks2/schema/type-index/Graph.md) - - [IgnoreReason](checks2/schema/type-index/IgnoreReason.md) - - [LintLevel](checks2/schema/type-index/LintLevel.md) - - [Output](checks2/schema/type-index/Output.md) - - [PackageSpec](checks2/schema/type-index/PackageSpec.md) - - [Target](checks2/schema/type-index/Target.md) - - [TargetAdvanced](checks2/schema/type-index/TargetAdvanced.md) - - [TargetString](checks2/schema/type-index/TargetString.md) +- [Config file {{ dashie-root }}]() +- [Type Index {{ dashie-type-index }}]() diff --git a/docs/src/checks2/advisories/README.md b/docs/src/checks2/advisories/README.md deleted file mode 100644 index dd95b93f..00000000 --- a/docs/src/checks2/advisories/README.md +++ /dev/null @@ -1 +0,0 @@ -# advisories diff --git a/docs/src/checks2/advisories/cfg.md b/docs/src/checks2/advisories/cfg.md deleted file mode 100644 index 1417945b..00000000 --- a/docs/src/checks2/advisories/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# config diff --git a/docs/src/checks2/advisories/diags.md b/docs/src/checks2/advisories/diags.md deleted file mode 100644 index c5f98215..00000000 --- a/docs/src/checks2/advisories/diags.md +++ /dev/null @@ -1 +0,0 @@ -# diagnostics diff --git a/docs/src/checks2/bans/README.md b/docs/src/checks2/bans/README.md deleted file mode 100644 index 27c9f3ef..00000000 --- a/docs/src/checks2/bans/README.md +++ /dev/null @@ -1 +0,0 @@ -# bans diff --git a/docs/src/checks2/bans/cfg.md b/docs/src/checks2/bans/cfg.md deleted file mode 100644 index 1417945b..00000000 --- a/docs/src/checks2/bans/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# config diff --git a/docs/src/checks2/bans/diags.md b/docs/src/checks2/bans/diags.md deleted file mode 100644 index c5f98215..00000000 --- a/docs/src/checks2/bans/diags.md +++ /dev/null @@ -1 +0,0 @@ -# diagnostics diff --git a/docs/src/checks2/graph/cfg.md b/docs/src/checks2/graph/cfg.md deleted file mode 100644 index 8dc858c5..00000000 --- a/docs/src/checks2/graph/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# graph diff --git a/docs/src/checks2/licenses/README.md b/docs/src/checks2/licenses/README.md deleted file mode 100644 index d40246d5..00000000 --- a/docs/src/checks2/licenses/README.md +++ /dev/null @@ -1 +0,0 @@ -# licenses diff --git a/docs/src/checks2/licenses/cfg.md b/docs/src/checks2/licenses/cfg.md deleted file mode 100644 index 1417945b..00000000 --- a/docs/src/checks2/licenses/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# config diff --git a/docs/src/checks2/licenses/diags.md b/docs/src/checks2/licenses/diags.md deleted file mode 100644 index c5f98215..00000000 --- a/docs/src/checks2/licenses/diags.md +++ /dev/null @@ -1 +0,0 @@ -# diagnostics diff --git a/docs/src/checks2/output/cfg.md b/docs/src/checks2/output/cfg.md deleted file mode 100644 index 2580f631..00000000 --- a/docs/src/checks2/output/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# output diff --git a/docs/src/checks2/schema.md b/docs/src/checks2/schema.md deleted file mode 100644 index 367e4ee6..00000000 --- a/docs/src/checks2/schema.md +++ /dev/null @@ -1,9 +0,0 @@ -# config - -The top level config for cargo-deny, by default called `deny.toml`. - -## Example - cargo-deny's own configuration - -```ini -{{#include ../../../deny.toml}} -``` \ No newline at end of file diff --git a/docs/src/checks2/schema/root.md b/docs/src/checks2/schema/root.md deleted file mode 100644 index d24c9a4b..00000000 --- a/docs/src/checks2/schema/root.md +++ /dev/null @@ -1,27 +0,0 @@ -# Root - -**Type:** `object` - -Configuration file for cargo-deny, by default called `deny.toml`. - -Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html - -## `advisories` - -**Type:** [`Advisories`](/checks2/schema/type-index/Advisories.md) `object`
-**Key:** `optional` - -## `bans` - -**Type:** [`Bans`](/checks2/schema/type-index/Bans.md) `object`
-**Key:** `optional` - -## `graph` - -**Type:** [`Graph`](/checks2/schema/type-index/Graph.md) `object`
-**Key:** `optional` - -## `output` - -**Type:** [`Output`](/checks2/schema/type-index/Output.md) `object`
-**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index.md b/docs/src/checks2/schema/type-index.md deleted file mode 100644 index dc677c54..00000000 --- a/docs/src/checks2/schema/type-index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Type Index - -This is an index of common types used across the schema. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Advisories.md b/docs/src/checks2/schema/type-index/Advisories.md deleted file mode 100644 index a2d31a9e..00000000 --- a/docs/src/checks2/schema/type-index/Advisories.md +++ /dev/null @@ -1,204 +0,0 @@ -# `Advisories` - -**Type:** `object` - -Checks advisory databases for crates with security vulnerabilities, -or that have been marked as unmaintained, or which have been yanked from -their source registry. - -This section is considered when running `cargo deny check advisories`. - - -## Example - -```toml -db-path = "~/.cargo/advisory-dbs" -db-urls = ["https://github.com/RustSec/advisory-db"] -vulnerability = "deny" -unmaintained = "warn" -unsound = "warn" -yanked = "warn" -notice = "warn" -ignore = [ - "RUSTSEC-0000-0000", - "crate@0.1", - { crate = "yanked", reason = "a new version has not been released" }, -] -severity-threshold = "medium" -``` - -## `db-urls` - -**Type:** `array`
-**Key:** `optional` - -URLs to one or more advisory databases. - -### Default - -```toml -db-urls = ["https://github.com/RustSec/advisory-db"] -``` - -### `db-urls[N]` - -**Type:** `string (uri)` - -## `db-path` - -**Type:** `string`
-**Key:** `optional` - -Path to the root directory into which one or more advisory databases are cloned into. - -This value supports basic shell expansion: - -- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) -- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) - or the fallback value if it doesn't exist (everything between the `:-` and `}`) -- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) - if it exists, otherwise expands to `$(home::home_dir())/.cargo` - -Note that the path must be valid utf-8, after expansion. - - -### Default - -```toml -db-path = "$CARGO_HOME/advisory-dbs" -``` - -## `version` - -**Type:** `integer (enum)`
-**Key:** `optional` - -The advisories section has an upcoming breaking change, with deprecation warnings for several -fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. - -The breaking change is as follows: - -- `vulnerability` - Removed, all vulnerability advisories now emit errors. -- `unmaintained` - Removed, all unmaintained advisories now emit errors. -- `unsound` - Removed, all unsound advisories now emit errors. -- `notice` - Removed, all notice advisories now emit errors. -- `severity-threshold` - Removed, all vulnerability advisories now emit errors. - -As before, if you want to ignore a specific advisory, add it to the `ignore` field. - - -### Possible values - -- `2` - -## `vulnerability` - -**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
-**Key:** `optional` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a security vulnerability is encountered. - - -### Default - -```toml -vulnerability = "deny" -``` - -## `unmaintained` - -**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
-**Key:** `optional` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unmaintained` advisory is encountered. - - -### Default - -```toml -unmaintained = "warn" -``` - -## `unsound` - -**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
-**Key:** `optional` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with an `unsound` advisory is encountered. - - -### Default - -```toml -unsound = "warn" -``` - -## `notice` - -**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
-**Key:** `optional` - -**DEPRECATED** (see `version` field) - -Determines what happens when a crate with a `notice` advisory is encountered. - -**NOTE**: As of 2019-12-17 there are no `notice` advisories in the -[RustSec Advisory DB](https://github.com/RustSec/advisory-db) - - -### Default - -```toml -notice = "warn" -``` - -## `yanked` - -**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
-**Key:** `optional` - -Determines what happens when a crate with a version that has been yanked from its source -registry is encountered. - - -### Default - -```toml -yanked = "warn" -``` - -## `ignore` - -**Type:** `array`
-**Key:** `optional` - -Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. -Putting an identifier in this array will cause the advisory to be treated as a note, rather -than a warning or error. - -In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -with an optional `reason`. - - -### Example - -```toml -ignore = [ - "RUSTSEC-0000-0000", - { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, - "yanked@0.1.1", - { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, -] -``` - -### `ignore[N]` - -**Type:** [`AdvisoriesIgnoreItem`](/checks2/schema/type-index/AdvisoriesIgnoreItem.md) \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md deleted file mode 100644 index f6a48ec0..00000000 --- a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md +++ /dev/null @@ -1,21 +0,0 @@ -# `AdvisoriesIgnoreAdvisory` - -**Type:** `object` - -## `id` - -**Type:** `string`
-**Key:** `required` - -The unique identifier of the advisory to ignore - -### Example - -```toml -id = "RUSTSEC-2019-0001" -``` - -## `reason` - -**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
-**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md deleted file mode 100644 index 33d4d2de..00000000 --- a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreItem.md +++ /dev/null @@ -1,17 +0,0 @@ -# `AdvisoriesIgnoreItem` - - - -## `As string` - -**Type:** `string` - -Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - -## `As AdvisoriesIgnoreAdvisory` - -**Type:** [`AdvisoriesIgnoreAdvisory`](/checks2/schema/type-index/AdvisoriesIgnoreAdvisory.md) `object` - -## `As AdvisoriesIgnoreYanked` - -**Type:** [`AdvisoriesIgnoreYanked`](/checks2/schema/type-index/AdvisoriesIgnoreYanked.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md b/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md deleted file mode 100644 index f5c80e22..00000000 --- a/docs/src/checks2/schema/type-index/AdvisoriesIgnoreYanked.md +++ /dev/null @@ -1,13 +0,0 @@ -# `AdvisoriesIgnoreYanked` - -**Type:** `object` - -## `crate` - -**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string`
-**Key:** `required` - -## `reason` - -**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
-**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Bans.md b/docs/src/checks2/schema/type-index/Bans.md deleted file mode 100644 index 17a8d57b..00000000 --- a/docs/src/checks2/schema/type-index/Bans.md +++ /dev/null @@ -1,13 +0,0 @@ -# `Bans` - -**Type:** `object` - -Checks for specific crates in your graph, as well as duplicates. - -This section is considered when running `cargo deny check bans`. - - -## `allow` - -**Type:** [`BansAllow`](/checks2/schema/type-index/BansAllow.md) `array`
-**Key:** `optional` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/BansAllow.md b/docs/src/checks2/schema/type-index/BansAllow.md deleted file mode 100644 index 7d99ce2c..00000000 --- a/docs/src/checks2/schema/type-index/BansAllow.md +++ /dev/null @@ -1,13 +0,0 @@ -# `BansAllow` - -**Type:** `array` - -Determines specific crates that are allowed. If the `allow` list has one or more entries, then -any crate not in that list will be denied, so use with care. Each entry uses the same -[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -as other parts of cargo-deny's configuration. - - -## `[N]` - -**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Graph.md b/docs/src/checks2/schema/type-index/Graph.md deleted file mode 100644 index 69d9ea06..00000000 --- a/docs/src/checks2/schema/type-index/Graph.md +++ /dev/null @@ -1,105 +0,0 @@ -# `Graph` - -**Type:** `object` - -The graph table configures how the dependency graph is constructed and thus which crates the -checks are performed against - - -## `targets` - -**Type:** `array`
-**Key:** `optional` - -By default, cargo-deny will consider every single crate that is resolved by cargo, including -target specific dependencies e.g. - -```toml -[target.x86_64-pc-windows-msvc.dependencies] -winapi = "0.3.8" - -[target.'cfg(target_os = "fuchsia")'.dependencies] -fuchsia-cprng = "0.1.1" -``` - -But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is -never actually going to be compiled or linked into your project, so checking it is pointless for you. - -The `targets` field allows you to specify one or more targets which you **actually** build for. -Every dependency link to a crate is checked against this list, and if none of the listed targets -satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links -to it, it is not included into the crate graph that the checks are -executed against. - - -### `targets[N]` - -**Type:** [`Target`](/checks2/schema/type-index/Target.md) - -## `exclude` - -**Type:** `array`
-**Key:** `optional` - -Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) -that will cause the crate(s) in question to be excluded from the crate graph that is used -for the operation you are performing. - -Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced -via the excluded crate, they will also be excluded from the crate graph. - - -### Example - -```toml -exclude = "some-crate@0.1.0" -``` - -### `exclude[N]` - -**Type:** `string` - -## `all-features` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, `--all-features` will be used when collecting metadata. - -## `no-default-features` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, `--no-default-features` will be used when collecting metadata. - -## `features` - -**Type:** `array`
-**Key:** `optional` - -If set, and `--features` is not specified on the cmd line, these features will be used when -collecting metadata. - - -### Example - -```toml -features = "some-feature" -``` - -### `features[N]` - -**Type:** `string` - -## `exclude-dev` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included -in the crate graph used for any of the checks. This option can also be enabled on cmd line -with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) -the `check` subcommand. diff --git a/docs/src/checks2/schema/type-index/IgnoreReason.md b/docs/src/checks2/schema/type-index/IgnoreReason.md deleted file mode 100644 index 2b0899c3..00000000 --- a/docs/src/checks2/schema/type-index/IgnoreReason.md +++ /dev/null @@ -1,5 +0,0 @@ -# `IgnoreReason` - -**Type:** `string` - -Free-form string that can be used to describe the reason why the advisory is ignored. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/LintLevel.md b/docs/src/checks2/schema/type-index/LintLevel.md deleted file mode 100644 index 4da3f64e..00000000 --- a/docs/src/checks2/schema/type-index/LintLevel.md +++ /dev/null @@ -1,9 +0,0 @@ -# `LintLevel` - -**Type:** `string (enum)` - -## Possible values - -- `"deny"` - Emit an error with details about the problem, and fail the check. -- `"warn"` - Print a warning for each propblem, but don't fail the check. -- `"allow"` - Print a note about the problem, but don't fail the check. \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/Output.md b/docs/src/checks2/schema/type-index/Output.md deleted file mode 100644 index 3028661c..00000000 --- a/docs/src/checks2/schema/type-index/Output.md +++ /dev/null @@ -1,21 +0,0 @@ -# `Output` - -**Type:** `object` - -The output table provides options for how/if diagnostics are outputted - -## `feature-depth` - -**Type:** `integer`
-**Key:** `optional` - -The maximum depth that features will be displayed when inclusion graphs are shown in -diagnostics, unless specified via `--feature-depth` on the command line. Only applies to -diagnostics that actually print features. - - -### Default - -```toml -feature-depth = 1 -``` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/PackageSpec.md b/docs/src/checks2/schema/type-index/PackageSpec.md deleted file mode 100644 index bb3985a1..00000000 --- a/docs/src/checks2/schema/type-index/PackageSpec.md +++ /dev/null @@ -1,73 +0,0 @@ -# `PackageSpec` - -**Type:** `string` - -Many configuration options require a package specifier at a minimum, which we'll describe here. -The options that use package specifiers will be called out in their individual documentation. -We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. - -### String format - -If the particular only requires a package spec at a minimum, then the string format can be used, -which comes in three forms. - -#### Simple - -```toml -# Will match any version of the simple crate -deny = ["simple"] -``` - -The simplest string is one which is just the crate name. In this case, the version requirement -used when checking will be `*` meaning it will match against all versions of that crate in the graph. - -#### With Version Requirements - -```toml -# Will match only these versions of the simple crate that match the predicate(s) -deny = ["simple:<=0.1,>0.2"] -``` - -If you want to apply version requirements (predicates) to the crate, simply append them following -a `:` separator. - -#### Exact - -```toml -# Will match only this exact version of the simple crate -deny = [ - "simple@0.1.0", - # This is semantically equivalent to the above - "simple:=0.1.0", -] -``` - -The exact form is a specialization of the version requirements, where the semver after the `@` -is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). - -### Table format - -#### Crate format - -```toml -deny = [ - { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" - { crate = "simple", wrappers = ["example"] }, -] -``` - -The crate format is a replacement for the old `name` and/or `version` table format. It uses -the string format described above in a single `crate` key. - -#### Old format - -```toml -deny = [ - { name = "simple" }, - { name = "simple", version = "*" }, - { name = "simple", wrappers = ["example"] } -] -``` - -The old format uses a required `name` key and an optional `version` key. This format is deprecated -and should not be used. diff --git a/docs/src/checks2/schema/type-index/Target.md b/docs/src/checks2/schema/type-index/Target.md deleted file mode 100644 index df380b55..00000000 --- a/docs/src/checks2/schema/type-index/Target.md +++ /dev/null @@ -1,11 +0,0 @@ -# `Target` - - - -## `As TargetString` - -**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string` - -## `As TargetAdvanced` - -**Type:** [`TargetAdvanced`](/checks2/schema/type-index/TargetAdvanced.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/schema/type-index/TargetAdvanced.md b/docs/src/checks2/schema/type-index/TargetAdvanced.md deleted file mode 100644 index 743f9226..00000000 --- a/docs/src/checks2/schema/type-index/TargetAdvanced.md +++ /dev/null @@ -1,32 +0,0 @@ -# `TargetAdvanced` - -**Type:** `object` - -Advanced configurations to apply for the target triple - -## Examples - -- ```toml - triple = "aarch64-apple-darwin" - ``` -- ```toml - triple = "x86_64-pc-windows-msvc" - features = ["some-feature"] - ``` - -## `triple` - -**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string`
-**Key:** `required` - -## `features` - -**Type:** `string`
-**Key:** `optional` - -Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) -predicate, but at the moment, the only way to actually pass them when compiling is to use -the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more -`target_feature`s you plan to build with, for a particular target triple. At the time of -this writing, cargo-deny does not attempt to validate that the features you specify are -actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). diff --git a/docs/src/checks2/schema/type-index/TargetString.md b/docs/src/checks2/schema/type-index/TargetString.md deleted file mode 100644 index 9972e1c6..00000000 --- a/docs/src/checks2/schema/type-index/TargetString.md +++ /dev/null @@ -1,22 +0,0 @@ -# `TargetString` - -**Type:** `string` - -The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target -you wish to filter target specific dependencies with. If the target triple specified is **not** -one of the targets builtin to `rustc`, the configuration check for that target will be limited -to only the raw `[target..dependencies]` style of target configuration, as `cfg()` -expressions require us to know the details about the target. - - -## Examples - -- ```toml - value = "x86_64-unknown-linux-gnu" - ``` -- ```toml - value = "x86_64-pc-windows-msvc" - ``` -- ```toml - value = "aarch64-apple-darwin" - ``` \ No newline at end of file diff --git a/docs/src/checks2/sources/README.md b/docs/src/checks2/sources/README.md deleted file mode 100644 index e916e46e..00000000 --- a/docs/src/checks2/sources/README.md +++ /dev/null @@ -1 +0,0 @@ -# sources diff --git a/docs/src/checks2/sources/cfg.md b/docs/src/checks2/sources/cfg.md deleted file mode 100644 index 1417945b..00000000 --- a/docs/src/checks2/sources/cfg.md +++ /dev/null @@ -1 +0,0 @@ -# config diff --git a/docs/src/checks2/sources/diags.md b/docs/src/checks2/sources/diags.md deleted file mode 100644 index c5f98215..00000000 --- a/docs/src/checks2/sources/diags.md +++ /dev/null @@ -1 +0,0 @@ -# diagnostics diff --git a/docs/src/checks2/type-index.md b/docs/src/checks2/type-index.md deleted file mode 100644 index 9ebf3ff6..00000000 --- a/docs/src/checks2/type-index.md +++ /dev/null @@ -1,10 +0,0 @@ -# Type Index - -This is an index of common types used across the schema. - - - -This is a bad thing that you should pay attention to. - -Warning blocks should be used sparingly in documentation, to - diff --git a/docs/src/checks2/type-index/Advisories.md b/docs/src/checks2/type-index/Advisories.md deleted file mode 100644 index 9188ec72..00000000 --- a/docs/src/checks2/type-index/Advisories.md +++ /dev/null @@ -1,142 +0,0 @@ -# `Advisories` - -**Type:** `object` - -Checks advisory databases for crates with security vulnerabilities, -or that have been marked as unmaintained, or which have been yanked from -their source registry. - -This section is considered when running `cargo deny check advisories`. - - -## Example - -```toml -db-path = "~/.cargo/advisory-dbs" -db-urls = ["https://github.com/RustSec/advisory-db"] -vulnerability = "deny" -unmaintained = "warn" -unsound = "warn" -yanked = "warn" -notice = "warn" -ignore = [ - "RUSTSEC-0000-0000", - "crate@0.1", - { crate = "yanked", reason = "a new version has not been released" }, -] -severity-threshold = "medium" -``` - -## `db-urls` - -**Type:** `array`
-**Key:** `optional` - -URLs to one or more advisory databases. - -### Default - -```toml -db-urls = ["https://github.com/RustSec/advisory-db"] -``` - -### Array item - -**Type:** `string (uri)` - -## `db-path` - -**Type:** `string`
-**Key:** `optional` - -Path to the root directory into which one or more advisory databases are cloned into. - -This value supports basic shell expansion: - -- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) -- `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) -- `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) - or the fallback value if it doesn't exist (everything between the `:-` and `}`) -- `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) - if it exists, otherwise expands to `$(home::home_dir())/.cargo` - -Note that the path must be valid utf-8, after expansion. - - -### Default - -```toml -db-path = "$CARGO_HOME/advisory-dbs" -``` - -## `version` - -**Type:** `integer (enum)`
-**Key:** `optional` - -The advisories section has an upcoming breaking change, with deprecation warnings for several -fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. - -The breaking change is as follows: - -- `vulnerability` - Removed, all vulnerability advisories now emit errors. -- `unmaintained` - Removed, all unmaintained advisories now emit errors. -- `unsound` - Removed, all unsound advisories now emit errors. -- `notice` - Removed, all notice advisories now emit errors. -- `severity-threshold` - Removed, all vulnerability advisories now emit errors. - -As before, if you want to ignore a specific advisory, add it to the `ignore` field. - - -### Possible values - -- `2` - -## `vulnerability` - -**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` - -## `unmaintained` - -**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` - -## `unsound` - -**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` - -## `notice` - -**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` - -## `yanked` - -**Type:** [`LintLevel`](/checks2/type-index/LintLevel.md) `string (enum)` - -## `ignore` - -**Type:** `array`
-**Key:** `optional` - -Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. -Putting an identifier in this array will cause the advisory to be treated as a note, rather -than a warning or error. - -In addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -with an optional `reason`. - - -### Example - -```toml -ignore = [ - "RUSTSEC-0000-0000", - { id = "RUSTSEC-0000-0000", reason = "this vulnerability does not affect us as we don't use the particular code path" }, - "yanked@0.1.1", - { crate = "yanked-crate@0.1.1", reason = "a semver compatible version hasn't been published yet" }, -] -``` - -### Array item - -**Type:** [`AdvisoriesIgnoreItem`](/checks2/type-index/AdvisoriesIgnoreItem.md) \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md b/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md deleted file mode 100644 index b297819c..00000000 --- a/docs/src/checks2/type-index/AdvisoriesIgnoreAdvisory.md +++ /dev/null @@ -1,20 +0,0 @@ -# `AdvisoriesIgnoreAdvisory` - -**Type:** `object` - -## `id` - -**Type:** `string`
-**Key:** `required` - -The unique identifier of the advisory to ignore - -### Example - -```toml -id = "RUSTSEC-2019-0001" -``` - -## `reason` - -**Type:** [`IgnoreReason`](/checks2/type-index/IgnoreReason.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md b/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md deleted file mode 100644 index b9b7bb3e..00000000 --- a/docs/src/checks2/type-index/AdvisoriesIgnoreItem.md +++ /dev/null @@ -1,17 +0,0 @@ -# `AdvisoriesIgnoreItem` - - - -## Variant: `string` - -**Type:** `string` - -Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`). - -## Variant: `AdvisoriesIgnoreAdvisory` - -**Type:** [`AdvisoriesIgnoreAdvisory`](/checks2/type-index/AdvisoriesIgnoreAdvisory.md) `object` - -## Variant: `AdvisoriesIgnoreYanked` - -**Type:** [`AdvisoriesIgnoreYanked`](/checks2/type-index/AdvisoriesIgnoreYanked.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md b/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md deleted file mode 100644 index 20a1242c..00000000 --- a/docs/src/checks2/type-index/AdvisoriesIgnoreYanked.md +++ /dev/null @@ -1,11 +0,0 @@ -# `AdvisoriesIgnoreYanked` - -**Type:** `object` - -## `crate` - -**Type:** [`PackageSpec`](/checks2/type-index/PackageSpec.md) `string` - -## `reason` - -**Type:** [`IgnoreReason`](/checks2/type-index/IgnoreReason.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/Bans.md b/docs/src/checks2/type-index/Bans.md deleted file mode 100644 index b13d9ec1..00000000 --- a/docs/src/checks2/type-index/Bans.md +++ /dev/null @@ -1,12 +0,0 @@ -# `Bans` - -**Type:** `object` - -Checks for specific crates in your graph, as well as duplicates. - -This section is considered when running `cargo deny check bans`. - - -## `allow` - -**Type:** [`BansAllow`](/checks2/type-index/BansAllow.md) `array` \ No newline at end of file diff --git a/docs/src/checks2/type-index/BansAllow.md b/docs/src/checks2/type-index/BansAllow.md deleted file mode 100644 index daf6dfb8..00000000 --- a/docs/src/checks2/type-index/BansAllow.md +++ /dev/null @@ -1,13 +0,0 @@ -# `BansAllow` - -**Type:** `array` - -Determines specific crates that are allowed. If the `allow` list has one or more entries, then -any crate not in that list will be denied, so use with care. Each entry uses the same -[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) -as other parts of cargo-deny's configuration. - - -## Array item - -**Type:** [`PackageSpec`](/checks2/type-index/PackageSpec.md) `string` \ No newline at end of file diff --git a/docs/src/checks2/type-index/Graph.md b/docs/src/checks2/type-index/Graph.md deleted file mode 100644 index 9f34d63d..00000000 --- a/docs/src/checks2/type-index/Graph.md +++ /dev/null @@ -1,105 +0,0 @@ -# `Graph` - -**Type:** `object` - -The graph table configures how the dependency graph is constructed and thus which crates the -checks are performed against - - -## `targets` - -**Type:** `array`
-**Key:** `optional` - -By default, cargo-deny will consider every single crate that is resolved by cargo, including -target specific dependencies e.g. - -```toml -[target.x86_64-pc-windows-msvc.dependencies] -winapi = "0.3.8" - -[target.'cfg(target_os = "fuchsia")'.dependencies] -fuchsia-cprng = "0.1.1" -``` - -But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is -never actually going to be compiled or linked into your project, so checking it is pointless for you. - -The `targets` field allows you to specify one or more targets which you **actually** build for. -Every dependency link to a crate is checked against this list, and if none of the listed targets -satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links -to it, it is not included into the crate graph that the checks are -executed against. - - -### Array item - -**Type:** [`Target`](/checks2/type-index/Target.md) - -## `exclude` - -**Type:** `array`
-**Key:** `optional` - -Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) -that will cause the crate(s) in question to be excluded from the crate graph that is used -for the operation you are performing. - -Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced -via the excluded crate, they will also be excluded from the crate graph. - - -### Example - -```toml -exclude = "some-crate@0.1.0" -``` - -### Array item - -**Type:** `string` - -## `all-features` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, `--all-features` will be used when collecting metadata. - -## `no-default-features` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, `--no-default-features` will be used when collecting metadata. - -## `features` - -**Type:** `array`
-**Key:** `optional` - -If set, and `--features` is not specified on the cmd line, these features will be used when -collecting metadata. - - -### Example - -```toml -features = "some-feature" -``` - -### Array item - -**Type:** `string` - -## `exclude-dev` - -**Type:** `boolean`
-**Key:** `optional` - -If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included -in the crate graph used for any of the checks. This option can also be enabled on cmd line -with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) -or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) -the `check` subcommand. diff --git a/docs/src/checks2/type-index/IgnoreReason.md b/docs/src/checks2/type-index/IgnoreReason.md deleted file mode 100644 index 2b0899c3..00000000 --- a/docs/src/checks2/type-index/IgnoreReason.md +++ /dev/null @@ -1,5 +0,0 @@ -# `IgnoreReason` - -**Type:** `string` - -Free-form string that can be used to describe the reason why the advisory is ignored. \ No newline at end of file diff --git a/docs/src/checks2/type-index/LintLevel.md b/docs/src/checks2/type-index/LintLevel.md deleted file mode 100644 index 4e4f897a..00000000 --- a/docs/src/checks2/type-index/LintLevel.md +++ /dev/null @@ -1,11 +0,0 @@ -# `LintLevel` - -**Type:** `string (enum)` - -## Possible values - -- `"deny"` - Emit an error with details about the problem, and fail the check. - -- `"warn"` - Print a warning for each propblem, but don't fail the check. - -- `"allow"` - Print a note about the problem, but don't fail the check. \ No newline at end of file diff --git a/docs/src/checks2/type-index/Output.md b/docs/src/checks2/type-index/Output.md deleted file mode 100644 index 3028661c..00000000 --- a/docs/src/checks2/type-index/Output.md +++ /dev/null @@ -1,21 +0,0 @@ -# `Output` - -**Type:** `object` - -The output table provides options for how/if diagnostics are outputted - -## `feature-depth` - -**Type:** `integer`
-**Key:** `optional` - -The maximum depth that features will be displayed when inclusion graphs are shown in -diagnostics, unless specified via `--feature-depth` on the command line. Only applies to -diagnostics that actually print features. - - -### Default - -```toml -feature-depth = 1 -``` \ No newline at end of file diff --git a/docs/src/checks2/type-index/PackageSpec.md b/docs/src/checks2/type-index/PackageSpec.md deleted file mode 100644 index bb3985a1..00000000 --- a/docs/src/checks2/type-index/PackageSpec.md +++ /dev/null @@ -1,73 +0,0 @@ -# `PackageSpec` - -**Type:** `string` - -Many configuration options require a package specifier at a minimum, which we'll describe here. -The options that use package specifiers will be called out in their individual documentation. -We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. - -### String format - -If the particular only requires a package spec at a minimum, then the string format can be used, -which comes in three forms. - -#### Simple - -```toml -# Will match any version of the simple crate -deny = ["simple"] -``` - -The simplest string is one which is just the crate name. In this case, the version requirement -used when checking will be `*` meaning it will match against all versions of that crate in the graph. - -#### With Version Requirements - -```toml -# Will match only these versions of the simple crate that match the predicate(s) -deny = ["simple:<=0.1,>0.2"] -``` - -If you want to apply version requirements (predicates) to the crate, simply append them following -a `:` separator. - -#### Exact - -```toml -# Will match only this exact version of the simple crate -deny = [ - "simple@0.1.0", - # This is semantically equivalent to the above - "simple:=0.1.0", -] -``` - -The exact form is a specialization of the version requirements, where the semver after the `@` -is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). - -### Table format - -#### Crate format - -```toml -deny = [ - { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" - { crate = "simple", wrappers = ["example"] }, -] -``` - -The crate format is a replacement for the old `name` and/or `version` table format. It uses -the string format described above in a single `crate` key. - -#### Old format - -```toml -deny = [ - { name = "simple" }, - { name = "simple", version = "*" }, - { name = "simple", wrappers = ["example"] } -] -``` - -The old format uses a required `name` key and an optional `version` key. This format is deprecated -and should not be used. diff --git a/docs/src/checks2/type-index/Target.md b/docs/src/checks2/type-index/Target.md deleted file mode 100644 index 0b59ef1f..00000000 --- a/docs/src/checks2/type-index/Target.md +++ /dev/null @@ -1,11 +0,0 @@ -# `Target` - - - -## Variant: `TargetString` - -**Type:** [`TargetString`](/checks2/type-index/TargetString.md) `string` - -## Variant: `TargetAdvanced` - -**Type:** [`TargetAdvanced`](/checks2/type-index/TargetAdvanced.md) `object` \ No newline at end of file diff --git a/docs/src/checks2/type-index/TargetAdvanced.md b/docs/src/checks2/type-index/TargetAdvanced.md deleted file mode 100644 index 1562680c..00000000 --- a/docs/src/checks2/type-index/TargetAdvanced.md +++ /dev/null @@ -1,31 +0,0 @@ -# `TargetAdvanced` - -**Type:** `object` - -Advanced configurations to apply for the target triple - -## Examples - -- ```toml - triple = "aarch64-apple-darwin" - ``` -- ```toml - triple = "x86_64-pc-windows-msvc" - features = ["some-feature"] - ``` - -## `triple` - -**Type:** [`TargetString`](/checks2/type-index/TargetString.md) `string` - -## `features` - -**Type:** `string`
-**Key:** `optional` - -Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) -predicate, but at the moment, the only way to actually pass them when compiling is to use -the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more -`target_feature`s you plan to build with, for a particular target triple. At the time of -this writing, cargo-deny does not attempt to validate that the features you specify are -actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). diff --git a/docs/src/checks2/type-index/TargetString.md b/docs/src/checks2/type-index/TargetString.md deleted file mode 100644 index 9972e1c6..00000000 --- a/docs/src/checks2/type-index/TargetString.md +++ /dev/null @@ -1,22 +0,0 @@ -# `TargetString` - -**Type:** `string` - -The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target -you wish to filter target specific dependencies with. If the target triple specified is **not** -one of the targets builtin to `rustc`, the configuration check for that target will be limited -to only the raw `[target..dependencies]` style of target configuration, as `cfg()` -expressions require us to know the details about the target. - - -## Examples - -- ```toml - value = "x86_64-unknown-linux-gnu" - ``` -- ```toml - value = "x86_64-pc-windows-msvc" - ``` -- ```toml - value = "aarch64-apple-darwin" - ``` \ No newline at end of file diff --git a/docus/src/plugin/source.ts b/docus/src/plugin/source.ts index d59e546b..9bc2d641 100644 --- a/docus/src/plugin/source.ts +++ b/docus/src/plugin/source.ts @@ -42,6 +42,25 @@ const SchemaBase = z.object({ examples: z.array(z.unknown()).optional(), required: z.array(z.string()).optional(), + enum: z.array( + z.union([ + z.intersection( + z.object({ + description: z.string(), + }), + z.union([ + z.object({ + value: z.unknown(), + name: z.string(), + }), + z.object({ + value: z.string(), + }), + ]) + ), + z.union([z.string(), z.number()]) + ]), + ).optional() // #[serde(flatten)] // pub(crate) object_schema: Option, @@ -60,34 +79,12 @@ type Schema = z.infer & { properties?: Record; items?: Schema; oneOf?: { schema: Schema; name?: string }[]; - enum?: ({ value: unknown; name: string } | { value: string } | string | number)[]; }; const Schema: z.ZodType = SchemaBase.extend({ properties: z.lazy(() => z.record(Schema)).optional(), items: z.lazy(() => Schema).optional(), oneOf: z.lazy(() => z.array(Schema.extend({ name: z.string().optional() })).optional()), - enum: z.lazy(() => - z.array( - z.union([ - z.intersection( - z.object({ - description: z.string(), - }), - z.union([ - z.object({ - value: z.unknown(), - name: z.string(), - }), - z.object({ - value: z.string(), - }), - ]) - ), - z.union([z.string(), z.number()]) - ]), - ).optional() - ) }); const RootSchema = Schema.extend({ diff --git a/xtask/src/cli/codegen.rs b/xtask/src/cli/codegen.rs deleted file mode 100644 index cca2b5c7..00000000 --- a/xtask/src/cli/codegen.rs +++ /dev/null @@ -1,24 +0,0 @@ -mod source; -mod json_schema; -mod md_doc; - -use std::fs; - -/// Update generated code that is checked in to source control. -#[derive(clap::Args, Debug)] -pub(crate) struct CodegenCommand {} - -impl CodegenCommand { - pub(crate) fn run(self) -> anyhow::Result<()> { - // Maybe we'll need CLI params here in the future - let Self {} = self; - - let input = fs::read_to_string("deny.schema.yml")?; - let input: source::RootSchema = serde_yaml::from_str(&input)?; - - md_doc::gen(&input)?; - json_schema::gen(&input)?; - - Ok(()) - } -} diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs deleted file mode 100644 index 86c4a19c..00000000 --- a/xtask/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod cli; -mod entrypoint; - -pub use entrypoint::run; From 77d08b7f631faea5afc5c2756e772fe4641a5722 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 2 May 2024 01:53:18 +0000 Subject: [PATCH 16/20] Add simplificiation logic --- dashie/src/cli.rs | 3 + dashie/src/cli/codegen/json_schema.rs | 9 +- dashie/src/cli/codegen/mod.rs | 4 +- .../src/cli/mdbook/preprocessor/preprocess.rs | 4 +- dashie/src/entrypoint.rs | 24 +- dashie/src/error.rs | 11 + dashie/src/lib.rs | 8 +- dashie/src/md_doc/hir/doc.rs | 298 ------------- dashie/src/md_doc/hir/mod.rs | 417 ++++++++++-------- dashie/src/md_doc/hir/node.rs | 203 +++++++++ dashie/src/md_doc/hir/simplifying.rs | 97 ++++ dashie/src/serdex/json.rs | 32 ++ dashie/src/serdex/mod.rs | 1 + dashie/src/{dashie_schema.rs => source.rs} | 76 +++- deny16.schema.json | 326 -------------- deny38.schema.json | 326 -------------- 16 files changed, 671 insertions(+), 1168 deletions(-) create mode 100644 dashie/src/error.rs delete mode 100644 dashie/src/md_doc/hir/doc.rs create mode 100644 dashie/src/md_doc/hir/node.rs create mode 100644 dashie/src/md_doc/hir/simplifying.rs create mode 100644 dashie/src/serdex/json.rs create mode 100644 dashie/src/serdex/mod.rs rename dashie/src/{dashie_schema.rs => source.rs} (85%) delete mode 100644 deny16.schema.json delete mode 100644 deny38.schema.json diff --git a/dashie/src/cli.rs b/dashie/src/cli.rs index 3094fbb2..8ceb6776 100644 --- a/dashie/src/cli.rs +++ b/dashie/src/cli.rs @@ -21,6 +21,9 @@ enum Command { pub(crate) fn run() -> Result { let cli = Cli::parse(); + + debug!(cli = format_args!("{cli:#?}"), "Invoked with CLI params"); + match cli.command { Command::Codegen(cmd) => cmd.run(), Command::Mdbook(cmd) => cmd.run(), diff --git a/dashie/src/cli/codegen/json_schema.rs b/dashie/src/cli/codegen/json_schema.rs index b0664aa3..cc983771 100644 --- a/dashie/src/cli/codegen/json_schema.rs +++ b/dashie/src/cli/codegen/json_schema.rs @@ -1,12 +1,13 @@ -use crate::dashie_schema::{EnumVariantSchema, RootSchema, Schema}; +use crate::source::{EnumVariantSchema, RootSchema, Schema}; use crate::prelude::*; +use crate::serdex; /// Generate the JSON schema based on the input YML schema. pub(crate) fn gen(root: &RootSchema) -> Result { let ctx = GenContext::new(root); let root = ctx.gen()?; - let output = serde_json::to_string_pretty(&root)?; + let output = serdex::json::to_string_pretty(&root); std::fs::write("deny.schema.json", output)?; @@ -37,14 +38,14 @@ impl<'a> GenContext<'a> { Ok(RootSchema { definitions, schema, - other: self.root.other.clone(), + misc: self.root.misc.clone(), }) } fn gen_schema(&self, schema: &Schema) -> Result { let mut schema = schema.clone(); - schema.traverse_mut(|schema| self.normalize_enum(schema))?; + schema.traverse_mut(&mut |schema| self.normalize_enum(schema))?; Ok(schema) } diff --git a/dashie/src/cli/codegen/mod.rs b/dashie/src/cli/codegen/mod.rs index 49000433..f3ede47a 100644 --- a/dashie/src/cli/codegen/mod.rs +++ b/dashie/src/cli/codegen/mod.rs @@ -1,6 +1,6 @@ mod json_schema; -use crate::dashie_schema; +use crate::source; use crate::prelude::*; use camino::Utf8PathBuf; @@ -13,7 +13,7 @@ pub(crate) struct CodegenCommand { impl CodegenCommand { pub(crate) fn run(self) -> Result { - let dashie_schema = dashie_schema::RootSchema::from_file(self.dashie_schema)?; + let dashie_schema = source::RootSchema::from_file(self.dashie_schema)?; json_schema::gen(&dashie_schema)?; diff --git a/dashie/src/cli/mdbook/preprocessor/preprocess.rs b/dashie/src/cli/mdbook/preprocessor/preprocess.rs index 9f43d8b6..93006f77 100644 --- a/dashie/src/cli/mdbook/preprocessor/preprocess.rs +++ b/dashie/src/cli/mdbook/preprocessor/preprocess.rs @@ -1,6 +1,6 @@ use crate::md_doc::mir; use crate::prelude::*; -use crate::{dashie_schema, md_doc}; +use crate::{source, md_doc}; use camino::Utf8PathBuf; use mdbook::book::{self, Book}; use mdbook::preprocess::PreprocessorContext; @@ -51,7 +51,7 @@ impl Context { .transpose()? .unwrap_or_else(|| "dashie.schema.yml".into()); - let schema = dashie_schema::RootSchema::from_file(schema_path)?; + let schema = source::RootSchema::from_file(schema_path)?; let doc = md_doc::hir::Dom::builder().schema(schema).build()?.lower(); diff --git a/dashie/src/entrypoint.rs b/dashie/src/entrypoint.rs index f8790037..087df064 100644 --- a/dashie/src/entrypoint.rs +++ b/dashie/src/entrypoint.rs @@ -1,21 +1,31 @@ use crate::prelude::*; use std::process::ExitCode; +use tracing::level_filters::LevelFilter; use tracing_subscriber::prelude::*; pub fn run() -> ExitCode { - let Err(err) = try_run() else { - return ExitCode::SUCCESS; - }; - - eprintln!("Exiting with error: {err:?}"); - ExitCode::FAILURE + match std::panic::catch_unwind(try_run) { + Ok(Ok(())) => ExitCode::SUCCESS, + Ok(Err(err)) => { + error!("Exiting with error: {err:?}"); + ExitCode::FAILURE + } + Err(_) => { + error!("Exiting with error due to a panic"); + ExitCode::FAILURE + } + } } fn try_run() -> Result { - let env_filter = tracing_subscriber::EnvFilter::from_env("XTASK_LOG"); + let env_filter = tracing_subscriber::EnvFilter::builder() + .with_env_var("DASHIE_LOG") + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(); let fmt = tracing_subscriber::fmt::layer() .with_target(true) + .with_writer(std::io::stderr) .with_ansi(std::env::var("COLORS").as_deref() != Ok("0")) .pretty(); diff --git a/dashie/src/error.rs b/dashie/src/error.rs new file mode 100644 index 00000000..4d62a001 --- /dev/null +++ b/dashie/src/error.rs @@ -0,0 +1,11 @@ +use crate::prelude::*; + +pub(crate) fn fail_or_warn(ignore_error: bool, err: Error) -> Result { + if !ignore_error { + return Err(err) + } + + warn!("{err:?}"); + + Ok(()) +} diff --git a/dashie/src/lib.rs b/dashie/src/lib.rs index 395bed15..d895b02d 100644 --- a/dashie/src/lib.rs +++ b/dashie/src/lib.rs @@ -1,14 +1,16 @@ mod cli; -mod dashie_schema; +mod source; mod entrypoint; mod md_doc; +mod error; +mod serdex; pub use entrypoint::run; mod prelude { - pub(crate) use anyhow::{bail, Context as _}; + pub(crate) use anyhow::{bail, ensure, Context as _, Error, format_err}; pub(crate) use itertools::Itertools as _; - pub(crate) use tracing::{info, warn}; + pub(crate) use tracing::{info, debug, warn, error}; pub(crate) type Result = std::result::Result; } diff --git a/dashie/src/md_doc/hir/doc.rs b/dashie/src/md_doc/hir/doc.rs deleted file mode 100644 index c9dc8023..00000000 --- a/dashie/src/md_doc/hir/doc.rs +++ /dev/null @@ -1,298 +0,0 @@ -use super::*; -use crate::dashie_schema::{ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; -use crate::prelude::*; -use buildstructor::buildstructor; -use std::collections::BTreeMap; - -pub(crate) struct Dom { - pub(crate) root: SchemaNode, - pub(crate) type_index: BTreeMap, -} - -#[buildstructor] -impl Dom { - #[builder] - pub(crate) fn new(schema: RootSchema, max_nesting_in_file: Option) -> Result { - let ctx = Context { - root: schema, - max_nesting_in_file: max_nesting_in_file.unwrap_or(2), - }; - - let doc = ctx.generate()?; - - Ok(doc) - } - - // pub(crate) fn new(ctx: DocContext) -> Result { - // let all_schemas = || { - // let schemas_in_root = root.schema.entries(); - // let schemas_in_defs = root.definitions.values().flat_map(Schema::entries); - // itertools::chain(schemas_in_root, schemas_in_defs) - // }; - - // let definition_ref_counts = all_schemas() - // .map(|entry| entry.schema.referenced_definition()) - // .flatten_ok() - // .process_results(|iter| iter.counts())?; - - // let unused_defs: Vec<_> = root - // .definitions - // .iter() - // .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) - // .collect(); - - // anyhow::ensure!( - // unused_defs.is_empty(), - // "Found unused definitions: {unused_defs:#?}", - // ); - - // let repeated_references: BTreeMap<_, _> = definition_ref_counts - // .into_iter() - // // For schemas that are repeatedly referenced, we want to include them in the - // // "Type Index". This is separate page where common types are defined such - // // that we don't duplicate their docs all over the place. - // .filter(|(_, count)| *count > 1) - // .map(|(def_name, _)| { - // let schema = root.find_definition(def_name)?; - // anyhow::Ok((def_name.to_owned(), schema)) - // }) - // .try_collect()?; - - // let flattened = all_schemas() - // .filter(|entry| entry.level % max_level == 0) - // .map(|entry| { - // let schema = entry.schema; - // }) - // .collect(); - - // doc.flatten(max_level)?; - - // Ok(doc) - // } - - // fn flatten(&mut self, max_level: usize) -> Result<()> { - // FlattenDoc { - // ty_index: &mut self.type_index, - // max_level, - // } - // .flatten(&mut self.root, 0) - // } -} - -// struct FlattenDoc<'a> { -// ty_index: &'a mut BTreeMap, -// max_level: usize, -// } - -// impl FlattenDoc<'_> { -// fn flatten(&mut self, node: &mut TypeDocNode, level: usize) -> Result<()> { -// for child in &mut node.children { -// if level <= self.max_level { -// Self { -// ty_index: self.ty_index, -// max_level: self.max_level, -// } -// } - -// self.flatten(child, level + 1)?; -// } - -// if level <= self.max_level { -// return Ok(()); -// } - -// node.children.clear(); - -// let type_doc = &node.inner; - -// let definition = type_doc -// .key -// .definition() -// .with_context(|| { -// format!( -// "Can't flatten node at level {level}, because the name to \ -// assign to it in the type index can not be inferred.\n\ -// Schema key: {}\n\ -// Try moving the schema to a definition, and the definition key \ -// will be used as a name for this type in the type index", -// type_doc.key -// ) -// })? -// .to_owned(); - -// let type_index_entry = self.ty_index.get(&definition).unwrap_or_else(|| { -// panic!("We inlined this type before, so it must be in type index: {definition}") -// }); - -// let type_index_ref = TypeIndexRef { -// definition: definition.clone(), -// ty: type_index_entry.inner.ty.clone(), -// }; - -// let new_type_doc = TypeDoc { -// key: type_doc.key.clone(), -// title: None, -// description: None, -// default: None, -// examples: vec![], -// ty: type_doc.ty.clone(), -// type_index_ref: Some(type_index_ref), -// }; - -// let node = std::mem::replace(node, TypeDocNode::leaf(new_type_doc)); - -// self.ty_index.insert(definition, node); - -// Ok(()) -// } -// } - -struct Context { - root: RootSchema, - max_nesting_in_file: u8, -} - -impl Context { - fn generate(self) -> Result { - let root = PathedSourceSchema::origin(PathOrigin::Root, self.root.schema.clone()); - let root = self.schema_node(root)?; - - let definitions = self - .root - .definitions - .iter() - .map(|(def_name, schema)| { - let origin = PathOrigin::Definition(def_name.clone()); - let schema = PathedSourceSchema::origin(origin, schema.clone()); - - Ok((def_name.clone(), self.schema_node(schema)?)) - }) - .collect::>()?; - - Ok(Dom { - root, - type_index: definitions, - }) - } - - fn schema_node(&self, schema: PathedSourceSchema) -> Result { - // if let Some(reference) = schema.inner.reference.clone() { - // self.schema_node_ref(schema, reference) - // } else { - // self.schema_node_non_ref(schema) - // } - // } - - // fn schema_node_ref(&self, schema: PathedSourceSchema, reference: String) -> Result { - // let doc = SchemaDoc::Ref(reference); - // let path = schema.path; - - // let inline = self - // .options - // .root - // .inline_referenced_definition(&schema.inner)?; - - // let ty = Type::from_source_schema(&inline); - - // let schema = Schema { path, ty, doc }; - - // Ok(SchemaNode::leaf(schema)) - // } - - // fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { - let path = schema.path; - - let ty = Type::from_source_schema(&self.root.inline_referenced_definition(&schema.inner)?); - - let schema = schema.inner; - - let children = if let Some(array) = schema.array_schema { - Self::array_children(&path, array)? - } else if let Some(object) = schema.object_schema { - Self::object_children(&path, object)? - } else if let Some(variants) = schema.one_of { - Self::one_of_children(&path, variants)? - } else { - vec![] - }; - - let children = children - .into_iter() - .map(|child| self.schema_node(child)) - .try_collect()?; - - let data = SchemaDocData { - title: schema.title, - description: schema.description, - default: schema.default, - examples: schema.examples, - }; - - let doc = if let Some(reference) = schema.reference.clone() { - SchemaDoc::Ref(SchemaDocRef { reference, data }) - } else if path.segments.len() % (usize::from(self.max_nesting_in_file) + 1) == 0 { - SchemaDoc::Nested(data) - } else { - SchemaDoc::Embedded(data) - }; - - let schema = Schema { path, ty, doc }; - - Ok(SchemaNode { schema, children }) - } - - fn array_children(path: &Path, array: ArraySchema) -> Result> { - let path = path.add_segment(PathSegment::Index); - let items = PathedSourceSchema::new(path, *array.items); - Ok(vec![items]) - } - - fn object_children(path: &Path, object: ObjectSchema) -> Result> { - let properties = object - .properties - .into_iter() - .map(|(name, value)| { - let field = Field { - name: name.clone(), - required: object.required.contains(&name), - }; - let path = path.add_segment(PathSegment::Field(field)); - PathedSourceSchema::new(path, value) - }) - .collect(); - - Ok(properties) - } - - fn one_of_children( - path: &Path, - variants: Vec, - ) -> Result> { - let names: Vec<_> = variants - .clone() - .into_iter() - .map(|variant| variant.name().map(ToOwned::to_owned)) - .try_collect()?; - - let duplicates: Vec<_> = names.iter().duplicates().collect(); - - anyhow::ensure!( - duplicates.is_empty(), - "Duplicate variant names found in one_of schema.\n\ - Duplicates: {duplicates:?}\n\ - Variants: {variants:#?}", - ); - - let variants = variants - .into_iter() - .zip(names) - .map(|(variant, name)| { - let path = path.add_segment(PathSegment::Variant(name)); - - PathedSourceSchema::new(path, variant.schema) - }) - .collect(); - - Ok(variants) - } -} diff --git a/dashie/src/md_doc/hir/mod.rs b/dashie/src/md_doc/hir/mod.rs index e01e3b16..786fd359 100644 --- a/dashie/src/md_doc/hir/mod.rs +++ b/dashie/src/md_doc/hir/mod.rs @@ -1,207 +1,264 @@ -mod doc; +mod node; -pub(crate) use doc::*; +pub(crate) use node::*; + +mod simplifying; -use crate::dashie_schema; use crate::prelude::*; -use serde_json::Value; -use std::fmt; +use crate::source::{ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; +use buildstructor::buildstructor; +use std::collections::BTreeMap; -#[derive(Debug)] -pub(crate) struct SchemaNode { - pub(crate) schema: Schema, - pub(crate) children: Vec, +pub(crate) struct Dom { + pub(crate) root: SchemaNode, + pub(crate) type_index: BTreeMap, } -impl SchemaNode { - pub(crate) fn leaf(schema: Schema) -> Self { - Self { - schema, - children: vec![], - } +#[buildstructor] +impl Dom { + #[builder] + pub(crate) fn new( + schema: RootSchema, + max_nesting_in_file: Option, + allow_unused_definitions: Option, + ) -> Result { + let ctx = LoweringContext { + root: schema, + max_nesting_in_file: max_nesting_in_file.unwrap_or(2), + allow_unused_definitions: allow_unused_definitions.unwrap_or(false), + }; + + let doc = ctx.lower()?; + + Ok(doc) } -} - -#[derive(Debug)] -pub(crate) struct Schema { - pub(crate) path: Path, - pub(crate) ty: Type, - pub(crate) doc: SchemaDoc, -} - -#[derive(Debug)] -pub(crate) enum SchemaDoc { - /// Documentation should be embedded in the same file. The value is [`None`] - Embedded(SchemaDocData), - /// Schema should live as a nested document - Nested(SchemaDocData), - - /// This schema is a reference to some other schema. It may be either a reference - /// to a definition within the same schema or a reference to some external schema. - Ref(SchemaDocRef), + // fn flatten(&mut self, max_level: usize) -> Result<()> { + // FlattenDoc { + // ty_index: &mut self.type_index, + // max_level, + // } + // .flatten(&mut self.root, 0) + // } } -impl SchemaDoc { - pub(crate) fn reference(&self) -> Option<&str> { - match self { - SchemaDoc::Ref(reference) => Some(&reference.reference), - _ => None, - } - } +// struct FlattenDoc<'a> { +// ty_index: &'a mut BTreeMap, +// max_level: usize, +// } + +// impl FlattenDoc<'_> { +// fn flatten(&mut self, node: &mut TypeDocNode, level: usize) -> Result<()> { +// for child in &mut node.children { +// if level <= self.max_level { +// Self { +// ty_index: self.ty_index, +// max_level: self.max_level, +// } +// } + +// self.flatten(child, level + 1)?; +// } + +// if level <= self.max_level { +// return Ok(()); +// } + +// node.children.clear(); + +// let type_doc = &node.inner; + +// let definition = type_doc +// .key +// .definition() +// .with_context(|| { +// format!( +// "Can't flatten node at level {level}, because the name to \ +// assign to it in the type index can not be inferred.\n\ +// Schema key: {}\n\ +// Try moving the schema to a definition, and the definition key \ +// will be used as a name for this type in the type index", +// type_doc.key +// ) +// })? +// .to_owned(); + +// let type_index_entry = self.ty_index.get(&definition).unwrap_or_else(|| { +// panic!("We inlined this type before, so it must be in type index: {definition}") +// }); + +// let type_index_ref = TypeIndexRef { +// definition: definition.clone(), +// ty: type_index_entry.inner.ty.clone(), +// }; + +// let new_type_doc = TypeDoc { +// key: type_doc.key.clone(), +// title: None, +// description: None, +// default: None, +// examples: vec![], +// ty: type_doc.ty.clone(), +// type_index_ref: Some(type_index_ref), +// }; + +// let node = std::mem::replace(node, TypeDocNode::leaf(new_type_doc)); + +// self.ty_index.insert(definition, node); + +// Ok(()) +// } +// } + +struct LoweringContext { + root: RootSchema, + max_nesting_in_file: u8, + allow_unused_definitions: bool, } -#[derive(Debug)] -pub(crate) struct SchemaDocRef { - pub(crate) reference: String, +impl LoweringContext { + fn lower(mut self) -> Result { + self.simplify()?; - /// Additional data that may override the details of the referenced schema. - pub(crate) data: SchemaDocData, -} + let root = PathedSourceSchema::origin(PathOrigin::Root, self.root.schema.clone()); + let root = self.schema_node(root)?; -#[derive(Debug)] -pub(crate) struct SchemaDocData { - pub(crate) title: Option, - pub(crate) description: Option, - pub(crate) default: Option, - pub(crate) examples: Vec, -} + let definitions = self + .root + .definitions + .iter() + .map(|(def_name, schema)| { + let origin = PathOrigin::Definition(def_name.clone()); + let schema = PathedSourceSchema::origin(origin, schema.clone()); -#[derive(Clone, Debug)] -pub(crate) struct Path { - pub(crate) origin: PathOrigin, - pub(crate) segments: Vec, -} + Ok((def_name.clone(), self.schema_node(schema)?)) + }) + .collect::>()?; -impl Path { - pub(crate) fn new(origin: PathOrigin) -> Self { - Self { - origin, - segments: vec![], - } - } - - #[must_use] - pub(crate) fn add_segment(&self, new_segment: PathSegment) -> Self { - let mut segments = self.segments.clone(); - segments.push(new_segment); - Self { - origin: self.origin.clone(), - segments, - } - } -} - -impl fmt::Display for Path { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut segments = self.segments.iter(); - - if let Some(segment) = segments.next() { - if let PathSegment::Variant(_) = segment { - write!(f, "As {segment}")?; - } else { - write!(f, "{segment}")?; - } - } - - segments.try_for_each(|segment| match &segment { - PathSegment::Field(_) => write!(f, ".{segment}"), - PathSegment::Index => write!(f, "{segment}"), - PathSegment::Variant(_) => write!(f, "as {segment}"), + Ok(Dom { + root, + type_index: definitions, }) } -} - -#[derive(Clone, Debug)] -pub(crate) enum PathOrigin { - Root, - Definition(String), -} - -impl fmt::Display for PathSegment { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self { - PathSegment::Field(field) => f.write_str(&field.name), - // . - // [..] - PathSegment::Index => f.write_str("[N]"), - PathSegment::Variant(name) => write!(f, "{name}"), - } - } -} - -#[derive(Clone, Debug)] -pub(crate) enum PathSegment { - Field(Field), - Index, - Variant(String), -} - -#[derive(Clone, Debug)] -pub(crate) struct Field { - pub(crate) name: String, - pub(crate) required: bool, -} - -#[derive(Debug, Clone)] -pub(crate) struct LeafType { - pub(crate) ty: Option, - pub(crate) format: Option, - pub(crate) enum_schema: Option>, -} -impl LeafType { - fn from_dashie_schema(schema: &dashie_schema::Schema) -> Self { - Self { - ty: schema.ty.clone(), - format: schema.format.clone(), - enum_schema: schema.enum_schema.clone(), - } + fn schema_node(&self, schema: PathedSourceSchema) -> Result { + // if let Some(reference) = schema.inner.reference.clone() { + // self.schema_node_ref(schema, reference) + // } else { + // self.schema_node_non_ref(schema) + // } + // } + + // fn schema_node_ref(&self, schema: PathedSourceSchema, reference: String) -> Result { + // let doc = SchemaDoc::Ref(reference); + // let path = schema.path; + + // let inline = self + // .options + // .root + // .inline_referenced_definition(&schema.inner)?; + + // let ty = Type::from_source_schema(&inline); + + // let schema = Schema { path, ty, doc }; + + // Ok(SchemaNode::leaf(schema)) + // } + + // fn schema_node_non_ref(&self, schema: PathedSourceSchema) -> Result { + let path = schema.path; + + let ty = Type::from_source_schema(&self.root.inline_referenced_definition(&schema.inner)?); + + let schema = schema.inner; + + let children = if let Some(array) = schema.array_schema { + Self::array_children(&path, array)? + } else if let Some(object) = schema.object_schema { + Self::object_children(&path, object)? + } else if let Some(variants) = schema.one_of { + Self::one_of_children(&path, variants)? + } else { + vec![] + }; + + let children = children + .into_iter() + .map(|child| self.schema_node(child)) + .try_collect()?; + + let data = SchemaDocData { + title: schema.title, + description: schema.description, + default: schema.default, + examples: schema.examples, + }; + + let doc = if let Some(reference) = schema.reference.clone() { + SchemaDoc::Ref(SchemaDocRef { reference, data }) + } else if path.segments.len() % (usize::from(self.max_nesting_in_file) + 1) == 0 { + SchemaDoc::Nested(data) + } else { + SchemaDoc::Embedded(data) + }; + + let schema = Schema { path, ty, doc }; + + Ok(SchemaNode { schema, children }) } -} - -#[derive(Debug, Clone)] -pub(crate) struct Type { - pub(crate) inner: LeafType, - - /// [`LeafType`] exists to make sure we don't have recursion in this field. - /// We describe at max two levels of nesting in type tags. - pub(crate) array_items_ty: Option, -} - -impl Type { - pub(crate) fn from_source_schema(schema: &dashie_schema::Schema) -> Self { - let inner = LeafType::from_dashie_schema(schema); - - let array_items_ty = schema - .array_schema - .as_ref() - .map(|array| LeafType::from_dashie_schema(&array.items)); - - Self { - inner, - array_items_ty, - } - } -} - -#[derive(Clone, Debug)] -pub(crate) struct PathedSourceSchema { - pub(crate) path: Path, - pub(crate) inner: dashie_schema::Schema, -} -impl PathedSourceSchema { - pub(crate) fn new(path: Path, inner: dashie_schema::Schema) -> Self { - Self { path, inner } + fn array_children(path: &Path, array: ArraySchema) -> Result> { + let path = path.add_segment(PathSegment::Index); + let items = PathedSourceSchema::new(path, *array.items); + Ok(vec![items]) } - pub(crate) fn origin(origin: PathOrigin, inner: dashie_schema::Schema) -> Self { - Self::new(Path::new(origin), inner) + fn object_children(path: &Path, object: ObjectSchema) -> Result> { + let properties = object + .properties + .into_iter() + .map(|(name, value)| { + let field = Field { + name: name.clone(), + required: object.required.contains(&name), + }; + let path = path.add_segment(PathSegment::Field(field)); + PathedSourceSchema::new(path, value) + }) + .collect(); + + Ok(properties) } - fn inline_referenced_definition(mut self, root: &dashie_schema::RootSchema) -> Result { - self.inner = root.inline_referenced_definition(&self.inner)?; - Ok(self) + fn one_of_children( + path: &Path, + variants: Vec, + ) -> Result> { + let names: Vec<_> = variants + .clone() + .into_iter() + .map(|variant| variant.name().map(ToOwned::to_owned)) + .try_collect()?; + + let duplicates: Vec<_> = names.iter().duplicates().collect(); + + anyhow::ensure!( + duplicates.is_empty(), + "Duplicate variant names found in one_of schema.\n\ + Duplicates: {duplicates:?}\n\ + Variants: {variants:#?}", + ); + + let variants = variants + .into_iter() + .zip(names) + .map(|(variant, name)| { + let path = path.add_segment(PathSegment::Variant(name)); + + PathedSourceSchema::new(path, variant.schema) + }) + .collect(); + + Ok(variants) } } diff --git a/dashie/src/md_doc/hir/node.rs b/dashie/src/md_doc/hir/node.rs new file mode 100644 index 00000000..096b1deb --- /dev/null +++ b/dashie/src/md_doc/hir/node.rs @@ -0,0 +1,203 @@ +use crate::source; +use crate::prelude::*; +use serde_json::Value; +use std::fmt; + +#[derive(Debug)] +pub(crate) struct SchemaNode { + pub(crate) schema: Schema, + pub(crate) children: Vec, +} + +impl SchemaNode { + pub(crate) fn leaf(schema: Schema) -> Self { + Self { + schema, + children: vec![], + } + } +} + +#[derive(Debug)] +pub(crate) struct Schema { + pub(crate) path: Path, + pub(crate) ty: Type, + pub(crate) doc: SchemaDoc, +} + +#[derive(Debug)] +pub(crate) enum SchemaDoc { + /// Documentation should be embedded in the same file. The value is [`None`] + Embedded(SchemaDocData), + + /// Schema should live as a nested document + Nested(SchemaDocData), + + /// This schema is a reference to some other schema. It may be either a reference + /// to a definition within the same schema or a reference to some external schema. + Ref(SchemaDocRef), +} + +impl SchemaDoc { + pub(crate) fn reference(&self) -> Option<&str> { + match self { + SchemaDoc::Ref(reference) => Some(&reference.reference), + _ => None, + } + } +} + +#[derive(Debug)] +pub(crate) struct SchemaDocRef { + pub(crate) reference: String, + + /// Additional data that may override the details of the referenced schema. + pub(crate) data: SchemaDocData, +} + +#[derive(Debug)] +pub(crate) struct SchemaDocData { + pub(crate) title: Option, + pub(crate) description: Option, + pub(crate) default: Option, + pub(crate) examples: Vec, +} + +#[derive(Clone, Debug)] +pub(crate) struct Path { + pub(crate) origin: PathOrigin, + pub(crate) segments: Vec, +} + +impl Path { + pub(crate) fn new(origin: PathOrigin) -> Self { + Self { + origin, + segments: vec![], + } + } + + #[must_use] + pub(crate) fn add_segment(&self, new_segment: PathSegment) -> Self { + let mut segments = self.segments.clone(); + segments.push(new_segment); + Self { + origin: self.origin.clone(), + segments, + } + } +} + +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut segments = self.segments.iter(); + + if let Some(first_segment) = segments.next() { + if let PathSegment::Variant(_) = first_segment { + write!(f, "As {first_segment}")?; + } else { + write!(f, "{first_segment}")?; + } + } + + segments.try_for_each(|segment| match &segment { + PathSegment::Field(_) => write!(f, ".{segment}"), + PathSegment::Index => write!(f, "{segment}"), + PathSegment::Variant(_) => write!(f, "as {segment}"), + }) + } +} + +#[derive(Clone, Debug)] +pub(crate) enum PathOrigin { + Root, + Definition(String), +} + +impl fmt::Display for PathSegment { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + PathSegment::Field(field) => f.write_str(&field.name), + // . + // [..] + PathSegment::Index => f.write_str("[N]"), + PathSegment::Variant(name) => write!(f, "{name}"), + } + } +} + +#[derive(Clone, Debug)] +pub(crate) enum PathSegment { + Field(Field), + Index, + Variant(String), +} + +#[derive(Clone, Debug)] +pub(crate) struct Field { + pub(crate) name: String, + pub(crate) required: bool, +} + +#[derive(Debug, Clone)] +pub(crate) struct LeafType { + pub(crate) ty: Option, + pub(crate) format: Option, + pub(crate) enum_schema: Option>, +} + +impl LeafType { + fn from_dashie_schema(schema: &source::Schema) -> Self { + Self { + ty: schema.ty.clone(), + format: schema.format.clone(), + enum_schema: schema.enum_schema.clone(), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct Type { + pub(crate) inner: LeafType, + + /// [`LeafType`] exists to make sure we don't have recursion in this field. + /// We describe at max two levels of nesting in type tags. + pub(crate) array_items_ty: Option, +} + +impl Type { + pub(crate) fn from_source_schema(schema: &source::Schema) -> Self { + let inner = LeafType::from_dashie_schema(schema); + + let array_items_ty = schema + .array_schema + .as_ref() + .map(|array| LeafType::from_dashie_schema(&array.items)); + + Self { + inner, + array_items_ty, + } + } +} + +#[derive(Clone, Debug)] +pub(crate) struct PathedSourceSchema { + pub(crate) path: Path, + pub(crate) inner: source::Schema, +} + +impl PathedSourceSchema { + pub(crate) fn new(path: Path, inner: source::Schema) -> Self { + Self { path, inner } + } + + pub(crate) fn origin(origin: PathOrigin, inner: source::Schema) -> Self { + Self::new(Path::new(origin), inner) + } + + fn inline_referenced_definition(mut self, root: &source::RootSchema) -> Result { + self.inner = root.inline_referenced_definition(&self.inner)?; + Ok(self) + } +} diff --git a/dashie/src/md_doc/hir/simplifying.rs b/dashie/src/md_doc/hir/simplifying.rs new file mode 100644 index 00000000..c0a33316 --- /dev/null +++ b/dashie/src/md_doc/hir/simplifying.rs @@ -0,0 +1,97 @@ +use super::LoweringContext; +use crate::prelude::*; +use crate::source; +use std::collections::{BTreeMap, BTreeSet}; +use std::ops::ControlFlow; + +impl LoweringContext { + pub(crate) fn simplify(&mut self) -> Result> { + let all_schemas = || { + let schemas_in_root = self.root.schema.entries(); + let schemas_in_defs = self + .root + .definitions + .values() + .flat_map(source::Schema::entries); + itertools::chain(schemas_in_root, schemas_in_defs) + }; + + let definition_ref_counts = all_schemas() + .filter_map(|entry| entry.schema.referenced_definition()) + .counts(); + + let unused_defs: Vec<_> = self + .root + .definitions + .iter() + .filter(|(def_name, _)| !definition_ref_counts.contains_key(def_name.as_str())) + .collect(); + + if !unused_defs.is_empty() { + crate::error::fail_or_warn( + self.allow_unused_definitions, + format_err!("Found unused definitions: {unused_defs:#?}"), + )?; + } + + let single_references: BTreeMap<_, _> = definition_ref_counts + .into_iter() + // For schemas that are referenced only once, we want to inline them + // directly in the containing schema object instead. This is done to + // reduce the "Type Index" and make it clear that the definition is + // only used in one place, where it is defined inline. + .filter(|(_, count)| *count == 1) + .map(|(def_name, _)| def_name.to_owned()) + .collect::>() + .into_iter() + .map(|definition_name| { + let definition = self.root.remove_definition(&definition_name)?; + Ok::<_, Error>((definition_name, definition)) + }) + .try_collect()?; + + if single_references.is_empty() { + // nothing to simplify anymore + return Ok(ControlFlow::Break(())); + } + + let mut ctx = SimplificationContext { single_references }; + + ctx.simplify(self)?; + + Ok(ControlFlow::Continue(())) + } +} + +struct SimplificationContext { + single_references: BTreeMap, +} + +impl SimplificationContext { + fn simplify(&mut self, lowering: &mut LoweringContext) -> Result { + // We simplify in a loop because inlining a definition may introduce new + // opportunities for further simplification. It is a fixed-point iteration + // where we keep simplifying until eventually no more simplifications can + // be made. + while !self.single_references.is_empty() { + lowering.root.traverse_mut(&mut |schema| { + self.inline_single_reference(schema); + Ok(()) + })?; + dbg!(&self.single_references.keys().collect_vec()); + } + + Ok(()) + } + + fn inline_single_reference(&mut self, schema: &mut source::Schema) { + let Some(definition) = schema.referenced_definition() else { + return; + }; + let Some(definition) = self.single_references.remove(definition) else { + return; + }; + + schema.inline_reference(&definition); + } +} diff --git a/dashie/src/serdex/json.rs b/dashie/src/serdex/json.rs new file mode 100644 index 00000000..ad804ae0 --- /dev/null +++ b/dashie/src/serdex/json.rs @@ -0,0 +1,32 @@ +use serde::Serialize; + +/// Shortcut for [`serde_json::to_string_pretty`] that unwraps the result, asserting +/// that it is serializable to JSON. +/// +/// # Panics +/// +/// Panics if [`serde_json::to_string_pretty`] returns an error. +/// It is fine for this function to panic, because the former function returns an error +/// due to a type-level mistake caused by a developer like serializing a map with non-string key to JSON. +/// Hopefully, the panic message should be clear enough for the developer to catch this problem. +#[track_caller] +pub(crate) fn to_string_pretty(value: T) -> String { + serialize_imp(&value, serde_json::to_string_pretty) +} + +#[track_caller] +fn serialize_imp(value: T, ser: fn(T) -> serde_json::Result) -> D +where + T: Serialize, +{ + // Not using `map_err` to make `track_caller` work. + match ser(value) { + Ok(ok) => ok, + Err(err) => panic!( + "failed to serialize `{}` to JSON `{}`: {:?}", + std::any::type_name::(), + std::any::type_name::(), + anyhow::Error::from(err) + ), + } +} diff --git a/dashie/src/serdex/mod.rs b/dashie/src/serdex/mod.rs new file mode 100644 index 00000000..1ebac8d4 --- /dev/null +++ b/dashie/src/serdex/mod.rs @@ -0,0 +1 @@ +pub(crate) mod json; diff --git a/dashie/src/dashie_schema.rs b/dashie/src/source.rs similarity index 85% rename from dashie/src/dashie_schema.rs rename to dashie/src/source.rs index 38bee3b7..45a2016b 100644 --- a/dashie/src/dashie_schema.rs +++ b/dashie/src/source.rs @@ -1,4 +1,5 @@ -use anyhow::{Context, Result}; +use crate::prelude::*; +use crate::serdex; use camino::Utf8Path; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; @@ -14,10 +15,22 @@ pub(crate) struct RootSchema { pub(crate) definitions: BTreeMap, - // Keep the rest of the fields in the schema so they are not lost during - // the deserialize -> serialize roundtrip. + /// Keep the rest of the fields in the schema so they are not lost during + /// the deserialize -> serialize roundtrip. + /// Unfortunatelly, we can't use `#[serde(flatten)]` with BTreeMap + /// here because it contains a copy of fields from the flattened `schema` due + /// a bug in serde. Probably: #[serde(flatten)] - pub(crate) other: Object, + pub(crate) misc: MiscRootSchemaProperties, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub(crate) struct MiscRootSchemaProperties { + #[serde(rename = "$id")] + id: String, + + #[serde(rename = "$schema")] + schema: String, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -186,22 +199,23 @@ impl Schema { }) } - pub(crate) fn traverse_mut(&mut self, visit: impl Fn(&mut Schema) -> Result<()>) -> Result<()> { + pub(crate) fn traverse_mut(&mut self, visit: &mut impl FnMut(&mut Schema) -> Result) -> Result { visit(self)?; if let Some(object) = &mut self.object_schema { - object.properties.values_mut().try_for_each(&visit)?; + for schema in object.properties.values_mut() { + schema.traverse_mut(visit)?; + } } if let Some(array) = &mut self.array_schema { - visit(&mut array.items)?; + array.items.traverse_mut(visit)?; } if let Some(one_of) = &mut self.one_of { - one_of - .iter_mut() - .map(|variant| &mut variant.schema) - .try_for_each(&visit)?; + for variant in one_of { + variant.schema.traverse_mut(visit)?; + } } Ok(()) @@ -286,15 +300,28 @@ impl Schema { if examples.is_empty() ) } + + pub(crate) fn inline_reference(&mut self, referenced_value: &Schema) { + // Values from the schema should take priority + merge_json_mut(self, referenced_value); + + self.reference = None; + } } impl RootSchema { pub(crate) fn from_file(path: impl AsRef) -> Result { - let input = fs::read_to_string("deny.schema.yml")?; + let input = fs::read_to_string(path.as_ref())?; let input: Self = serde_yaml::from_str(&input)?; Ok(input) } + pub(crate) fn remove_definition(&mut self, definition: &str) -> Result { + self.definitions + .remove(definition) + .with_context(|| format!("Reference to unknown definition: `{definition}`")) + } + pub(crate) fn definition(&self, definition: &str) -> Result<&Schema> { self.definitions .get(definition) @@ -306,9 +333,12 @@ impl RootSchema { return Ok(None); }; - let definition = self - .definition(definition) - .with_context(|| format!("inside of schema: {schema:#?}"))?; + let definition = self.definition(definition).with_context(|| { + format!( + "error inside of schema: {}", + serdex::json::to_string_pretty(schema) + ) + })?; Ok(Some(definition)) } @@ -319,14 +349,20 @@ impl RootSchema { }; let mut output = definition.clone(); - - // Values from the schema should take priority - merge_json_mut(&mut output, schema); - - output.reference = None; + output.inline_reference(schema); Ok(output) } + + pub(crate) fn traverse_mut( + &mut self, + visit: &mut impl FnMut(&mut Schema) -> Result, + ) -> Result<()> { + self.schema.traverse_mut(visit)?; + self.definitions + .values_mut() + .try_for_each(|schema| schema.traverse_mut(visit)) + } } impl OneOfVariantSchema { diff --git a/deny16.schema.json b/deny16.schema.json deleted file mode 100644 index 817e42b5..00000000 --- a/deny16.schema.json +++ /dev/null @@ -1,326 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft-07/schema#", - "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", - "title": "cargo-deny configuration file", - "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", - "type": "object", - "properties": - { - "advisories": - { - "$ref": "#/definitions/advisories" - }, - "graph": - { - "$ref": "#/definitions/graph" - }, - "output": - { - "$ref": "#/definitions/output" - } - }, - "definitions": - { - "advisories": - { - "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found\n[here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html)\n", - "type": "object", - "properties": - { - "db-urls": - { - "type": "array", - "items": - { - "type": "string", - "format": "uri" - }, - "default": - [ - "https://github.com/RustSec/advisory-db" - ], - "description": "URLs to one or more advisory databases." - }, - "db-path": - { - "type": "string", - "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" - }, - "version": - { - "enum": - [ - 2 - ], - "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" - }, - "vulnerability": - { - "anyOf": - [ - { - "const": "deny", - "description": "Emit an error with details about the problem", - "and fail the check.": null - }, - { - "const": "warn", - "description": "Print a warning for each propblem", - "but don't fail the check.": null - }, - { - "const": "allow", - "description": "Print a note about the problem", - "but don't fail the check.": null - } - ], - "enum": - [ - "deny", - "warn", - "allow" - ], - "x-taplo": - { - "docs": - { - "enumValues": - [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." - ] - } - } - }, - "unmaintained": - { - "deprecated": true, - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" - }, - "unsound": - { - "deprecated": true, - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" - }, - "notice": - { - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" - }, - "yanked": - { - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" - }, - "ignore": - { - "type": "array", - "items": - { - "$ref": "#/definitions/advisories-ignore-item" - }, - "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" - } - } - }, - "advisories-ignore-item": - { - "oneOf": - [ - { - "type": "string", - "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." - }, - { - "$ref": "#/definitions/advisories-ignore-advisory" - }, - { - "$ref": "#/definitions/advisories-ignore-yanked" - } - ] - }, - "advisories-ignore-advisory": - { - "type": "object", - "required": - [ - "id" - ], - "properties": - { - "id": - { - "type": "string", - "examples": - [ - "RUSTSEC-2019-0001" - ], - "description": "The unique identifier of the advisory to ignore" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "advisories-ignore-yanked": - { - "type": "object", - "required": - [ - "crate" - ], - "properties": - { - "crate": - { - "$ref": "#/definitions/package-spec" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "ignore-reason": - { - "type": "string", - "description": "Free-form string that can be used to describe the reason why the advisory is ignored." - }, - "lint-level": - { - "enum": - [ - "deny", - "warn", - "allow" - ], - "x-taplo": - { - "docs": - { - "enumValues": - [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." - ] - } - } - }, - "package-spec": - { - "type": "string", - "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" - }, - "graph": - { - "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", - "type": "object", - "properties": - { - "targets": - { - "type": "array", - "items": - { - "$ref": "#/definitions/target" - }, - "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" - }, - "exclude": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" - }, - "all-features": - { - "type": "boolean", - "description": "If set to `true`, `--all-features` will be used when collecting metadata." - }, - "no-default-features": - { - "type": "boolean", - "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." - }, - "features": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" - }, - "exclude-dev": - { - "type": "boolean", - "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" - } - } - }, - "target": - { - "oneOf": - [ - { - "$ref": "#/definitions/target-string" - }, - { - "$ref": "#/definitions/target-complex" - } - ] - }, - "target-complex": - { - "description": "Advanced configurations to apply for the target triple", - "type": "object", - "required": - [ - "triple" - ], - "properties": - { - "triple": - { - "$ref": "#/definitions/target-string" - }, - "features": - { - "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" - } - } - }, - "target-string": - { - "type": "string", - "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" - }, - "output": - { - "description": "The output table provides options for how/if diagnostics are outputted", - "type": "object", - "properties": - { - "feature-depth": - { - "type": "integer", - "minimum": 0, - "default": 1, - "description": "The maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" - } - } - } - } -} \ No newline at end of file diff --git a/deny38.schema.json b/deny38.schema.json deleted file mode 100644 index 817e42b5..00000000 --- a/deny38.schema.json +++ /dev/null @@ -1,326 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft-07/schema#", - "$id": "https://github.com/EmbarkStudios/cargo-deny/deny.schema.json", - "title": "cargo-deny configuration file", - "description": "Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html", - "type": "object", - "properties": - { - "advisories": - { - "$ref": "#/definitions/advisories" - }, - "graph": - { - "$ref": "#/definitions/graph" - }, - "output": - { - "$ref": "#/definitions/output" - } - }, - "definitions": - { - "advisories": - { - "description": "This section is considered when running `cargo deny check advisories`\nMore documentation for the advisories section can be found\n[here](https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html)\n", - "type": "object", - "properties": - { - "db-urls": - { - "type": "array", - "items": - { - "type": "string", - "format": "uri" - }, - "default": - [ - "https://github.com/RustSec/advisory-db" - ], - "description": "URLs to one or more advisory databases." - }, - "db-path": - { - "type": "string", - "description": "Path to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n" - }, - "version": - { - "enum": - [ - 2 - ], - "description": "The advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n" - }, - "vulnerability": - { - "anyOf": - [ - { - "const": "deny", - "description": "Emit an error with details about the problem", - "and fail the check.": null - }, - { - "const": "warn", - "description": "Print a warning for each propblem", - "but don't fail the check.": null - }, - { - "const": "allow", - "description": "Print a note about the problem", - "but don't fail the check.": null - } - ], - "enum": - [ - "deny", - "warn", - "allow" - ], - "x-taplo": - { - "docs": - { - "enumValues": - [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." - ] - } - } - }, - "unmaintained": - { - "deprecated": true, - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n" - }, - "unsound": - { - "deprecated": true, - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n" - }, - "notice": - { - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n" - }, - "yanked": - { - "$ref": "#/definitions/lint-level", - "default": "warn", - "description": "Determines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n" - }, - "ignore": - { - "type": "array", - "items": - { - "$ref": "#/definitions/advisories-ignore-item" - }, - "description": "```toml\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n" - } - } - }, - "advisories-ignore-item": - { - "oneOf": - [ - { - "type": "string", - "description": "Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`)." - }, - { - "$ref": "#/definitions/advisories-ignore-advisory" - }, - { - "$ref": "#/definitions/advisories-ignore-yanked" - } - ] - }, - "advisories-ignore-advisory": - { - "type": "object", - "required": - [ - "id" - ], - "properties": - { - "id": - { - "type": "string", - "examples": - [ - "RUSTSEC-2019-0001" - ], - "description": "The unique identifier of the advisory to ignore" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "advisories-ignore-yanked": - { - "type": "object", - "required": - [ - "crate" - ], - "properties": - { - "crate": - { - "$ref": "#/definitions/package-spec" - }, - "reason": - { - "$ref": "#/definitions/ignore-reason" - } - } - }, - "ignore-reason": - { - "type": "string", - "description": "Free-form string that can be used to describe the reason why the advisory is ignored." - }, - "lint-level": - { - "enum": - [ - "deny", - "warn", - "allow" - ], - "x-taplo": - { - "docs": - { - "enumValues": - [ - "Emit an error with details about the problem, and fail the check.", - "Print a warning for each propblem, but don't fail the check.", - "Print a note about the problem, but don't fail the check." - ] - } - } - }, - "package-spec": - { - "type": "string", - "description": "Many configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n" - }, - "graph": - { - "description": "The graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n", - "type": "object", - "properties": - { - "targets": - { - "type": "array", - "items": - { - "$ref": "#/definitions/target" - }, - "description": "By default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n" - }, - "exclude": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n" - }, - "all-features": - { - "type": "boolean", - "description": "If set to `true`, `--all-features` will be used when collecting metadata." - }, - "no-default-features": - { - "type": "boolean", - "description": "If set to `true`, `--no-default-features` will be used when collecting metadata." - }, - "features": - { - "type": "array", - "items": - { - "type": "string" - }, - "description": "If set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n" - }, - "exclude-dev": - { - "type": "boolean", - "description": "If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n" - } - } - }, - "target": - { - "oneOf": - [ - { - "$ref": "#/definitions/target-string" - }, - { - "$ref": "#/definitions/target-complex" - } - ] - }, - "target-complex": - { - "description": "Advanced configurations to apply for the target triple", - "type": "object", - "required": - [ - "triple" - ], - "properties": - { - "triple": - { - "$ref": "#/definitions/target-string" - }, - "features": - { - "description": "Rust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n" - } - } - }, - "target-string": - { - "type": "string", - "description": "The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n" - }, - "output": - { - "description": "The output table provides options for how/if diagnostics are outputted", - "type": "object", - "properties": - { - "feature-depth": - { - "type": "integer", - "minimum": 0, - "default": 1, - "description": "The maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n" - } - } - } - } -} \ No newline at end of file From 327be3840c317b6b42d7a0643852ac6e84c72b5c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 2 May 2024 02:26:54 +0000 Subject: [PATCH 17/20] Fix inlining --- dashie/src/md_doc/hir/mod.rs | 4 +-- dashie/src/md_doc/hir/simplifying.rs | 4 +-- dashie/src/md_doc/mir/mod.rs | 24 ++++++++++--- dashie/src/source.rs | 53 +++++++++++++++++++++++----- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/dashie/src/md_doc/hir/mod.rs b/dashie/src/md_doc/hir/mod.rs index 786fd359..92d7da56 100644 --- a/dashie/src/md_doc/hir/mod.rs +++ b/dashie/src/md_doc/hir/mod.rs @@ -5,7 +5,7 @@ pub(crate) use node::*; mod simplifying; use crate::prelude::*; -use crate::source::{ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; +use crate::source::{self, ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; use buildstructor::buildstructor; use std::collections::BTreeMap; @@ -194,7 +194,7 @@ impl LoweringContext { examples: schema.examples, }; - let doc = if let Some(reference) = schema.reference.clone() { + let doc = if let Some(source::Reference::Uninlined(reference)) = schema.reference.clone() { SchemaDoc::Ref(SchemaDocRef { reference, data }) } else if path.segments.len() % (usize::from(self.max_nesting_in_file) + 1) == 0 { SchemaDoc::Nested(data) diff --git a/dashie/src/md_doc/hir/simplifying.rs b/dashie/src/md_doc/hir/simplifying.rs index c0a33316..dfb09bf1 100644 --- a/dashie/src/md_doc/hir/simplifying.rs +++ b/dashie/src/md_doc/hir/simplifying.rs @@ -17,7 +17,7 @@ impl LoweringContext { }; let definition_ref_counts = all_schemas() - .filter_map(|entry| entry.schema.referenced_definition()) + .filter_map(|entry| entry.schema.referenced_uninlined_definition()) .counts(); let unused_defs: Vec<_> = self @@ -85,7 +85,7 @@ impl SimplificationContext { } fn inline_single_reference(&mut self, schema: &mut source::Schema) { - let Some(definition) = schema.referenced_definition() else { + let Some(definition) = schema.referenced_uninlined_definition() else { return; }; let Some(definition) = self.single_references.remove(definition) else { diff --git a/dashie/src/md_doc/mir/mod.rs b/dashie/src/md_doc/mir/mod.rs index 96c939d8..e5d84154 100644 --- a/dashie/src/md_doc/mir/mod.rs +++ b/dashie/src/md_doc/mir/mod.rs @@ -84,17 +84,31 @@ impl Context { } // fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { - // let document = self.schema_embedded(node, doc); - - // let name = node.schema.path.segments.last().unwrap().to_string(); + // let name = node + // .schema + // .path + // .segments + // .last() + // .unwrap_or_else(|| &PathSegment::Index) + // .to_string(); // let nested = NamedDocument { // name: name.clone(), - // document, + // data: self.schema_embedded(node, doc), // }; // let url = format!("./{name}.md"); - // let section = self.type_reference(&node.schema, "Nested", &url); + // let body = [ + // self.tag_for_type(&node.schema), + // self.tag_for_required(&node.schema), + // ] + // .into_iter() + // .flatten() + // .join("\n"); + + // let section = Section::leaf(self.section_header(&node.schema), body); + + // // self.type_reference(&node.schema, "Nested", &url); // Document { // section, diff --git a/dashie/src/source.rs b/dashie/src/source.rs index 45a2016b..3ebea2bb 100644 --- a/dashie/src/source.rs +++ b/dashie/src/source.rs @@ -66,8 +66,8 @@ pub(crate) struct Schema { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) description: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "$ref")] - pub(crate) reference: Option, + #[serde(skip_serializing_if = "Reference::skip_serializing", rename = "$ref")] + pub(crate) reference: Option, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) default: Option, @@ -77,6 +77,31 @@ pub(crate) struct Schema { pub(crate) x_taplo: Option, } +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub(crate) enum Reference { + Uninlined(String), + /// Reference to the definition that was inlined into this schema. + Inlined(String), +} + +impl Reference { + fn as_str(&self) -> &str { + let (Self::Uninlined(reference) | Self::Inlined(reference)) = self; + reference + } + fn skip_serializing(val: &Option) -> bool { + matches!(val, Some(Self::Inlined(_)) | None) + } + + fn as_uninlined(&self) -> Option<&str> { + match self { + Self::Uninlined(reference) => Some(reference), + Self::Inlined(_) => None, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub(crate) enum EnumVariantSchema { @@ -275,8 +300,11 @@ impl Schema { .with_context(|| format!("Expected description for schema, but found none: {self:#?}")) } - pub(crate) fn referenced_definition(&self) -> Option<&str> { - self.reference.as_ref()?.strip_prefix("#/definitions/") + pub(crate) fn referenced_uninlined_definition(&self) -> Option<&str> { + self.reference + .as_ref()? + .as_uninlined()? + .strip_prefix("#/definitions/") } pub(crate) fn is_undocumented_primitive(&self) -> bool { @@ -304,8 +332,16 @@ impl Schema { pub(crate) fn inline_reference(&mut self, referenced_value: &Schema) { // Values from the schema should take priority merge_json_mut(self, referenced_value); - - self.reference = None; + self.reference = match self.reference.take().unwrap() { + Reference::Uninlined(reference) => Some(Reference::Inlined(reference)), + Reference::Inlined(reference) => { + panic!( + "Reference `{reference}` was already inlined:\n\ + Schema: {self:#?}\n\ + Referenced value: {referenced_value:#?}" + ) + } + }; } } @@ -329,7 +365,7 @@ impl RootSchema { } fn referenced_definition(&self, schema: &Schema) -> Result> { - let Some(definition) = schema.referenced_definition() else { + let Some(definition) = schema.referenced_uninlined_definition() else { return Ok(None); }; @@ -372,7 +408,8 @@ impl OneOfVariantSchema { .or_else(|| { self.schema .reference - .as_deref()? + .as_ref()? + .as_str() .strip_prefix("#/definitions/") }) .or(self.schema.ty.as_deref()) From 31edd09e54585ed4ae7dcdc35e2e59bb926c11c8 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 3 May 2024 08:15:39 +0000 Subject: [PATCH 18/20] Next iter --- dashie/src/cli/codegen/json_schema.rs | 4 +- dashie/src/md_doc/hir/mod.rs | 10 +-- dashie/src/md_doc/hir/node.rs | 2 +- dashie/src/md_doc/hir/simplifying.rs | 36 +++++----- dashie/src/md_doc/mir/mod.rs | 80 +++++++++++---------- dashie/src/{source.rs => source/mod.rs} | 92 +++++-------------------- dashie/src/source/traversal.rs | 58 ++++++++++++++++ 7 files changed, 143 insertions(+), 139 deletions(-) rename dashie/src/{source.rs => source/mod.rs} (83%) create mode 100644 dashie/src/source/traversal.rs diff --git a/dashie/src/cli/codegen/json_schema.rs b/dashie/src/cli/codegen/json_schema.rs index cc983771..e7c5bb5d 100644 --- a/dashie/src/cli/codegen/json_schema.rs +++ b/dashie/src/cli/codegen/json_schema.rs @@ -1,6 +1,6 @@ -use crate::source::{EnumVariantSchema, RootSchema, Schema}; use crate::prelude::*; use crate::serdex; +use crate::source::{EnumVariantSchema, RootSchema, Schema, Traverse}; /// Generate the JSON schema based on the input YML schema. pub(crate) fn gen(root: &RootSchema) -> Result { @@ -45,7 +45,7 @@ impl<'a> GenContext<'a> { fn gen_schema(&self, schema: &Schema) -> Result { let mut schema = schema.clone(); - schema.traverse_mut(&mut |schema| self.normalize_enum(schema))?; + schema.try_traverse_mut(&mut |schema| self.normalize_enum(schema))?; Ok(schema) } diff --git a/dashie/src/md_doc/hir/mod.rs b/dashie/src/md_doc/hir/mod.rs index 92d7da56..e3a21fe4 100644 --- a/dashie/src/md_doc/hir/mod.rs +++ b/dashie/src/md_doc/hir/mod.rs @@ -9,6 +9,7 @@ use crate::source::{self, ArraySchema, ObjectSchema, OneOfVariantSchema, RootSch use buildstructor::buildstructor; use std::collections::BTreeMap; +#[derive(Debug)] pub(crate) struct Dom { pub(crate) root: SchemaNode, pub(crate) type_index: BTreeMap, @@ -24,7 +25,7 @@ impl Dom { ) -> Result { let ctx = LoweringContext { root: schema, - max_nesting_in_file: max_nesting_in_file.unwrap_or(2), + max_nesting_in_file: max_nesting_in_file.unwrap_or(3), allow_unused_definitions: allow_unused_definitions.unwrap_or(false), }; @@ -194,9 +195,9 @@ impl LoweringContext { examples: schema.examples, }; - let doc = if let Some(source::Reference::Uninlined(reference)) = schema.reference.clone() { + let doc = if let Some(reference) = schema.reference.clone() { SchemaDoc::Ref(SchemaDocRef { reference, data }) - } else if path.segments.len() % (usize::from(self.max_nesting_in_file) + 1) == 0 { + } else if (path.segments.len() + 1) % (usize::from(self.max_nesting_in_file) + 1) == 0 { SchemaDoc::Nested(data) } else { SchemaDoc::Embedded(data) @@ -242,9 +243,10 @@ impl LoweringContext { let duplicates: Vec<_> = names.iter().duplicates().collect(); - anyhow::ensure!( + ensure!( duplicates.is_empty(), "Duplicate variant names found in one_of schema.\n\ + Path: {path}\n\ Duplicates: {duplicates:?}\n\ Variants: {variants:#?}", ); diff --git a/dashie/src/md_doc/hir/node.rs b/dashie/src/md_doc/hir/node.rs index 096b1deb..ed717568 100644 --- a/dashie/src/md_doc/hir/node.rs +++ b/dashie/src/md_doc/hir/node.rs @@ -103,7 +103,7 @@ impl fmt::Display for Path { segments.try_for_each(|segment| match &segment { PathSegment::Field(_) => write!(f, ".{segment}"), PathSegment::Index => write!(f, "{segment}"), - PathSegment::Variant(_) => write!(f, "as {segment}"), + PathSegment::Variant(_) => write!(f, "::{segment}"), }) } } diff --git a/dashie/src/md_doc/hir/simplifying.rs b/dashie/src/md_doc/hir/simplifying.rs index dfb09bf1..1da11d52 100644 --- a/dashie/src/md_doc/hir/simplifying.rs +++ b/dashie/src/md_doc/hir/simplifying.rs @@ -1,6 +1,6 @@ use super::LoweringContext; use crate::prelude::*; -use crate::source; +use crate::source::{self, Traverse}; use std::collections::{BTreeMap, BTreeSet}; use std::ops::ControlFlow; @@ -17,7 +17,7 @@ impl LoweringContext { }; let definition_ref_counts = all_schemas() - .filter_map(|entry| entry.schema.referenced_uninlined_definition()) + .filter_map(|entry| entry.schema.referenced_definition_name()) .counts(); let unused_defs: Vec<_> = self @@ -57,7 +57,14 @@ impl LoweringContext { let mut ctx = SimplificationContext { single_references }; - ctx.simplify(self)?; + ctx.simplify(&mut self.root); + + assert_eq!( + ctx.single_references.len(), + 0, + "All single references should have been inlined at this point, but got: {:#?}", + ctx.single_references + ); Ok(ControlFlow::Continue(())) } @@ -68,30 +75,21 @@ struct SimplificationContext { } impl SimplificationContext { - fn simplify(&mut self, lowering: &mut LoweringContext) -> Result { - // We simplify in a loop because inlining a definition may introduce new - // opportunities for further simplification. It is a fixed-point iteration - // where we keep simplifying until eventually no more simplifications can - // be made. - while !self.single_references.is_empty() { - lowering.root.traverse_mut(&mut |schema| { - self.inline_single_reference(schema); - Ok(()) - })?; - dbg!(&self.single_references.keys().collect_vec()); - } - - Ok(()) + fn simplify(&mut self, tree: &mut impl Traverse) { + tree.traverse_mut(&mut |schema| self.inline_single_reference(schema)); } fn inline_single_reference(&mut self, schema: &mut source::Schema) { - let Some(definition) = schema.referenced_uninlined_definition() else { + let Some(definition_name) = schema.referenced_definition_name() else { return; }; - let Some(definition) = self.single_references.remove(definition) else { + let Some(mut definition) = self.single_references.remove(definition_name) else { return; }; + // Recursively simplify the inlined definition itself. + self.simplify(&mut definition); + schema.inline_reference(&definition); } } diff --git a/dashie/src/md_doc/mir/mod.rs b/dashie/src/md_doc/mir/mod.rs index e5d84154..f6ae7b4b 100644 --- a/dashie/src/md_doc/mir/mod.rs +++ b/dashie/src/md_doc/mir/mod.rs @@ -12,6 +12,8 @@ use std::collections::BTreeMap; impl hir::Dom { pub(crate) fn lower(&self) -> Dom { + dbg!(&self); + let context = Context {}; context.doc(self) } @@ -78,43 +80,44 @@ impl Context { fn schema_node(&self, node: &SchemaNode) -> Document { match &node.schema.doc { SchemaDoc::Embedded(doc) => self.schema_embedded(&node, doc), - SchemaDoc::Nested(doc) => self.schema_embedded(&node, doc), + SchemaDoc::Nested(doc) => self.schema_nested(&node, doc), SchemaDoc::Ref(reference) => self.schema_embedded(&node, &reference.data), } } - // fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { - // let name = node - // .schema - // .path - // .segments - // .last() - // .unwrap_or_else(|| &PathSegment::Index) - // .to_string(); - - // let nested = NamedDocument { - // name: name.clone(), - // data: self.schema_embedded(node, doc), - // }; - - // let url = format!("./{name}.md"); - // let body = [ - // self.tag_for_type(&node.schema), - // self.tag_for_required(&node.schema), - // ] - // .into_iter() - // .flatten() - // .join("\n"); - - // let section = Section::leaf(self.section_header(&node.schema), body); - - // // self.type_reference(&node.schema, "Nested", &url); - - // Document { - // section, - // children: vec![nested], - // } - // } + fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { + let name = node + .schema + .path + .segments + .last() + .unwrap_or(&PathSegment::Index) + .to_string(); + + let nested = NamedDocument { + // name: node.schema.path.to_string(), + name, + data: self.schema_embedded(node, doc), + }; + + // let url = format!("./{name}.md"); + let body = [ + self.tag_for_type(&node.schema), + self.tag_for_required(&node.schema), + ] + .into_iter() + .flatten() + .join("
\n"); + + let section = Section::leaf(self.section_header(&node.schema), body); + + // self.type_reference(&node.schema, "Nested", &url); + + Document { + section, + children: vec![nested], + } + } fn schema_embedded(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { let enum_doc = node @@ -160,11 +163,12 @@ impl Context { }; }; - match &last_segment { - PathSegment::Field(_) => format!("`{}`", schema.path), - PathSegment::Index => format!("`{}`", schema.path), - PathSegment::Variant(_) => format!("`{}`", schema.path), - } + format!("`{last_segment}`") + // match &last_segment { + // PathSegment::Field(_) => format!("`{}`", schema.path), + // PathSegment::Index => format!("`{}`", schema.path), + // PathSegment::Variant(_) => format!("`{}`", schema.path), + // } } fn section_body(&self, schema: &Schema, doc: &SchemaDocData) -> String { diff --git a/dashie/src/source.rs b/dashie/src/source/mod.rs similarity index 83% rename from dashie/src/source.rs rename to dashie/src/source/mod.rs index 3ebea2bb..6ffc857e 100644 --- a/dashie/src/source.rs +++ b/dashie/src/source/mod.rs @@ -1,3 +1,7 @@ +mod traversal; + +pub(crate) use traversal::*; + use crate::prelude::*; use crate::serdex; use camino::Utf8Path; @@ -66,8 +70,8 @@ pub(crate) struct Schema { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) description: Option, - #[serde(skip_serializing_if = "Reference::skip_serializing", rename = "$ref")] - pub(crate) reference: Option, + #[serde(skip_serializing_if = "Option::is_none", rename = "$ref")] + pub(crate) reference: Option, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) default: Option, @@ -75,31 +79,11 @@ pub(crate) struct Schema { /// Extensions for taplo TOML language server #[serde(skip_serializing_if = "Option::is_none", rename = "x-taplo")] pub(crate) x_taplo: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(untagged)] -pub(crate) enum Reference { - Uninlined(String), - /// Reference to the definition that was inlined into this schema. - Inlined(String), -} -impl Reference { - fn as_str(&self) -> &str { - let (Self::Uninlined(reference) | Self::Inlined(reference)) = self; - reference - } - fn skip_serializing(val: &Option) -> bool { - matches!(val, Some(Self::Inlined(_)) | None) - } - - fn as_uninlined(&self) -> Option<&str> { - match self { - Self::Uninlined(reference) => Some(reference), - Self::Inlined(_) => None, - } - } + /// If [`Some`] specifies the original reference that was inlined into this + /// from a [`Self::reference`]. + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) inlined_from: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -224,28 +208,6 @@ impl Schema { }) } - pub(crate) fn traverse_mut(&mut self, visit: &mut impl FnMut(&mut Schema) -> Result) -> Result { - visit(self)?; - - if let Some(object) = &mut self.object_schema { - for schema in object.properties.values_mut() { - schema.traverse_mut(visit)?; - } - } - - if let Some(array) = &mut self.array_schema { - array.items.traverse_mut(visit)?; - } - - if let Some(one_of) = &mut self.one_of { - for variant in one_of { - variant.schema.traverse_mut(visit)?; - } - } - - Ok(()) - } - fn try_downcast_as<'a, T>(&'a self, schema: &'a Option, label: &str) -> Result<&'a T> { schema .as_ref() @@ -300,11 +262,8 @@ impl Schema { .with_context(|| format!("Expected description for schema, but found none: {self:#?}")) } - pub(crate) fn referenced_uninlined_definition(&self) -> Option<&str> { - self.reference - .as_ref()? - .as_uninlined()? - .strip_prefix("#/definitions/") + pub(crate) fn referenced_definition_name(&self) -> Option<&str> { + self.reference.as_ref()?.strip_prefix("#/definitions/") } pub(crate) fn is_undocumented_primitive(&self) -> bool { @@ -324,6 +283,7 @@ impl Schema { reference: None, default: None, x_taplo: None, + inlined_from: _, } if examples.is_empty() ) @@ -332,16 +292,7 @@ impl Schema { pub(crate) fn inline_reference(&mut self, referenced_value: &Schema) { // Values from the schema should take priority merge_json_mut(self, referenced_value); - self.reference = match self.reference.take().unwrap() { - Reference::Uninlined(reference) => Some(Reference::Inlined(reference)), - Reference::Inlined(reference) => { - panic!( - "Reference `{reference}` was already inlined:\n\ - Schema: {self:#?}\n\ - Referenced value: {referenced_value:#?}" - ) - } - }; + self.inlined_from = self.reference.take(); } } @@ -365,7 +316,7 @@ impl RootSchema { } fn referenced_definition(&self, schema: &Schema) -> Result> { - let Some(definition) = schema.referenced_uninlined_definition() else { + let Some(definition) = schema.referenced_definition_name() else { return Ok(None); }; @@ -389,16 +340,6 @@ impl RootSchema { Ok(output) } - - pub(crate) fn traverse_mut( - &mut self, - visit: &mut impl FnMut(&mut Schema) -> Result, - ) -> Result<()> { - self.schema.traverse_mut(visit)?; - self.definitions - .values_mut() - .try_for_each(|schema| schema.traverse_mut(visit)) - } } impl OneOfVariantSchema { @@ -408,7 +349,8 @@ impl OneOfVariantSchema { .or_else(|| { self.schema .reference - .as_ref()? + .as_ref() + .or(self.schema.inlined_from.as_ref())? .as_str() .strip_prefix("#/definitions/") }) diff --git a/dashie/src/source/traversal.rs b/dashie/src/source/traversal.rs new file mode 100644 index 00000000..249de5fe --- /dev/null +++ b/dashie/src/source/traversal.rs @@ -0,0 +1,58 @@ +use super::{RootSchema, Schema}; + +pub(crate) trait Traverse { + fn traverse_mut(&mut self, visit: &mut dyn FnMut(&mut T)) { + let result = self.try_traverse_mut(&mut |item| { + visit(item); + Ok::<(), std::convert::Infallible>(()) + }); + match result { + Ok(()) => {} + Err(infallible) => match infallible {}, + } + } + + fn try_traverse_mut( + &mut self, + visit: &mut dyn FnMut(&mut T) -> Result<(), E>, + ) -> Result<(), E>; +} + +impl Traverse for Schema { + fn try_traverse_mut( + &mut self, + visit: &mut dyn FnMut(&mut Schema) -> Result<(), E>, + ) -> Result<(), E> { + visit(self)?; + + if let Some(object) = &mut self.object_schema { + for schema in object.properties.values_mut() { + schema.try_traverse_mut(visit)?; + } + } + + if let Some(array) = &mut self.array_schema { + array.items.try_traverse_mut(visit)?; + } + + if let Some(one_of) = &mut self.one_of { + for variant in one_of { + variant.schema.try_traverse_mut(visit)?; + } + } + + Ok(()) + } +} + +impl Traverse for RootSchema { + fn try_traverse_mut( + &mut self, + visit: &mut dyn FnMut(&mut Schema) -> Result<(), E>, + ) -> Result<(), E> { + self.definitions + .values_mut() + .chain([&mut self.schema]) + .try_for_each(|schema| schema.try_traverse_mut(visit)) + } +} From 3825c5ea29c8c4a9a794da2fba7afaa74a7885cb Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 18 May 2024 23:13:12 +0000 Subject: [PATCH 19/20] Next iteratio --- Cargo.lock | 82 +- Cargo.toml | 2 +- book.json | 1146 +++++++++++++++++ config-spec/advisories.tsp | 187 +++ config-spec/bans.tsp | 12 + config-spec/graph.tsp | 114 ++ config-spec/main.tsp | 47 + config-spec/output.tsp | 8 + config-spec/package-lock.json | 781 +++++++++++ config-spec/package-spec.tsp | 75 ++ config-spec/package.json | 13 + config-spec/schemd.tsp | 27 + config-spec/schemd/decorators.js | 185 +++ config-spec/schemd/index.js | 14 + config-spec/schemd/lib.js | 6 + config-spec/tsconfig.json | 23 + .../tsp-output/@typespec/json-schema/Foo.json | 21 + .../tsp-output/@typespec/json-schema/Foo.yaml | 14 + .../@typespec/json-schema/PackageSpec.yaml | 11 + config-spec/tsp-output/CargoDenyConfig.yaml | 416 ++++++ config-spec/tspconfig.yaml | 5 + cspell.yml | 3 + deny.template.toml | 3 +- docs/book.toml | 6 +- docs/src/SUMMARY.md | 4 +- docus/src/plugin/index.ts | 10 +- {dashie => schemd}/Cargo.toml | 5 +- {dashie => schemd}/src/cli.rs | 0 .../src/cli/codegen/json_schema.rs | 19 +- {dashie => schemd}/src/cli/codegen/mod.rs | 8 +- {dashie => schemd}/src/cli/mdbook/mod.rs | 0 .../src/cli/mdbook/preprocessor/mod.rs | 0 .../src/cli/mdbook/preprocessor/preprocess.rs | 51 +- {dashie => schemd}/src/entrypoint.rs | 2 +- {dashie => schemd}/src/error.rs | 0 {dashie => schemd}/src/lib.rs | 1 + {dashie => schemd}/src/main.rs | 2 +- .../mir/mdast.rs => schemd/src/md_ast.rs | 30 +- {dashie => schemd}/src/md_doc/hir/mod.rs | 80 +- {dashie => schemd}/src/md_doc/hir/node.rs | 53 +- .../src/md_doc/hir/simplifying.rs | 6 +- {dashie => schemd}/src/md_doc/mir/mod.rs | 74 +- {dashie => schemd}/src/md_doc/mod.rs | 0 {dashie => schemd}/src/serdex/json.rs | 0 {dashie => schemd}/src/serdex/mod.rs | 0 {dashie => schemd}/src/source/mod.rs | 208 ++- {dashie => schemd}/src/source/traversal.rs | 6 +- 47 files changed, 3540 insertions(+), 220 deletions(-) create mode 100644 book.json create mode 100644 config-spec/advisories.tsp create mode 100644 config-spec/bans.tsp create mode 100644 config-spec/graph.tsp create mode 100644 config-spec/main.tsp create mode 100644 config-spec/output.tsp create mode 100644 config-spec/package-lock.json create mode 100644 config-spec/package-spec.tsp create mode 100644 config-spec/package.json create mode 100644 config-spec/schemd.tsp create mode 100644 config-spec/schemd/decorators.js create mode 100644 config-spec/schemd/index.js create mode 100644 config-spec/schemd/lib.js create mode 100644 config-spec/tsconfig.json create mode 100644 config-spec/tsp-output/@typespec/json-schema/Foo.json create mode 100644 config-spec/tsp-output/@typespec/json-schema/Foo.yaml create mode 100644 config-spec/tsp-output/@typespec/json-schema/PackageSpec.yaml create mode 100644 config-spec/tsp-output/CargoDenyConfig.yaml create mode 100644 config-spec/tspconfig.yaml create mode 100644 cspell.yml rename {dashie => schemd}/Cargo.toml (95%) rename {dashie => schemd}/src/cli.rs (100%) rename {dashie => schemd}/src/cli/codegen/json_schema.rs (75%) rename {dashie => schemd}/src/cli/codegen/mod.rs (58%) rename {dashie => schemd}/src/cli/mdbook/mod.rs (100%) rename {dashie => schemd}/src/cli/mdbook/preprocessor/mod.rs (100%) rename {dashie => schemd}/src/cli/mdbook/preprocessor/preprocess.rs (84%) rename {dashie => schemd}/src/entrypoint.rs (96%) rename {dashie => schemd}/src/error.rs (100%) rename {dashie => schemd}/src/lib.rs (96%) rename {dashie => schemd}/src/main.rs (68%) rename dashie/src/md_doc/mir/mdast.rs => schemd/src/md_ast.rs (86%) rename {dashie => schemd}/src/md_doc/hir/mod.rs (77%) rename {dashie => schemd}/src/md_doc/hir/node.rs (75%) rename {dashie => schemd}/src/md_doc/hir/simplifying.rs (95%) rename {dashie => schemd}/src/md_doc/mir/mod.rs (88%) rename {dashie => schemd}/src/md_doc/mod.rs (100%) rename {dashie => schemd}/src/serdex/json.rs (100%) rename {dashie => schemd}/src/serdex/mod.rs (100%) rename {dashie => schemd}/src/source/mod.rs (68%) rename {dashie => schemd}/src/source/traversal.rs (90%) diff --git a/Cargo.lock b/Cargo.lock index 444584dd..19d8edb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -595,29 +595,6 @@ dependencies = [ "serde", ] -[[package]] -name = "dashie" -version = "0.1.0" -dependencies = [ - "anyhow", - "buildstructor", - "camino", - "clap", - "fs-err", - "indexmap", - "itertools", - "mdbook", - "pulldown-cmark", - "pulldown-cmark-to-cmark", - "semver", - "serde", - "serde_json", - "serde_yaml", - "toml 0.8.12", - "tracing", - "tracing-subscriber", -] - [[package]] name = "data-encoding" version = "2.6.0" @@ -650,6 +627,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "duplicate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de78e66ac9061e030587b2a2e75cc88f22304913c907b11307bca737141230cb" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", +] + [[package]] name = "either" version = "1.10.0" @@ -2602,6 +2589,30 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.79" @@ -2953,6 +2964,31 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemd" +version = "0.1.0" +dependencies = [ + "anyhow", + "buildstructor", + "camino", + "clap", + "duplicate", + "fs-err", + "heck 0.5.0", + "indexmap", + "itertools", + "mdbook", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "semver", + "serde", + "serde_json", + "serde_yaml", + "toml 0.8.12", + "tracing", + "tracing-subscriber", +] + [[package]] name = "scoped-tls" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index e9152f9b..e73671af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["dashie"] +members = ["schemd"] [package] name = "cargo-deny" diff --git a/book.json b/book.json new file mode 100644 index 00000000..d0b6f201 --- /dev/null +++ b/book.json @@ -0,0 +1,1146 @@ +{ + "sections": [ + { + "Chapter": { + "name": "cargo-deny", + "content": "# [cargo-deny](https://github.com/EmbarkStudios/cargo-deny)\n\ncargo-deny is a cargo plugin that lets you lint your project's dependency graph to ensure all your dependencies conform to your expectations and requirements.\n\n## Quickstart\n\nInstalls cargo-deny, initializes your project with a default configuration, then runs all of the checks against your project.\n\n```bash\ncargo install --locked cargo-deny && cargo deny init && cargo deny check\n```\n\n## Command Line Interface\n\ncargo-deny is intended to be used as a [Command Line Tool](cli/index.html), see the link for the available commands and options.\n\n## Checks\n\ncargo-deny supports several classes of checks, see [Checks](checks/index.html) for the available checks and their configuration options.\n\n## API\n\ncargo-deny is primarily meant to be used as a cargo plugin, but a majority of its functionality is within a library whose docs you may view on [docs.rs](https://docs.rs/cargo-deny)\n\n## GitHub Action\n\nFor GitHub projects, one can run cargo-deny automatically as part of continuous integration using a GitHub Action:\n\n```yaml\nname: CI\non: [push, pull_request]\njobs:\n cargo-deny:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - uses: EmbarkStudios/cargo-deny-action@v1\n```\n\nFor more information, see [`cargo-deny-action`](https://github.com/EmbarkStudios/cargo-deny-action) repository.\n", + "number": [ + 1 + ], + "sub_items": [], + "path": "README.md", + "source_path": "README.md", + "parent_names": [] + } + }, + { + "Chapter": { + "name": "Command Line Tool", + "content": "# Command Line Tool\n\ncargo-deny can be used either as a command line tool or as a [Rust crate](https://crates.io/crates/cargo-deny). Let's focus on the command line tool capabilities first.\n\n## Install From Binaries\n\nPrecompiled binaries are provided for major platforms on a best-effort basis. Visit [the releases page](https://github.com/EmbarkStudios/cargo-deny/releases) to download the appropriate version for your platform.\n\n## Installation on Arch Linux\n\ncargo-deny is available in the Arch Linux [extra repository](https://archlinux.org/packages/extra/x86_64/cargo-deny/), you can install it via [pacman](https://wiki.archlinux.org/title/Pacman) as shown below:\n\n```bash\npacman -S cargo-deny\n```\n\n## Install From Source\n\ncargo-deny can also be installed from source.\n\n### Pre-requisites\n\ncargo-deny is written in **[Rust](https://www.rust-lang.org/)** and therefore needs to be compiled with **Cargo**. If you haven't already installed Rust, please go ahead and [install it](https://www.rust-lang.org/tools/install) now.\n\ncargo-deny depends on some crates that use C code, so you will also need to have a C toolchain available on your machine, such as gcc, clang, or msvc.\n\n### Install Crates.io version\n\nInstalling cargo-deny is relatively easy if you already have Rust and Cargo installed. You just have to type this snippet in your terminal:\n\n```bash\ncargo install --locked cargo-deny\n```\n\nThis will fetch the source code for the latest release from [Crates.io](https://crates.io/) and compile it. You will have to add Cargo's `bin` directory to your `PATH` if you have not done so already.\n\nRun `cargo deny help` in your terminal to verify if it works. Congratulations, you have installed cargo-deny!\n\n### Install Git version\n\nThe **[git version](https://github.com/EmbarkStudios/cargo-deny)** contains all the latest bug-fixes and features, that will be released in the next version on **Crates.io**, if you can't wait until the next release. You can build the git version yourself.\n\n```bash\ncargo install --locked --git https://github.com/EmbarkStudios/cargo-deny cargo-deny\n```\n\nRun `cargo deny help` in your terminal to verify if it works. Congratulations, you have installed cargo-deny!\n\n## CI Usage\n\nWe now have a Github Action for running cargo-deny on your Github repositories, check it out [here](https://github.com/EmbarkStudios/cargo-deny-action).\n\nIf you don't want to use the action, you can manually download (or install) cargo-deny as described above, but here's an example script that you can copy to get you started.\n\n```bash\n#!/bin/bash\nset -eu\n\nNAME=\"cargo-deny\"\nVS=\"0.8.5\"\nDIR=\"/tmp/$NAME\"\n\nmkdir $DIR\n\n# Download the tarball\ncurl -L -o $DIR/archive.tar.gz https://github.com/EmbarkStudios/$NAME/releases/download/$VS/$NAME-$VS-x86_64-unknown-linux-musl.tar.gz\n\n# Unpack the tarball into the temp directory\ntar -xzvf $DIR/archive.tar.gz --strip-components=1 -C $DIR\n\n# Run cargo deny check in our current directory\n$DIR/$NAME --context . -L debug check bans licenses advisories\n```\n", + "number": [ + 2 + ], + "sub_items": [ + { + "Chapter": { + "name": "common", + "content": "# Common options\n\nThe subcommands share some common options that can be used before the subcommand.\n\n## Options\n\n### `--manifest-path`\n\nThe path to a `Cargo.toml` file which is used as the context for operations.\n\n### `--all-features` (single crate or workspace)\n\nEnables all features when determining which crates to consider. Works for both single crates and workspaces.\n\n### `--no-default-features` (single crate only)\n\nDisables the `default` feature for a crate when determining which crates to consider.\n\n### `--features` (single crate only)\n\nSpace-separated list of features to enable when determining which crates to consider.\n\n### `--workspace`\n\nForces all workspace crates to be used as roots in the crate graph that we operate on, unless they are excluded by other means. By default, if you specify a [virtual manifest](https://doc.rust-lang.org/cargo/reference/manifest.html#virtual-manifest), all crates in the workspace will be used as roots. However, if you specify a normal package manifest somewhere inside a workspace, only that crate will be used as a graph root, and only other workspaces crates it depends on will be included in the graph. If you want to specify a sub-crate in a workspace, but still include all other crates in the workspace, you can use this flag.\n\n### `--exclude-dev`\n\nIf set to `true`, all `dev-dependencies`, even one for workspace crates, are not included in the crate graph used for any of the checks.\n\n### `--exclude`\n\nExclude the specified package(s) from the crate graph. Unlike other cargo subcommands, it doesn't have to be used in conjunction with the `--workspace` flag. This flag may be specified multiple times.\n\nThis uses a similar (though slightly more strict) [Package ID specification](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) to other cargo subcommands.\n\nPackages can also be excluded in your [configuration](../checks/cfg.md#the-exclude-field-optional) files, specifying this on the command line will append the package ID to the list that may exist in your configuration.\n\n### `-L, --log-level`\n\nThe log level for messages, only log messages at or above the level will be emitted.\n\nPossible values:\n\n* `off` - No output will be emitted\n* `error`\n* `warn` (default)\n* `info`\n* `debug`\n* `trace`\n\n### `--format`\n\nThe format of the output of both log and diagnostic messages.\n\nPossible values:\n\n* `human` (default) - Output for the pesky humans\n* `json` - Each log message/diagnostic is outputted as a single line JSON object\n\n### `--color`\n\nWhether coloring is applied to human-formatted output, using it on JSON output has no effect.\n\nPossible values:\n\n* `auto` (default) - Coloring is applied if the output stream is a TTY\n* `always` - Coloring is always applied\n* `never` - No coloring is applied for any output\n\n### `-t, --target`\n\nOne or more platforms to filter crates with. If a dependency is target specific, it will be ignored if it does not match at least 1 of the specified targets. This overrides the top-level [`targets = []`](../checks/cfg.md) configuration value.\n\n### `--offline`\n\nDisables network I/O.\n", + "number": [ + 2, + 1 + ], + "sub_items": [], + "path": "cli/common.md", + "source_path": "cli/common.md", + "parent_names": [ + "Command Line Tool" + ] + } + }, + { + "Chapter": { + "name": "init", + "content": "# The init command\n\ncargo-deny's configuration is a little bit complicated, so we provide the `init` command to create a configuration file from a template for you to give you a starting point for configuring how you want cargo-deny to lint your project.\n\nThe `init` command is used like this:\n\n```bash\ncargo deny init\n```\n\n## Specify a path\n\nThe `init` command can take a path as an argument to use as path of the config instead of the default which is `/deny.toml`.\n\n```bash\ncargo deny init path/to/config.toml\n```\n\n## Template\n\nA `deny.toml` file will be created in the current working directory that is a direct copy of [this template](https://github.com/EmbarkStudios/cargo-deny/blob/main/deny.template.toml).\n\n```ini\n{{#include ../../../deny.template.toml}}\n```\n", + "number": [ + 2, + 2 + ], + "sub_items": [], + "path": "cli/init.md", + "source_path": "cli/init.md", + "parent_names": [ + "Command Line Tool" + ] + } + }, + { + "Chapter": { + "name": "check", + "content": "# The `check` command\n\nThe check command is the primary subcommand of cargo-deny as it is what actually runs through all of the crates in your project and checks them against your configuration.\n\n## Args\n\n### ``\n\nThe check(s) to perform. By default, **all** checks will be performed, unless one or more checks are specified here.\n\nSee [checks](../checks/index.html) for the list of available checks.\n\n## Options\n\n### `-A, --allow `\n\nSet lint allowed\n\n### `--audit-compatible-output`\n\nTo ease transition from cargo-audit to cargo-deny, this flag will tell cargo-deny to output the exact same output as cargo-audit would, to `stdout` instead of `stderr`, just as with cargo-audit.\n\nNote that this flag only applies when the output format is JSON, and note that since cargo-deny supports multiple advisory databases, instead of a single JSON object, there will be 1 for each unique advisory database.\n\n### `-c, --config `\n\nPath to the config to use\n\nDefaults to `/deny.toml` if not specified\n\n### `-d, --disable-fetch`\n\nDisable fetching of the advisory database\n\nWhen running the `advisories` check, the configured advisory database will be fetched and opened. If this flag is passed, the database won't be fetched, but an error will occur if it doesn't already exist locally.\n\nThis option is also set if the `--offline` flag is used in the global options.\n\n### `--exclude-dev`\n\nIf set to `true`, all `dev-dependencies`, even one for workspace crates, are not included in the crate graph used for any of the checks.\n\n### `-D, --deny `\n\nSet lint denied\n\n### `--feature-depth `\n\nSpecifies the depth at which feature edges are added in inclusion graphs\n\n### `-g, --graph `\n\nPath to graph_output root directory\n\nIf set, a dotviz graph will be created for whenever multiple versions of the same crate are detected.\n\nEach file will be created at `/graph_output/.dot`. `/graph_output/*` is deleted and recreated each run.\n\n### `--hide-inclusion-graph`\n\nHides the inclusion graph when printing out info for a crate\n\nBy default, if a diagnostic message pertains to a specific crate, cargo-deny will append an inverse dependency graph to the diagnostic to show you how that crate was pulled into your project.\n\n```text\nsome diagnostic message\n\nthe-crate\n├── a-crate\n└── b-crate\n └── c-crate\n```\n\n### `-s, --show-stats`\n\nShow stats for all the checks, regardless of the log-level\n\n### `-W, --warn `\n\nSet lint warnings\n\n## Exit Codes\n\nAs of [0.14.1](https://github.com/EmbarkStudios/cargo-deny/releases/tag/0.14.1), the exit code for the check command is a bitset of the checks that were executed and had 1 or more errors.\n\nA script or program can use the following values to determine exactly which check(s) failed.\n\n* `advisories` - `0x1`\n* `bans` - `0x2`\n* `licenses` - `0x4`\n* `sources` - `0x8`\n", + "number": [ + 2, + 3 + ], + "sub_items": [], + "path": "cli/check.md", + "source_path": "cli/check.md", + "parent_names": [ + "Command Line Tool" + ] + } + }, + { + "Chapter": { + "name": "list", + "content": "# The `list` command\n\nSimilarly to [cargo-license](https://github.com/onur/cargo-license), `list` prints out the license information for each crate.\n\n## Options\n\n### `-f, --format`\n\nThe format of the output\n\n* `human` (default) - Simple format where each crate or license is its own line\n* `json`\n* `tsv`\n\n### `--color`\n\nOutput coloring, only applies to the `human` format.\n\n* `auto` (default) - Only colors if stdout is a TTY\n* `always` - Always emits colors\n* `never` - Never emits colors\n\nColors:\n\n* SPDX identifier - ![blue](https://placehold.it/15/5dade2/000000?text=+)\n* Crate with 1 license - ![white](https://placehold.it/15/717d7e/000000?text=+)\n* Crate with 2 or more licenses - ![yellow](https://placehold.it/15/f1c40f/000000?text=+)\n* Crate with 0 licenses - ![yellow](https://placehold.it/15/e74c3c/000000?text=+)\n\n### `-l, --layout`\n\nThe layout of the output. Does not apply to the `tsv` format.\n\n* `license` (default) - Each license acts as the key, and the values are all of the crates that use that license\n* `crate` - Each crate is a key, and the values are the list of licenses it uses.\n\n### `-t, --threshold`\n\nThe confidence threshold required for assigning a license identifier to a license text file. See the [license configuration](../checks/licenses/cfg.md#the-confidence-threshold-field-optional) for more information.\n\n* `layout = license, format = human` (default)\n\n![Imgur](https://i.imgur.com/Iejfc7h.png)\n\n* `layout = crate, format = human`\n\n![Imgur](https://i.imgur.com/zZdcFXI.png)\n\n* `layout = license, format = json`\n\n![Imgur](https://i.imgur.com/wC2R0ym.png)\n\n* `layout = license, format = tsv`\n\n![Imgur](https://i.imgur.com/14l8a5K.png)\n", + "number": [ + 2, + 4 + ], + "sub_items": [], + "path": "cli/list.md", + "source_path": "cli/list.md", + "parent_names": [ + "Command Line Tool" + ] + } + } + ], + "path": "cli/README.md", + "source_path": "cli/README.md", + "parent_names": [] + } + }, + { + "Chapter": { + "name": "Checks", + "content": "# Checks\n\ncargo-deny supports several different classes of checks that can be performed on your project's crate graph. By default, `cargo deny check` will execute **all** of the supported checks, falling back to the default configuration for that check if one is not explicitly specified.\n\n## [licenses](licenses/index.html)\n\nChecks the license information for each crate.\n\n## [bans](bans/index.html)\n\nChecks for specific crates in your graph, as well as duplicates.\n\n## [advisories](advisories/index.html)\n\nChecks advisory databases for crates with security vulnerabilities, or that have been marked as `Unmaintained`, or which have been yanked from their source registry.\n\n## [sources](sources/index.html)\n\nChecks the source location for each crate.\n", + "number": [ + 3 + ], + "sub_items": [ + { + "Chapter": { + "name": "config", + "content": "# config\n\nThe top level config for cargo-deny, by default called `deny.toml`.\n\n## Example - cargo-deny's own configuration\n\n```ini\n{{#include ../../../deny.toml}}\n```\n\n## The `graph` field (optional)\n\nThe graph tables provides configuration options for how the dependency graph that the various checks are executed against is constructed.\n\n```ini\n[graph]\ntargets = [\n \"x86_64-unknown-linux-gnu\",\n { triple = \"aarch64-apple-darwin\" },\n { triple = \"x86_64-pc-windows-msvc\", features = [\"sse2\"] },\n]\nexclude = [\"some-crate@0.1.0\"]\nall-features = true\nno-default-features = false\nfeatures = [\"some-feature\"]\nexclude-dev = true\n```\n\n### The `targets` field (optional)\n\nBy default, cargo-deny will consider every single crate that is resolved by cargo, including target specific dependencies eg\n\n```ini\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is never actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for. Every dependency link to a crate is checked against this list, and if none of the listed targets satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links to it, it is not included into the crate graph that the checks are executed against.\n\n#### The `targets.triple` field (optional) or `\"\"`\n\nThe [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target you wish to filter target specific dependencies with. If the target triple specified is **not** one of the targets builtin to `rustc`, the configuration check for that target will be limited to only the raw `[target..dependencies]` style of target configuration, as `cfg()` expressions require us to know the details about the target.\n\n#### The `targets.features` field (optional)\n\nRust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) predicate, but at the moment, the only way to actually pass them when compiling is to use the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more `target_feature`s you plan to build with, for a particular target triple. At the time of this writing, cargo-deny does not attempt to validate that the features you specify are actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n\n### The `exclude` field (optional)\n\nJust as with the [`--exclude`](../cli/common.md#--exclude) command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) that will cause the crate(s) in question to be excluded from the crate graph that is used for the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced via the excluded crate, they will also be excluded from the crate graph.\n\n### The `all-features` field (optional)\n\nIf set to `true`, `--all-features` will be used when collecting metadata.\n\n### The `no-default-features` field (optional)\n\nIf set to `true`, `--no-default-features` will be used when collecting metadata.\n\n### The `features` field (optional)\n\nIf set, and `--features` is not specified on the cmd line, these features will be used when collecting metadata.\n\n### The `exclude-dev` field (optional)\n\nIf set to `true`, all `dev-dependencies`, even one for workspace crates, are not included in the crate graph used for any of the checks. This option can also be enabled on cmd line with `--exclude-dev` either [before](../cli/common.md#--exclude-dev) or [after](../cli/check.md#--exclude-dev) the `check` subcommand.\n\n## The `output` field (optional)\n\n### The `feature-depth` field (optional)\n\nThe maximum depth that features will be displayed when inclusion graphs are included in diagnostics, unless specified via `--feature-depth` on the command line. Only applies to diagnostics that actually print features. If not specified defaults to `1`.\n\n## Package Specs\n\nMany configuration options require a package specifier at a minimum, which we'll describe here. The options that use package specifiers will be called out in their individual documentation. We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used, which comes in three forms.\n\n#### Simple\n\n```ini\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement used when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```ini\n# Will match only this versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following a `:` separator.\n\n#### Exact\n\n```ini\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@` is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```ini\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses the string format described above in a single `crate` key.\n\n#### Old format\n\n```ini\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" }\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated and should not be used.\n\n## The `[licenses]` section\n\nSee the [licenses config](licenses/cfg.html) for more info.\n\n## The `[bans]` section\n\nSee the [bans config](bans/cfg.html) for more info.\n\n## The `[advisories]` section\n\nSee the [advisories config](advisories/cfg.html) for more info.\n\n## The `[sources]` section\n\nSee the [sources config](sources/cfg.html) for more info.\n", + "number": [ + 3, + 1 + ], + "sub_items": [], + "path": "checks/cfg.md", + "source_path": "checks/cfg.md", + "parent_names": [ + "Checks" + ] + } + }, + { + "Chapter": { + "name": "advisories", + "content": "# advisories\n\nThe advisories check is used to detect issues for crates by looking in an advisory database.\n\n```bash\ncargo deny check advisories\n```\n\n## Use Case - Detecting security vulnerabilities\n\nSecurity vulnerabilities are generally considered \"not great\" by most people, luckily, Rust has a great [advisory database](https://github.com/RustSec/advisory-db) which cargo-deny can use to check that you don't have any crates with (known) security vulnerabilities.\n\nYou can also use your own advisory databases instead of, or in addition to, the above default, as long as it follows the same format.\n\n## Use Case - Detecting unmaintained crates\n\nThe [advisory database](https://github.com/RustSec/advisory-db) also contains advisories for unmaintained crates, which in most cases users will want to avoid in favor of more actively maintained crates.\n\n## Example output\n\n![advisories output](../../output/advisories.svg)\n", + "number": [ + 3, + 2 + ], + "sub_items": [ + { + "Chapter": { + "name": "config", + "content": "# The `[advisories]` section\n\nContains all of the configuration for `cargo deny check advisories`\n\n## Example Config\n\n```ini\n{{#include ../../../../tests/cfg/advisories.toml}}\n```\n\n### The `db-urls` field (optional)\n\nURLs to one or more advisory databases.\n\nDefault: [RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n\n### The `db-path` field (optional)\n\nPath to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html) or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html) if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\nDefault: `$CARGO_HOME/advisory-dbs`\n\n### The `version` field (optional)\n\n```ini\nversion = 2\n```\n\nThe advisories section has an upcoming breaking change, with deprecation warnings for several fields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n\n### The `vulnerability` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n\n- `deny` (default) - Will emit an error with details about each vulnerability, and fail the check.\n- `warn` - Prints a warning for each vulnerability, but does not fail the check.\n- `allow` - Prints a note about the security vulnerability, but does not fail the check.\n\n### The `unmaintained` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n\n- `deny` - Will emit an error with details about the unmaintained advisory, and fail the check.\n- `warn` (default) - Prints a warning for each unmaintained advisory, but does not fail the check.\n- `allow` - Prints a note about the unmaintained advisory, but does not fail the check.\n\n### The `unsound` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n\n- `deny` - Will emit an error with details about the unsound advisory, and fail the check.\n- `warn` (default) - Prints a warning for each unsound advisory, but does not fail the check.\n- `allow` - Prints a note about the unsound advisory, but does not fail the check.\n\n### The `yanked` field (optional)\n\nDetermines what happens when a crate with a version that has been yanked from its source registry is encountered.\n\n- `deny` - Will emit an error with the crate name and version that was yanked, and fail the check.\n- `warn` (default) - Prints a warning with the crate name and version that was yanked, but does not fail the check.\n- `allow` - Prints a note about the yanked crate, but does not fail the check.\n\n### The `notice` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the [RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n\n- `deny` - Will emit an error with details about the notice advisory, and fail the check.\n- `warn` (default) - Prints a warning for each notice advisory, but does not fail the check.\n- `allow` - Prints a note about the notice advisory, but does not fail the check.\n\n### The `ignore` field (optional)\n\n```ini\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. Putting an identifier in this array will cause the advisory to be treated as a note, rather than a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](../cfg.md#package-spec) with an optional `reason`.\n\n### The `severity-threshold` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nThe threshold for security vulnerabilities to be turned into notes instead of warnings or errors, depending upon its [CVSS](https://en.wikipedia.org/wiki/Common_Vulnerability_Scoring_System) score. So having a high threshold means some vulnerabilities might not fail the check, but having a log level `>= info` will mean that a note will be printed instead of a warning or error, depending on `[advisories.vulnerability]`.\n\n- `None` (default) - CVSS Score 0.0\n- `Low` - CVSS Score 0.1 - 3.9\n- `Medium` - CVSS Score 4.0 - 6.9\n- `High` - CVSS Score 7.0 - 8.9\n- `Critical` - CVSS Score 9.0 - 10.0\n\n### The `git-fetch-with-cli` field (optional)\n\nSimilar to cargo's [net.git-fetch-with-cli](https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli), this field allows you to opt-in to fetching advisory databases with the git CLI rather than using `gix`.\n\n- `false` (default) - Fetches advisory databases via `gix`\n- `true` - Fetches advisory databases using `git`. Git must be installed and in `PATH`.\n\n### The `maximum-db-staleness` field (optional)\n\nA duration in RFC3339 format that specifies the maximum amount of time that can pass before the database is considered stale and an error is emitted. This is only checked when advisory database fetching has been disabled via the `--offline` or `check --disable-fetch` flags, as otherwise the database is always cloned or fetched to be up to date with the remote git repository.\n\nThe default if not specified is the same value that `cargo-audit` uses, and `cargo-deny` has been using, which is `P90D`, or 90 days.\n\nThe RFC3339 duration format is...not well documented. The official grammar is as follows:\n\n```txt\n dur-second = 1*DIGIT \"S\"\n dur-minute = 1*DIGIT \"M\" [dur-second]\n dur-hour = 1*DIGIT \"H\" [dur-minute]\n dur-time = \"T\" (dur-hour / dur-minute / dur-second)\n dur-day = 1*DIGIT \"D\"\n dur-week = 1*DIGIT \"W\"\n dur-month = 1*DIGIT \"M\" [dur-day]\n dur-year = 1*DIGIT \"Y\" [dur-month]\n dur-date = (dur-day / dur-month / dur-year) [dur-time]\n\n duration = \"P\" (dur-date / dur-time / dur-week)\n```\n\nHowever, as far as I can tell, there are no official spec compliance tests one can run for the duration formation, and several parsers I found written in other languages seemed to...not actually properly follow the grammar, so the implementation in cargo-deny _may_ be wrong according to the spec, but at least it will be consistently wrong.\n\nNote that while the spec supports `,` as a decimal separator, for simplicity cargo-deny only supports `.` as a decimal separator.\n\nOne final note, there are 2 units available in the format that are not exact, namely, year 'Y' and month 'M'. It's not recommended to use either of them for that reason, but if you do they are calculated as follows.\n\n- 1 year = 365 days\n- 1 month = 30.43 days\n", + "number": [ + 3, + 2, + 1 + ], + "sub_items": [], + "path": "checks/advisories/cfg.md", + "source_path": "checks/advisories/cfg.md", + "parent_names": [ + "Checks", + "advisories" + ] + } + }, + { + "Chapter": { + "name": "diagnostics", + "content": "# Advisories Diagnostics\n\n### `vulnerability`\n\nA [`vulnerability`](cfg.md#the-vulnerability-field-optional) advisory was detected for a crate.\n\n### `notice`\n\nA [`notice`](cfg.md#the-notice-field-optional) advisory was detected for a crate.\n\n### `unmaintained`\n\nAn [`unmaintained`](cfg.md#the-unmaintained-field-optional) advisory was detected for a crate.\n\n### `unsound`\n\nAn [`unsound`](cfg.md#the-unsound-field-optional) advisory was detected for a crate.\n\n### `yanked`\n\nA crate using a version that has been [yanked](cfg.md#the-yanked-field-optional) from the registry index was detected.\n\n### `index-failure`\n\nAn error occurred trying to read or update the registry index (typically crates.io) so cargo-deny was unable to check the current yanked status for any crate.\n\n### `advisory-not-detected`\n\nAn advisory in [`advisories.ignore`](cfg.md#the-ignore-field-optional) didn't apply to any crate. This could happen if the advisory was [withdrawn](https://docs.rs/rustsec/latest/rustsec/advisory/struct.Metadata.html#structfield.withdrawn), or the version of the crate no longer falls within the range of affected versions the advisory applies to.\n\n### `unknown-advisory`\n\nAn advisory in [`advisories.ignore`](cfg.md#the-ignore-field-optional) wasn't found in any of the configured advisory databases, usually indicating a typo, as advisories, at the moment, are never deleted from the database, at least the canonical [advisory-db](https://github.com/rustsec/advisory-db).\n", + "number": [ + 3, + 2, + 2 + ], + "sub_items": [], + "path": "checks/advisories/diags.md", + "source_path": "checks/advisories/diags.md", + "parent_names": [ + "Checks", + "advisories" + ] + } + } + ], + "path": "checks/advisories/README.md", + "source_path": "checks/advisories/README.md", + "parent_names": [ + "Checks" + ] + } + }, + { + "Chapter": { + "name": "bans", + "content": "# bans\n\nThe bans check is used to deny (or allow) specific crates, as well as detect and handle multiple versions of the same crate.\n\n```bash\ncargo deny check bans\n```\n\n## Use Case - Denying specific crates\n\nSometimes, certain crates just don't fit in your project, so you have to remove them. However, nothing really stops them from sneaking back in due to innocuous changes like doing a `cargo update` and getting it transitively, or even forgetting to set `default-features = false, features = [\"feature-without-the-thing\"]` when the crate is pulled in via the default features of a crate you already depend on, in your entire workspace.\n\nFor example, we previously depended on OpenSSL as it is the \"default\" for many crates that provide TLS. This was extremely annoying as it required us to have OpenSSL development libraries installed on Windows, for both individuals and CI. We moved all of our dependencies to use the much more streamlined `native-tls` or `ring` crates instead, and now we can make sure that OpenSSL doesn't return from the grave by accident.\n\n## Use Case - Duplicate version detection\n\nThe larger your project and number of external dependencies, the likelihood that you will have multiple versions of the same crate rises. This is due to two fundamental aspects of the Rust ecosystem.\n\n1. Cargo's dependency resolution tries to solve all the version constraints to a crate to the same version, but is totally ok with using [multiple versions](https://stephencoakley.com/2019/04/24/how-rust-solved-dependency-hell) if it is unable to.\n1. Rust has a huge (ever growing) number of crates. Every maintainer has different amounts of time and energy they can spend on their crate, not to mention different philosophies on dependencies and how often (or not) they should be updated, so it is inevitable that crates will not always agree on which version of another crate they want to use.\n\nThis tradeoff of allowing multiple version of the same crate is one of the reasons that cargo is such a pleasant experience for many people new to Rust, but as with all tradeoffs, it does come with costs.\n\n1. More packages must be **fetched**, which especially impacts CI, as well as devs.\n1. **Compile times** increase, which impacts CI and devs.\n1. **Target directory size** increases, which can impact devs, or static CI environments.\n1. Final **binary size** will also tend to increase, which can impact users.\n\nNormally, you will not really notice that you have multiple versions of the same crate unless you constantly watch your build log, but as mentioned above, it **does** introduce paper cuts into your workflows.\n\nThe intention of duplicate detection in cargo-deny is not to \"correct\" cargo's behavior, but rather to draw your attention to duplicates so that you can make an informed decision about how to handle the situation.\n\n* Maybe you want to open up a PR on a crate to use a version of the duplicate that is aligned with the rest of the ecosystem.\n* Maybe the crate has actually already been updated, but the maintainer hasn't published a new version yet, and you can ask if they can publish a new one.\n* Maybe, even though the versions are supposedly incompatible according to semver, they actually aren't, and you can temporarily patch 1 or more crates to use a different version requirement without actually change the crates' code itself.\n* Sometimes having the \"latest and greatest\" is not really that important for every version, and you can just specify a lower version in your own project that matches the transitive constraint(s).\n* And finally, you don't care about a particular case of multiple versions, so you just tell cargo-deny to ignore one or more of the specific versions, and the situation will eventually resolve itself.\n\n## Example output\n\n![bans output](../../output/bans.svg)\n", + "number": [ + 3, + 3 + ], + "sub_items": [ + { + "Chapter": { + "name": "config", + "content": "# The `[bans]` section\n\nContains all of the configuration for `cargo deny check bans`\n\n## Example Config\n\n```ini\n{{#include ../../../../tests/cfg/bans.toml}}\n```\n\n### The `multiple-versions` field (optional)\n\nDetermines what happens when multiple versions of the same crate are encountered.\n\n* `deny` - Will emit an error for each crate with duplicates and fail the check.\n* `warn` (default) - Prints a warning for each crate with duplicates, but does not fail the check.\n* `allow` - Ignores duplicate versions of the same crate.\n\n### The `multiple-versions-include-dev` field (optional)\n\nIf `true`, `dev-dependencies` are included when checking for multiple versions of crates. By default this is false, and any crates that are only reached via dev dependency edges are ignored when checking for multiple versions. Note that this also means that `skip` and `skip` tree are not used, which may lead to warnings about unused configuration.\n\n### The `wildcards` field (optional)\n\nDetermines what happens when a dependency is specified with the `*` (wildcard) version.\n\n* `deny` - Will emit an error for each crate specified with a wildcard version.\n* `warn` (default) - Prints a warning for each crate with a wildcard version, but does not fail the check.\n* `allow` - Ignores all wildcard version specifications.\n\n### The `allow-wildcard-paths` field (optional)\n\nIf specified, alters how the `wildcard` field behaves:\n\n* [path](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies) or [git](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories) `dependencies` in **private** crates will no longer emit a warning or error.\n* path or git `dev-dependencies` in both public and private crates will no longer emit a warning or error.\n* path or git `dependencies` and `build-dependencies` in **public** crates will continue to produce warnings and errors.\n\nBeing limited to private crates is due to crates.io not allowing packages to be published with `path` or `git` dependencies except for `dev-dependencies`.\n\n### The `highlight` field (optional)\n\nWhen multiple versions of the same crate are encountered and `multiple-versions` is set to `warn` or `deny`, using the `-g ` option will print out a [dotgraph](https://www.graphviz.org/) of each of the versions and how they were included into the graph. This field determines how the graph is colored to help you quickly spot good candidates for removal or updating.\n\n* `lowest-version` - Highlights the path to the lowest duplicate version. Highlighted in ![red](https://placehold.it/15/ff0000/000000?text=+)\n* `simplest-path` - Highlights the path to the duplicate version with the fewest number of total edges to the root of the graph, which will often be the best candidate for removal and/or upgrading. Highlighted in ![blue](https://placehold.it/15/0000FF/000000?text=+).\n* `all` - Highlights both the `lowest-version` and `simplest-path`. If they are the same, they are only highlighted in ![red](https://placehold.it/15/ff0000/000000?text=+).\n\n![Imgur](https://i.imgur.com/xtarzeU.png)\n\n### The `deny` field (optional)\n\n```ini\ndeny = [\"package-spec\"]\n```\n\nDetermines specific crates that are denied. Each entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n#### The `wrappers` field (optional)\n\n```ini\ndeny = [{ crate = \"crate-you-don't-want:<=0.7.0\", wrappers = [\"this-can-use-it\"] }]\n```\n\nThis field allows specific crates to have a direct dependency on the banned crate but denies all transitive dependencies on it.\n\n#### The `deny-multiple-versions` field (optional)\n\n```ini\nmultiple-versions = 'allow'\ndeny = [{ crate = \"crate-you-want-only-one-version-of\", deny-multiple-versions = true }]\n```\n\nThis field allows specific crates to deny multiple versions of themselves, but allowing or warning on multiple versions for all other crates. This field cannot be set simultaneously with `wrappers`.\n\n#### The `deny.reason` field (optional)\n\n```ini\ndeny = [{ crate = \"package-spec\", reason = \"the reason this crate is banned\"}]\n```\n\nThis field provides the reason the crate is banned as a string (eg. a simple message or even a url) that is surfaced in diagnostic output so that the user does not have to waste time digging through history or asking maintainers why this is the case.\n\n#### The `deny.use-instead` field (optional)\n\n```ini\ndeny = [{ crate = \"openssl\", use-instead = \"rustls\"}]\n```\n\nThis is a shorthand for the most common case for banning a particular crate, which is that your project has chosen to use a different crate for that functionality.\n\n### The `allow` field (optional)\n\n```ini\ndeny = [\"package-spec\"]\n```\n\nDetermines specific crates that are allowed. If the `allow` list has one or more entries, then any crate not in that list will be denied, so use with care. Each entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n#### The `allow.reason` field (optional)\n\n```ini\nallow = [{ crate = \"package-spec\", reason = \"the reason this crate is allowed\"}]\n```\n\nThis field provides the reason the crate is allowed as a string (eg. a simple message or even a url) that is surfaced in diagnostic output so that the user does not have to waste time digging through history or asking maintainers why this is the case.\n\n### The `external-default-features` field (optional)\n\nDetermines the lint level used for when the `default` feature is enabled on a crate not in the workspace. This lint level will can then be overridden on a per-crate basis if desired.\n\nFor example, if `an-external-crate` had the `default` feature enabled it could be explicitly allowed.\n\n```ini\n[bans]\nexternal-default-features = \"deny\"\n\n[[bans.features]]\ncrate = \"an-external-crate\"\nallow = [\"default\"]\n```\n\n### The `workspace-default-features` field (optional)\n\nThe workspace version of `external-default-features`.\n\n```ini\n[bans]\nexternal-default-features = \"allow\"\n\n[[bans.features]]\ncrate = \"a-workspace-crate\"\ndeny = [\"default\"]\n```\n\n### The `features` field (optional)\n\n```ini\n[[bans.features]]\ncrate = \"featured-krate:1.0\"\ndeny = [\"bad-feature\"]\nallow = [\"good-feature\"]\nexact = true\n```\n\nAllows specification of crate specific allow/deny lists of features. Each entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n#### The `features.deny` field (optional)\n\nDenies specific features for the crate.\n\n#### The `features.allow` field (optional)\n\nAllows specific features for the crate, enabled features not in this list are denied.\n\n#### The `features.exact` field (optional)\n\nIf specified, requires that the features in `allow` exactly match the features enabled on the crate, and will fail if features are allowed that are not enabled.\n\n### The `skip` field (optional)\n\n```ini\nskip = [\n \"package-spec\",\n { crate = \"package-spec\", reason = \"an old version is used by crate-x, see for updating it\" },\n]\n```\n\nWhen denying duplicate versions, it's often the case that there is a window of time where you must wait for, for example, PRs to be accepted and new version published, before 1 or more duplicates are gone. The `skip` field allows you to temporarily ignore a crate during duplicate detection so that no errors are emitted, until it is no longer need.\n\nIt is recommended to use specific version constraints for crates in the `skip` list, as cargo-deny will emit warnings when any entry in the `skip` list no longer matches a crate in your graph so that you can cleanup your configuration.\n\nEach entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n### The `skip-tree` field (optional)\n\n```ini\nskip-tree = [\n \"windows-sys<=0.52\", # will skip this crate and _all_ direct and transitive dependencies\n { crate = \"windows-sys<=0.52\", reason = \"several crates use the outdated 0.42 and 0.45 versions\" },\n { crate = \"windows-sys<=0.52\", depth = 3, reason = \"several crates use the outdated 0.42 and 0.45 versions\" },\n]\n```\n\nWhen dealing with duplicate versions, it's often the case that a particular crate acts as a nexus point for a cascade effect, by either using bleeding edge versions of certain crates while in alpha or beta, or on the opposite end of the spectrum, a crate is using severely outdated dependencies while much of the rest of the ecosystem has moved to more recent versions. In both cases, it can be quite tedious to explicitly `skip` each transitive dependency pulled in by that crate that clashes with your other dependencies, which is where `skip-tree` comes in.\n\n`skip-tree` entries are similar to `skip` in that they are used to specify a crate name and version range that will be skipped, but they also have an additional `depth` field used to specify how many levels from the crate will also be skipped. A depth of `0` would be the same as specifying the crate in the `skip` field.\n\nNote that by default, the `depth` is infinite.\n\nEach entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n**NOTE:** `skip-tree` is a very big hammer, and should be used with care.\n\n### The `build` field (optional)\n\nThe `build` field contains configuration for raising diagnostics for crates that execute at compile time, either because they have a [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html), or they are a [procedural macro](https://doc.rust-lang.org/reference/procedural-macros.html). The configuration is (currently) focused on diagnostics around specific file types, as configured via extension glob patterns, as well as executables, either native or in the form of [interpreted shebang scripts](https://en.wikipedia.org/wiki/Shebang_(Unix)).\n\nWhile the intention of this configuration is to raise awareness of crates that have or use precompiled binaries or scripts, or otherwise contain file types that you want to be aware of, the compile time crate linting supplied by cargo-deny does **NOT** protect you from actively malicious code.\n\nA quick run down of things that cargo-deny **WILL NOT DETECT**.\n\n* The crate just straight up does bad things like uploading your SSH keys to a remote server using vanilla rust code\n* The crate contains compressed, or otherwise obfuscated executable binaries\n* The build script uses `include!()` for code that is benign in one version, then replaces it with something malicious without triggering a checksum mismatch on the build script contents itself.\n* A build time dependency of a non-malicious crate does any of the above.\n* Tons of other stuff I haven't thought of because I am not a security person\n\nSo all this is to say, `cargo-deny` (currently) is only really useful for analyzing when crates have native executables, and/or the crate maintainers have either forgotten or purposefully left helper scripts for their CI/release management/etc in the crate source that are not actually ever executed automatically.\n\n#### The `allow-build-scripts` field (optional)\n\nSpecifies all the crates that are allowed to have a build script. If this option is omitted, all crates are allowed to have a build script, and if this option is set to an empty list, no crate is allowed to have a build script.\n\n#### The `executables` field (optional)\n\nThis controls how native executables are handled. Note this check is done by actually reading the file headers from disk so that this check works on Windows as well, ie the executable bit is irrelevant.\n\n* `deny` (default) - Emits an error when native executables are detected.\n* `warn` - Prints a warning when native executables are detected, but does not fail the check.\n* `allow` - Prints a note when native executables are detected, but does not fail the check.\n\nThis check currently only handles the major executable formats.\n\n* [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)\n* [PE](https://en.wikipedia.org/wiki/Portable_Executable)\n* [Mach-O](https://en.wikipedia.org/wiki/Mach-O)\n\n#### The `interpreted` field (optional)\n\nThis controls how interpreted scripts are handled. Note this check is done by actually reading the file header from disk so that this check works on Windows as well, ie the executable bit is irrelevant.\n\n* `deny` - Emits an error when interpreted scripts are detected.\n* `warn` - Prints a warning when interpreted scripts are detected, but does not fail the check.\n* `allow` (default) - Prints a note when interpreted scripts are detected, but does not fail the check.\n\n#### The `script-extensions` field (optional)\n\nIf supplied scans crates that execute at compile time for any files with the specified extension(s), emitting an error for every one that matches.\n\n#### The `enable-builtin-globs` field (optional)\n\nIf `true`, enables the builtin glob patterns for common languages that tend to by installed on most developer machines, such as python.\n\n```ini\n{{#include ../../../../src/bans/builtin_globs.toml}}\n```\n\n#### The `include-dependencies` field (optional)\n\nBy default, only the crate that executes at compile time is scanned, but if set to `true`, this field will check this crate as well as all of its dependencies. This option is disabled by default, as this will tend to only find CI scripts that people leave in their published crates.\n\n#### The `include-workspace` field (optional)\n\nIf `true`, workspace crates will also be scanned. This defaults to false as you presumably have some degree of trust for your own code.\n\n#### The `include-archives` field (optional)\n\nIf `true`, archive files (eg. Windows .lib, Unix .a, C++ .o object files etc) are also counted as native code. This defaults to false, as these tend to need to be linked before they can be executed.\n\n#### The `bypass` field (optional)\n\nWhile all the previous configuration is about configuration the global checks that run on compile time crates, the `allow` field is how one can suppress those lints on a crate-by-crate basis.\n\nEach entry uses the same [PackageSpec](../cfg.md#package-specs) as other parts of cargo-deny's configuration.\n\n```ini\n[build.bypass]\ncrate = \"crate-name\"\n```\n\n##### The `build-script` and `required-features` field (optional)\n\nIf set to a valid, 64-character hexadecimal [SHA-256](https://en.wikipedia.org/wiki/SHA-2), the `build-script` field will cause the rest of the scanning to be bypassed _if_ the crate's build script's checksum matches the user specified checksum **AND** none of the features specified in the `required-features` field are enabled. If the checksum does not match, the calculated checksum will be emitted as a warning, and the crate will be scanned as if a checksum was not supplied.\n\n**NOTE:** These options only applies to crate with build scripts, not proc macros, as proc macros do not have a single entry point that can be easily checksummed.\n\n```ini\n[[build.bypass]]\nname = \"crate-name\"\nbuild-script = \"5392f0e58ad06e089462d93304dfe82337acbbefb87a0749a7dc2ed32af04af7\"\n```\n\n##### The `allow-globs` field (optional)\n\nBypasses scanning of files that match one or more of the glob patterns specified. Note that unlike the [`script-extensions`](#the-script-extensions-field-optional) field that applies to all crates, these globs can match anything, not just extensions.\n\n```ini\n[build]\nscript-extensions = [\"cs\"]\n\n[[build.bypass]]\ncrate = \"crate-name\"\nallow-globs = [\n \"scripts/*.cs\",\n]\n```\n\n##### The `bypass.allow` field (optional)\n\nBypasses scanning a single file.\n\n```ini\n[build]\nexecutables = \"deny\"\n\n[[build.bypass]]\ncrate = \"crate-name\"\nallow = [\n { path = \"bin/x86_64-linux\", checksum = \"5392f0e58ad06e089462d93304dfe82337acbbefb87a0749a7dc2ed32af04af7\" }\n]\n```\n\n###### The `path` field\n\nThe path, relative to the crate root, of the file to bypass scanning.\n\n###### The `checksum` field (optional)\n\nThe 64-character hexadecimal [SHA-256](https://en.wikipedia.org/wiki/SHA-2) checksum of the file. If the checksum does not match, an error is emitted.\n", + "number": [ + 3, + 3, + 1 + ], + "sub_items": [], + "path": "checks/bans/cfg.md", + "source_path": "checks/bans/cfg.md", + "parent_names": [ + "Checks", + "bans" + ] + } + }, + { + "Chapter": { + "name": "diagnostics", + "content": "# Bans diagnostics\n\n### `banned`\n\nA crate which is [explicitly banned](cfg.md#the-allow-and-deny-fields-optional) was detected.\n\n### `allowed`\n\nA crate which is [explicitly allowed](cfg.md#the-allow-and-deny-fields-optional) was detected.\n\n### `not-allowed`\n\nWhen using [`bans.allow`](cfg.md#the-allow-and-deny-fields-optional), a crate was detected that wasn't in that list.\n\n### `duplicate`\n\nOne or more [duplicate versions](cfg.md#the-multiple-versions-field-optional) of the same crate were detected.\n\n### `skipped`\n\nA crate version that matched an entry in [`bans.skip`](cfg.md#the-skip-field-optional) was encountered.\n\n### `wildcard`\n\nA crate was included via a [wildcard dependency](cfg.md#the-wildcards-field-optional) by one or more crates.\n\n### `unmatched-skip`\n\nA crate version in [`bans.skip`](cfg.md#the-skip-field-optional) was not encountered.\n\n### `allowed-by-wrapper`\n\nA crate in `bans.deny` was allowed since it was directly depended on by a [`wrappers`](cfg.md#the-wrappers-field-optional) crate.\n\n### `unmatched-wrapper`\n\nA crate in `bans.deny` had one or more [`wrappers`](cfg.md#the-wrappers-field-optional) crates, but a crate not in that list had a direct dependency on the banned crate.\n\n### `skipped-by-root`\n\nA crate was skipped from being checked as a duplicate due to being transitively referenced by a crate version in [`bans.skip-tree`](cfg.md#the-skip-tree-field-optional).\n\n### `unmatched-root`\n\nA crate version in [`bans.skip-tree`](cfg.md#the-skip-tree-field-optional) was not encountered.\n\n### `build-script-not-allowed`\n\nA crate which has been denied because it has a build script but is not part of the [`bans.allow-build-script`](cfg.md#the-allow-build-scripts-field-optional) list.\n\n### `exact-features-mismatch`\n\nA crate's features do not exactly match the configured feature set, and [`bans.features.exact`](cfg.md#the-features-exact-field-optional) is `true`.\n\n### `feature-banned`\n\nAn enabled crate feature is present in the [`bans.features.deny`](cfg.md#the-features-deny-field-optional) list.\n\n### `unknown-feature`\n\nA feature in either [`bans.features.deny`](cfg.md#the-features-deny-field-optional) or [`bans.features.allow`](cfg.md#the-features-allow-field-optional) does not exist for the crate.\n\n### `default-feature-enabled`\n\nThe `default` feature was enabled on a crate, and the [`bans.external-default-features`](cfg.md#the-external-default-features-field-optional) or [`bans.workspace-default-features`](cfg.md#the-workspace-default-features-field-optional) was configured.\n\n### `path-bypassed`\n\nA path specified by [`bans.build.bypass.allow.path`](cfg.md#the-path-field) was bypassed, optionally ensuring its contents matched a SHA-256 checksum.\n\n### `path-bypassed-by-glob`\n\nA path was bypassed due to matching one or more [glob patterns](cfg.md#the-allow-globs-field-optional).\n\n### `checksum-match`\n\nThe SHA-256 checksum calculated for the contents of a file matched the checksum in the configuration.\n\n### `checksum-mismatch`\n\nThe SHA-256 checksum calculated for the contents of a file did not match the checksum in the configuration.\n\n### `denied-by-extension`\n\nThe file extension matched either a [user specified](cfg.md#the-script-extensions-field-optional) or [builtin](cfg.md#the-enable-builtin-globs-field-optional) extension.\n\n### `detected-executable`\n\nA [native executable](cfg.md#the-executables-field-optional) was detected.\n\n### `detected-executable-script`\n\nAn [interpreted script](cfg.md#the-interpreted-field-optional) was detected.\n\n### `unable-to-check-path`\n\nAn I/O error occurred when opening or reading a file from disk.\n\n### `features-enabled`\n\nOne or more [`required-features`](cfg.md#the-build-script-and-required-features-field-optional) were enabled, causing the [`build-script`](cfg.md#the-build-script-and-required-features-field-optional) bypass to be ignored.\n\n### `unmatched-bypass`\n\nA [crate bypass](cfg.md#the-bypass-field-optional) did not match any crate in the graph.\n\n### `unmatched-path-bypass`\n\nA [path bypass](cfg.md#the-bypassallow-field-optional) did not match a file in the crate.\n\n### `unmatched-glob`\n\nA [glob bypass](cfg.md#the-allow-globs-field-optional) did not match any files in the crate.\n", + "number": [ + 3, + 3, + 2 + ], + "sub_items": [], + "path": "checks/bans/diags.md", + "source_path": "checks/bans/diags.md", + "parent_names": [ + "Checks", + "bans" + ] + } + } + ], + "path": "checks/bans/README.md", + "source_path": "checks/bans/README.md", + "parent_names": [ + "Checks" + ] + } + }, + { + "Chapter": { + "name": "licenses", + "content": "# licenses\n\nThe licenses check is used to verify that every crate you use has license terms you find acceptable. cargo-deny does this by evaluating the license requirements specified by each crate against the [configuration](cfg.md) you've specified, to determine if your project meets that crate's license requirements.\n\n```bash\ncargo deny check licenses\n```\n\n## SPDX\n\ncargo-deny uses [SPDX license expressions][SPDX] to interpret the license requirements of a crate. In the event that it cannot obtain an SPDX license expression directly from metadata, it tries to\nderive such within the confidence threshold you specify. Note that cargo-deny currently does **not** exhaustively search the entirety of the source code of every crate to find every possible license that could be attributed to the crate. There are many edge cases to that approach, and human ingenuity, or even human error, can always outwit a statically-compiled program.\n\ncargo-deny makes a good-faith assumption each crate correctly defines its license requirements. In the (in our experience, rare) circumstance such data cannot be gathered automatically, it provides a mechanism for manually specifying the license requirements for crates.\n\n### Expression Source Precedence\n\nThe source of the SPDX expression used to evaluate the crate's licensing requirement is obtained in the following order:\n\n1. If the crate in question has a [Clarification](cfg.md#the-clarify-field-optional) applied to it, and the source file(s) in the crate's source still match, the expression from the clarification will be used.\n1. The [`license`][cargo-md] field from the crate's Cargo.toml manifest will be used if it exists.\n1. The [`license-file`][cargo-md] field, as well as **all** other `LICENSE(-*)?` files will be parsed to determine the SPDX license identifier, and then all of those identifiers will be joined with the `AND` operator, meaning that you must accept **all** of the licenses detected.\n\n*Importantly*, this precedence, combined with the trust that licensing data is handled correctly, means the following edge cases are **not** handled. This is not an exhaustive list, but are rather a sample of the kinds of things a program is not able to completely prevent, even if more checks are added:\n\n1. **Absences**: If the package contains inadequate licensing data, in e.g. the event of a crate not reflecting the license of code it is linked with.\n1. **Mismatches:** If the Cargo.toml documents a given SPDX expression that does not match the actual license files in the package, this is not checked.\n1. **Inventiveness**: It is possible to place licensing data somewhere that is not in these locations, or have names that start with things other than `LICENSE`. There is no guarantee such placements inside a package would lose their legal force, even if there is other licensing data that cargo-deny may detect first and assume is comprehensive.\n\n### Evaluation Precedence\n\nCurrently, the precedence for determining whether a particular license is accepted or rejected is as follows:\n\n1. A license specified in the `deny` list is **always rejected**.\n1. A license specified in the `allow` list is **always accepted**.\n1. If the license is considered [copyleft](https://en.wikipedia.org/wiki/Copyleft), the\n[`[licenses.copyleft]`](cfg.md#the-copyleft-field-optional) configuration determines its status\n1. If the license is [OSI Approved](https://opensource.org/licenses) or [FSF Free/Libre](https://www.gnu.org/licenses/license-list.en.html), the [`[licenses.allow-osi-fsf-free]`](cfg.md#the-allow-osi-fsf-free-field-optional) configuration determines its status, if it is `neither` the check continues\n1. If the license does not match any of the above criteria, the [`[licenses.default]`](cfg.md#the-default-field-optional) configuration determines its status\n\n## Example output\n\n![licenses output](../../output/licenses.svg)\n\n[SPDX]: https://spdx.github.io/spdx-spec/appendix-IV-SPDX-license-expressions/\n[cargo-md]: https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata\n", + "number": [ + 3, + 4 + ], + "sub_items": [ + { + "Chapter": { + "name": "config", + "content": "# The `[licenses]` section\n\nContains all of the configuration for `cargo deny check license`.\n\n## Example\n\n```ini\n{{#include ../../../../tests/cfg/licenses.toml}}\n```\n\n## SPDX Identifiers\n\nAll identifiers used in the license configuration section are expected to be valid SPDX v2.1 short identifiers, either from version 3.11 of the [SPDX License List](https://spdx.org/licenses/), or use a [custom identifier](https://spdx.github.io/spdx-spec/appendix-V-using-SPDX-short-identifiers-in-source-files/#format-for-spdx-license-identifier) by prefixing it with `LicenseRef-`.\n\n```ini\nallow = [\n # The Apache license identifier\n \"Apache-2.0\",\n # A custom license identifier\n \"LicenseRef-Embark-Custom\",\n]\n\n# Custom license refs can be specified for crates which don't use a license\n# in the SPDX list\n[[licenses.clarify]]\ncrate = \"a-crate\"\nexpression = \"LicenseRef-Embark-Custom\"\nlicense-files = [\n { path = \"LICENSE\", hash = 0x001c7e6c },\n]\n```\n\nLicense identifiers can also be coupled with an optional [exception](https://spdx.org/licenses/exceptions-index.html) by appending `WITH ` to the license identifier. Licenses coupled with exceptions are considered distinct from the same license without the exception.\n\n```ini\nallow = [\n # The Apache license identifier\n \"Apache-2.0\",\n # The Apache license + LLVM-exception\n \"Apache-2.0 WITH LLVM-exception\",\n]\n```\n\n### The `include-dev` field (optional)\n\nIf `true`, licenses are checked even for `dev-dependencies`. By default this is false as `dev-dependencies` are not used by downstream crates, nor part of binary artifacts.\n\n### The `version` field (optional)\n\n```ini\nversion = 2\n```\n\nThe licenses section has an upcoming breaking change, with deprecation warnings for several fields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `unlicensed` - Removed, if a crate is unlicensed you should open an issue/PR to fix it, and in the meantime, you may add a [clarification](#the-clarify-field-optional).\n- `deny` - Removed, all licenses are denied unless explicitly allowed\n- `copyleft` - Removed, all licenses are denied unless explicitly allowed\n- `allow-osi-fsf-free` - Removed, all licenses are denied unless explicitly allowed\n- `default` - Removed, all licenses are denied unless explicitly allowed\n\n### The `unlicensed` field (optional)\n\nDetermines what happens when a crate has not explicitly specified its license terms, and no license information could be confidently detected via `LICENSE*` files in the crate's source.\n\n- `deny` (default) - All unlicensed crates will emit an error and fail the license check\n- `allow` - All unlicensed crates will show a note, but will not fail the license check\n- `warn` - All unlicensed crates will show a warning, but will not fail the license check\n\n### The `allow` and `deny` fields (optional)\n\nThe licenses that should be allowed or denied, note that the same license cannot\nappear in both the `allow` and `deny` lists.\n\n[`deny` is **DEPRECATED**](#the-version-field-optional)\n\n#### Note on GNU licenses\n\n- GPL\n- AGPL\n- LGPL\n- GFDL\n\nThe GNU licenses are, of course, different from all the other licenses in the SPDX list which makes them annoying to deal with. When supplying one of the above licenses, to either `allow` or `deny`, you **must not** use the suffixes `-only` or `-or-later`, as they can only be used by the license holder themselves to decide under which terms to license their code.\n\nSo, for example, if you wanted to disallow `GPL-2.0` licenses, but allow `GPL-3.0` licenses, you could use the following configuration.\n\n```ini\n[licenses]\nallow = [ \"GPL-3.0\" ]\ndeny = [ \"GPL-2.0\" ]\n```\n\nThis gets worse with the GFDL licenses, which also have an `invariants` modifier. Before licenses are checked they are normalized to make them consistent for all licenses.\n\nLet's use [`GFDL-1.2`](https://spdx.org/licenses/GFDL-1.2-only.html) to show how license requirements are normalized.\n\n- `GFDL-1.2-invariants-only` => `GFDL-1.2-invariants`\n- `GFDL-1.2-invariants-or-later` => `GFDL-1.2-invariants+`\n- `GFDL-1.2-no-invariants-only` => `GFDL-1.2`\n- `GFDL-1.2-no-invariants-or-later` => `GFDL-1.2+`\n- `GFDL-1.2-only` => `GFDL-1.2`\n- `GFDL-1.2-or-later` => `GFDL-1.2+`\n\nSo, for example, if you wanted to allow all version (1.1, 1.2, and 1.3), but only invariants for 1.3 you could use the following configuration.\n\n```ini\n[licenses]\nallow = [ \"GFDL-1.1\", \"GFDL-1.2\", \"GFDL-1.3\", \"GFDL-1.3-variants\"]\n```\n\n### The `exceptions` field (optional)\n\nThe license configuration generally applies to the entire crate graph, but this means that allowing any one license applies to all possible crates, even if only 1 crate actually uses that license. The `exceptions` field is meant to allow additional licenses only for particular crates, to make a clear distinction between licenses which you are fine with everywhere, versus ones which you want to be more selective about, and not have implicitly allowed in the future.\n\nThis field uses [PackageSpecs](../cfg.md#package-specs) to select the crate the exception applies to.\n\n### Additional exceptions configuration file\n\nIn some cases it's useful to have global cargo-deny config and project-local exceptions. This can be accomplished with a project exceptions file in any of these locations relative to your top level `Cargo.toml` manifest file.\n\n`cargo-deny` will look for the following files: `/deny.exceptions.toml`, `/.deny.exceptions.toml` and `/.cargo/deny.exceptions.toml`\n\nOnly the exceptions field should be set:\n\n```ini\nexceptions = [\n # Each entry is the crate and version constraint, and its specific allow list.\n { allow = [\"CDDL-1.0\"], crate = \"inferno\" },\n]\n```\n\n#### The `allow` field\n\nThis is the exact same as the general `allow` field.\n\n```ini\n[licenses]\nallow = [\n \"Apache-2.0\",\n \"MIT\",\n]\nexceptions = [\n # This is the only crate that cannot be licensed with either Apache-2.0\n # or MIT, so we just add an exception for it, meaning we'll get a warning\n # if we add another crate that also requires this license\n { crate = \"cloudabi\", allow = [\"BSD-2-Clause\"] },\n]\n```\n\n### The `copyleft` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a license that is considered [copyleft](https://www.gnu.org/licenses/license-list.html) is encountered.\n\n- `warn` (default) - Will emit a warning that a copyleft license was detected, but will not fail the license check\n- `deny` - The license is not accepted if it is copyleft, but the license check might not fail if the expression still evaluates to true\n- `allow` - The license is accepted if it is copyleft\n\n### The `allow-osi-fsf-free` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when licenses aren't explicitly allowed or denied, but **are** marked as [OSI Approved](https://opensource.org/licenses) or [FSF Free/Libre](https://www.gnu.org/licenses/license-list.en.html) in version 3.23 of the [SPDX License List](https://spdx.org/licenses/).\n\n- `both` - The license is accepted if it is both OSI approved and FSF Free\n- `either` - The license is accepted if it is either OSI approved or FSF Free\n- `osi` - The license is accepted if it is OSI approved\n- `fsf` - The license is accepted if it is FSF Free\n- `osi-only` - The license is accepted if it is OSI approved and not FSF Free\n- `fsf-only` - The license is accepted if it is FSF Free and not OSI approved\n- `neither` (default) - No special consideration is given the license\n\n### The `default` field (optional)\n\n[**DEPRECATED**](#the-version-field-optional)\n\nDetermines what happens when a license is encountered that:\n\n1. Isn't in the `allow` or `deny` lists\n1. Isn't `copyleft`\n1. Isn't OSI Approved nor FSF Free/Libre, or `allow-osi-fsf-free = \"neither\"`\n\n- `warn` - Will emit a warning that the license was detected, but will not fail the license check\n- `deny` (default) - The license is not accepted, but the license check might not fail if the expression still evaluates to true\n- `allow` - The license is accepted\n\n### The `confidence-threshold` field (optional)\n\n`cargo-deny` uses [askalono](https://github.com/amzn/askalono) to determine the license of a LICENSE file. Due to variability in license texts because of things like authors, copyright year, and so forth, askalano assigns a confidence score to its determination, from `0.0` (no confidence) to `1.0` (perfect match). The confidence threshold value is used to reject the license determination if the score does not match or exceed the threshold.\n\n`0.0` - `1.0` (default `0.8`)\n\n### The `clarify` field (optional)\n\nIn some exceptional cases, a crate will not have easily machine readable license information, and would by default be considered \"unlicensed\" by cargo-deny. As a (hopefully) temporary patch for using the crate, you can specify a clarification for the crate by manually assigning its SPDX expression, based on one or more files in the crate's source. cargo-deny will use that expression for as long as the source files in the crate exactly match the clarification's hashes.\n\nThis field uses [PackageSpecs](../cfg.md#package-specs) to select the crate the clarification applies to.\n\n```ini\n[[licenses.clarify]]\ncrate = \"webpki\"\nexpression = \"ISC\"\nlicense-files = [\n { path = \"LICENSE\", hash = 0x001c7e6c },\n]\n```\n\n#### The `expression` field\n\nThe [SPDX license expression][SPDX-expr] you are specifying as the license requirements for the crate.\n\n#### The `license-files` field\n\nContains one or more files that will be checked to ensure the license expression still applies to a version of the crate.\n\n##### The `path` field\n\nThe crate relative path to a file to be used as a source of truth.\n\n##### The `hash` field\n\nAn opaque hash calculated from the file contents. This hash can be obtained from the output of the license check when cargo-deny can't determine the license of the file in question.\n\n### The `private` field (optional)\n\nIt's often not useful or wanted to check for licenses in your own private workspace crates. So the private field allows you to do so.\n\n#### The `ignore` field\n\nIf `true`, workspace members will not have their license expression checked if they are not published.\n\n```ini\n# Cargo.toml\n[package]\nname = \"sekret\"\nlicense = \"¯\\_(ツ)_/¯\"\npublish = false # \"private\"!\n```\n\n```ini\n# deny.toml\n[licenses]\n# The sekret package would be ignored now\nprivate = { ignore = true }\n```\n\n### The `registries` field\n\nA list of private registries you may publish your workspace crates to. If a workspace member **only** publishes to private registries, it will also be ignored if `private.ignore = true`\n\n```ini\n# Cargo.toml\n[package]\nname = \"sekret\"\nlicense = \"¯\\_(ツ)_/¯\"\npublish = [\"sauce\"]\n```\n\n```ini\n# deny.toml\n[licenses]\n# Still ignored!\nprivate = { ignore = true, registries = [\"sauce\"] }\n```\n\n### The `ignore-sources` field\n\nA list of registries that crates can be sourced from that will not have their licenses checked.\n\n```ini\n# deny.toml\n[licenses.private]\nignore = true\nignore-sources = [\"https://sekretz.com/super/secret-index\"]\n```\n\n[SPDX-expr]: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/\n\n### The `unused-allowed-license` field (optional)\n\nDetermines what happens when one of the licenses that appears in the `allow` list is not encountered in the dependency graph.\n\n- `warn` (default) - A warning is emitted for each license that appears in `license.allow` but which is not used in any crate.\n- `allow` - Unused licenses in the `licenses.allow` list are ignored.\n- `deny` - An unused license in the `licenses.allow` list triggers an error, and cause the license check to fail.\n", + "number": [ + 3, + 4, + 1 + ], + "sub_items": [], + "path": "checks/licenses/cfg.md", + "source_path": "checks/licenses/cfg.md", + "parent_names": [ + "Checks", + "licenses" + ] + } + }, + { + "Chapter": { + "name": "diagnostics", + "content": "# Licenses Diagnostics\n\n### `rejected`\n\nOne or more licenses for a crate were rejected because they were not configured to be [allowed](cfg.md#the-allow-and-deny-fields-optional).\n\n### `accepted`\n\nThe license expression for a crate was [allowed](cfg.md#the-allow-and-deny-fields-optional), though there may be warnings.\n\n### `unlicensed`\n\nNo license expression could be found for a crate and it is considered [unlicensed](cfg.md#the-unlicensed-field-optional).\n\n### `skipped-private-workspace-crate`\n\nA workspace member is `publish = false` and was [skipped](cfg.md#the-private-field-optional).\n\n### `license-not-encountered`\n\nA license in [`licenses.allow`](cfg.md#the-allow-and-deny-fields-optional) was not found in any crate.\n\nThis diagnostic can be silenced by configuring the [`licenses.unused-allowed-license`](cfg.md#the-unused-allowed-license-field-optional) field to \"allow\".\n\n### `license-exception-not-encountered`\n\nA [`licenses.exception`](cfg.md#the-exceptions-field-optional) was not used as the crate it applied to was not encountered.\n", + "number": [ + 3, + 4, + 2 + ], + "sub_items": [], + "path": "checks/licenses/diags.md", + "source_path": "checks/licenses/diags.md", + "parent_names": [ + "Checks", + "licenses" + ] + } + } + ], + "path": "checks/licenses/README.md", + "source_path": "checks/licenses/README.md", + "parent_names": [ + "Checks" + ] + } + }, + { + "Chapter": { + "name": "sources", + "content": "# sources\n\nThe sources check ensures crates only come from sources you trust.\n\n```bash\ncargo deny check sources\n```\n\n## Use Case - Only allowing known/trusted sources\n\nCargo can retrieve crates from a variety of sources, namely registries, git repositories, or local file paths. This is great in general and very flexible for development. But, especially when re-routing dependencies to git repositories, increasing the amount of sources that a project has to trust may be something a repository wants to explicitly opt-in to.\n\nSee [Why npm lockfiles can be a security blindspot for injecting malicious modules](https://snyk.io/blog/why-npm-lockfiles-can-be-a-security-blindspot-for-injecting-malicious-modules/) for the motivating reason for why this check was added.\n\n## Use Case - Only using vendored file dependencies\n\nA project may want to only support local file dependencies, such as having all dependencies vendored into the repository for full control and offline building. This can be achieved by disallowing all git and registry sources to ensure that every dependency is added into your source control rather than via an external source.\n\n## Example output\n\n![sources output](../../output/sources.svg)\n", + "number": [ + 3, + 5 + ], + "sub_items": [ + { + "Chapter": { + "name": "config", + "content": "# The `[sources]` section\n\nContains all of the configuration for `cargo deny check sources`\n\n## Example Config\n\n```ini\n{{#include ../../../../tests/cfg/sources.toml}}\n```\n\n### The `unknown-registry` field (optional)\n\nDetermines what happens when a crate from a crate registry that is not in the `allow-registry` list is encountered.\n\n* `deny` - Will emit an error with the URL of the source, and fail the check.\n* `warn` (default) - Prints a warning for each crate, but does not fail the check.\n* `allow` - Prints a note for each crate, but does not fail the check.\n\n### The `unknown-git` field (optional)\n\nDetermines what happens when a crate from a git repository not in the `allow-git` list is encountered.\n\n* `deny` - Will emit an error with the URL of the repository, and fail the check.\n* `warn` (default) - Prints a warning for each crate, but does not fail the check.\n* `allow` - Prints a note for each crate, but does not fail the check.\n\n### The `required-git-spec` (optional)\n\nDetermines which [specifiers](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories) are required for git sources. Git sources are a convenient way to use patched code temporarily, but they have downsides for long term maintenance, as the specifier you use for the source determines what happens when you do a `cargo update`, and in the default case, this means you essentially have a wildcard dependency on the repository.\n\nThis configuration value allows you to control what specifiers you want to allow for your git sources to reduce surprises. The following values are listed in order from least to most specific, and using a less specific specifier will also allow all of the more specific ones.\n\n* `any` (default) - Allows all git specs, including the default of not having\nany specifier, which tracks the latest commit on the `master` branch of the repo\n* `branch` - Allows the `branch = \"\"` specifier.\n* `tag` - Allows the `tag = \"\"` specifier.\n* `rev` - Allows the `rev = \"\"` specifier.\n\n### The `allow-git` field (optional)\n\nConfigure which git urls are allowed for crate sources. If a crate's source is not in one of the listed urls, then the `unknown-git` setting will determine how it is handled. Note that the url must match exactly, though `.git` is stripped if it exists to match the logic of cargo.\n\n```ini\n[sources]\nallow-git = [\n \"https://github.com/EmbarkStudios/cargo-deny\",\n]\n```\n\n### The `private` field (optional)\n\nSimilarly to `allow-git`, allows you to configure urls, however, unlike `allow-git` which is meant for a single, exact, url, `private` urls actually allow _any_ git repo url which matches the host and begins with the same path. This field is primarily meant to support the use of internal/private git hosts (usually on a VPN) without needing to specify each individual repo. Of course, this can be used to also just allow every repo on Github, but this is not recommended. 😉\n\n```ini\n[sources]\nprivate = [\n \"https://super-duper-sekret\",\n]\n```\n\n### The `allow-registry` field (optional)\n\nThe list of registries that are allowed. If a crate is not found in one of the listed registries, then the `unknown-registry` setting will determine how it is handled.\n\nIf not specified, this list will by default contain the [crates.io](http://crates.io) registry, equivalent to this:\n\n```ini\n[sources]\nallow-registry = [\n \"https://github.com/rust-lang/crates.io-index\",\n]\n```\n\nTo not allow any crates registries, set it to empty:\n\n```ini\n[sources]\nunknown-registry = \"deny\"\nallow-registry = []\n```\n\n### The `allow-org` field (optional)\n\nGenerally, I think most projects in the Rust space probably follow a similar procedure as we do when they want to fix a bug or add a feature to one of their dependencies, which is basically.\n\n1. Fork the crate to make your changes\n1. Hack away locally, probably just patching your project(s) to use a `path` dependency to the cloned fork\n1. Push changes to your fork, and once you're happy, change the `path` dependency to a `git` dependency and point it to your fork for others/CI to be able to use the same changes easily\n1. Eventually (hopefully!) make a PR to the original repo with your changes\n1. Hopefully get your changes merged to the original repo\n1. Wait until a release is made that incorporates your changes, possibly changing the `git` source to point to the original repo\n1. Remove the `git` source and instead point at the new version of the crate with your changes\n1. Profit!\n\nWhen working in a company or organization, it is often the case that all crates will be forked to a shared organization account rather than a personal Github account. However, if you lint your git sources, every new and deleted fork needs to keep that list updated, which is tedious, even if all the forks fall under the same organization (in Github terminology), even though presumably only people you trust have permission to create forks there, and you would like to just blanket trust any repo under that org.\n\nThe `allow-org` object allows you to specify 1 or more organizations or users in several VCS providers to more easily configure git sources for your projects.\n\n#### The `github` field (optional)\n\nAllows you to specify one or more `github.com` organizations to allow as git sources.\n\n```ini\n[sources.allow-org]\ngithub = [\"YourCoolOrgGoesHere\"]\n```\n\n#### The `gitlab` field (optional)\n\nAllows you to specify one or more `gitlab.com` organizations to allow as git sources.\n\n```ini\n[sources.allow-org]\ngitlab = [\"YourCoolOrgGoesHere\"]\n```\n\n#### The `bitbucket` field (optional)\n\nAllows you to specify one or more `bitbucket.org` organizations to allow as git sources.\n\n```ini\n[sources.allow-org]\nbitbucket = [\"YourCoolOrgGoesHere\"]\n```\n", + "number": [ + 3, + 5, + 1 + ], + "sub_items": [], + "path": "checks/sources/cfg.md", + "source_path": "checks/sources/cfg.md", + "parent_names": [ + "Checks", + "sources" + ] + } + }, + { + "Chapter": { + "name": "diagnostics", + "content": "# Sources diagnostics\n\n### `git-source-underspecified`\n\nA `git` source uses a specification that doesn't meet the minimum specifier required by [`sources.required-git-spec`](cfg.md#the-required-git-spec-optional).\n\n### `allowed-source`\n\nA crate source is explicitly allowed by [`sources.allow-git`](cfg.md#the-allow-git-field-optional) or [`sources.allow-registry`](cfg.md#the-allow-registry-field-optional).\n\n### `allowed-by-organization`\n\nA crate source was explicitly allowed by an entry in [`sources.allow-org`](cfg.md#the-allow-org-field-optional).\n\n### `source-not-allowed`\n\nA crate's source was not explicitly allowed.\n\n### `unmatched-source`\n\nAn allowed source in [`sources.allow-git`](cfg.md#the-allow-git-field-optional) or [`sources.allow-registry`](cfg.md#the-allow-registry-field-optional) was not encountered.\n\n### `unmatched-organization`\n\nAn allowed source in [`sources.allow-org`](cfg.md#the-allow-org-field-optional) was not encountered.\n", + "number": [ + 3, + 5, + 2 + ], + "sub_items": [], + "path": "checks/sources/diags.md", + "source_path": "checks/sources/diags.md", + "parent_names": [ + "Checks", + "sources" + ] + } + } + ], + "path": "checks/sources/README.md", + "source_path": "checks/sources/README.md", + "parent_names": [ + "Checks" + ] + } + } + ], + "path": "checks/README.md", + "source_path": "checks/README.md", + "parent_names": [] + } + }, + { + "Chapter": { + "name": "Config file", + "content": "# Root\n\n**Type:** `object`", + "number": [ + 4 + ], + "sub_items": [ + { + "Chapter": { + "name": "", + "content": "# Root\n\n**Type:** `object`\n\nConfiguration file for cargo-deny, by default called `deny.toml`.\n\nFull documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html\n\n## `advisories`\n\n**Type:** `object`
\n**Key:** `optional`\n\n## `bans`\n\n**Type:** `object`
\n**Key:** `optional`\n\n## `graph`\n\n**Type:** `object`
\n**Key:** `optional`\n\n## `output`\n\n**Type:** `object`
\n**Key:** `optional`", + "number": [ + 4, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories", + "content": "# `advisories`\n\n**Type:** `object`
\n**Key:** `optional`\n\nChecks advisory databases for crates with security vulnerabilities,\nor that have been marked as unmaintained, or which have been yanked from\ntheir source registry.\n\nThis section is considered when running `cargo deny check advisories`.\n\n\n## Example\n\n```toml\n[advisories]\ndb-path = \"~/.cargo/advisory-dbs\"\ndb-urls = [\"https://github.com/RustSec/advisory-db\"]\nvulnerability = \"deny\"\nunmaintained = \"warn\"\nunsound = \"warn\"\nyanked = \"warn\"\nnotice = \"warn\"\nignore = [\n \"RUSTSEC-0000-0000\",\n \"crate@0.1\",\n { crate = \"yanked\", reason = \"a new version has not been released\" },\n]\nseverity-threshold = \"medium\"\n```\n\n## `db-urls`\n\n**Type:** `array`
\n**Key:** `optional`\n\n## `db-path`\n\n**Type:** `string`
\n**Key:** `optional`\n\n## `version`\n\n**Type:** `integer (enum)`
\n**Key:** `optional`\n\n## `vulnerability`\n\n**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
\n**Key:** `optional`\n\n**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a security vulnerability is encountered.\n\n\n### Default\n\n```toml\n[advisories]\nvulnerability = \"deny\"\n```\n\n## `unmaintained`\n\n**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
\n**Key:** `optional`\n\n**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unmaintained` advisory is encountered.\n\n\n### Default\n\n```toml\n[advisories]\nunmaintained = \"warn\"\n```\n\n## `unsound`\n\n**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
\n**Key:** `optional`\n\n**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with an `unsound` advisory is encountered.\n\n\n### Default\n\n```toml\n[advisories]\nunsound = \"warn\"\n```\n\n## `notice`\n\n**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
\n**Key:** `optional`\n\n**DEPRECATED** (see `version` field)\n\nDetermines what happens when a crate with a `notice` advisory is encountered.\n\n**NOTE**: As of 2019-12-17 there are no `notice` advisories in the\n[RustSec Advisory DB](https://github.com/RustSec/advisory-db)\n\n\n### Default\n\n```toml\n[advisories]\nnotice = \"warn\"\n```\n\n## `yanked`\n\n**Type:** [`LintLevel`](/checks2/schema/type-index/LintLevel.md) `string (enum)`
\n**Key:** `optional`\n\nDetermines what happens when a crate with a version that has been yanked from its source\nregistry is encountered.\n\n\n### Default\n\n```toml\n[advisories]\nyanked = \"warn\"\n```\n\n## `ignore`\n\n**Type:** `array`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories.db-urls", + "content": "# `db-urls`\n\n**Type:** `array`
\n**Key:** `optional`\n\nURLs to one or more advisory databases.\n\n## Default\n\n```toml\n[advisories]\ndb-urls = [\"https://github.com/RustSec/advisory-db\"]\n```\n\n## `[N]`\n\n**Type:** `string (uri)`", + "number": [ + 4, + 0, + 0, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories.db-urls[N]", + "content": "# `[N]`\n\n**Type:** `string (uri)`", + "number": [ + 4, + 0, + 0, + 0, + 0 + ], + "sub_items": [], + "path": "advisories-db-urls-N-", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.db-urls", + "advisories.db-urls[N]" + ] + } + } + ], + "path": "advisories-db-urls", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.db-urls" + ] + } + }, + { + "Chapter": { + "name": "advisories.db-path", + "content": "# `db-path`\n\n**Type:** `string`
\n**Key:** `optional`\n\nPath to the root directory into which one or more advisory databases are cloned into.\n\nThis value supports basic shell expansion:\n\n- `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html)\n- `$VARNAME` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n- `${VARNAME:-fallback}` - Expands to [`std::env::var(\"VARNAME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n or the fallback value if it doesn't exist (everything between the `:-` and `}`)\n- `$CARGO_HOME` - Expands to [`std::env::var(\"CARGO_HOME\")`](https://doc.rust-lang.org/std/env/fn.var.html)\n if it exists, otherwise expands to `$(home::home_dir())/.cargo`\n\nNote that the path must be valid utf-8, after expansion.\n\n\n## Default\n\n```toml\n[advisories]\ndb-path = \"$CARGO_HOME/advisory-dbs\"\n```", + "number": [ + 4, + 0, + 0, + 1 + ], + "sub_items": [], + "path": "advisories-db-path", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.db-path" + ] + } + }, + { + "Chapter": { + "name": "advisories.version", + "content": "# `version`\n\n**Type:** `integer (enum)`
\n**Key:** `optional`\n\nThe advisories section has an upcoming breaking change, with deprecation warnings for several\nfields that will be removed. Setting `version = 2` will opt-in to the future default behavior.\n\nThe breaking change is as follows:\n\n- `vulnerability` - Removed, all vulnerability advisories now emit errors.\n- `unmaintained` - Removed, all unmaintained advisories now emit errors.\n- `unsound` - Removed, all unsound advisories now emit errors.\n- `notice` - Removed, all notice advisories now emit errors.\n- `severity-threshold` - Removed, all vulnerability advisories now emit errors.\n\nAs before, if you want to ignore a specific advisory, add it to the `ignore` field.\n\n\n## Possible values\n\n- `2`", + "number": [ + 4, + 0, + 0, + 2 + ], + "sub_items": [], + "path": "advisories-version", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.version" + ] + } + }, + { + "Chapter": { + "name": "advisories.ignore", + "content": "# `ignore`\n\n**Type:** `array`
\n**Key:** `optional`\n\nEvery advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`.\nPutting an identifier in this array will cause the advisory to be treated as a note, rather\nthan a warning or error.\n\nIn addition, yanked crate versions can be ignored by specifying a [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nwith an optional `reason`.\n\n\n## Example\n\n```toml\n[advisories]\nignore = [\n \"RUSTSEC-0000-0000\",\n { id = \"RUSTSEC-0000-0000\", reason = \"this vulnerability does not affect us as we don't use the particular code path\" },\n \"yanked@0.1.1\",\n { crate = \"yanked-crate@0.1.1\", reason = \"a semver compatible version hasn't been published yet\" },\n]\n```\n\n## `[N]`\n\n", + "number": [ + 4, + 0, + 0, + 3 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories.ignore[N]", + "content": "# `[N]`\n\n\n\n## `string`\n\n**Type:** `string`\n\n## `AdvisoriesIgnoreAdvisory`\n\n**Type:** `object`\n\n## `AdvisoriesIgnoreYanked`\n\n**Type:** `object`", + "number": [ + 4, + 0, + 0, + 3, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories.ignore[N]::string", + "content": "# `string`\n\n**Type:** `string`\n\nEither an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`).", + "number": [ + 4, + 0, + 0, + 3, + 0, + 0 + ], + "sub_items": [], + "path": "advisories-ignore-N---string", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore", + "advisories.ignore[N]", + "advisories.ignore[N]::string" + ] + } + }, + { + "Chapter": { + "name": "advisories.ignore[N]::AdvisoriesIgnoreAdvisory", + "content": "# `AdvisoriesIgnoreAdvisory`\n\n**Type:** `object`\n\n## `id`\n\n**Type:** `string`
\n**Key:** `required`\n\n## `reason`\n\n**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 0, + 3, + 0, + 1 + ], + "sub_items": [ + { + "Chapter": { + "name": "advisories.ignore[N]::AdvisoriesIgnoreAdvisory.id", + "content": "# `id`\n\n**Type:** `string`
\n**Key:** `required`\n\nThe unique identifier of the advisory to ignore\n\n## Example\n\n```toml\n[advisories]\nignore = [\"RUSTSEC-2019-0001\"]\n```", + "number": [ + 4, + 0, + 0, + 3, + 0, + 1, + 0 + ], + "sub_items": [], + "path": "advisories-ignore-N---AdvisoriesIgnoreAdvisory-id", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore", + "advisories.ignore[N]", + "advisories.ignore[N]::AdvisoriesIgnoreAdvisory", + "advisories.ignore[N]::AdvisoriesIgnoreAdvisory.id" + ] + } + } + ], + "path": "advisories-ignore-N---AdvisoriesIgnoreAdvisory", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore", + "advisories.ignore[N]", + "advisories.ignore[N]::AdvisoriesIgnoreAdvisory" + ] + } + }, + { + "Chapter": { + "name": "advisories.ignore[N]::AdvisoriesIgnoreYanked", + "content": "# `AdvisoriesIgnoreYanked`\n\n**Type:** `object`\n\n## `crate`\n\n**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string`
\n**Key:** `required`\n\n## `reason`\n\n**Type:** [`IgnoreReason`](/checks2/schema/type-index/IgnoreReason.md) `string`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 0, + 3, + 0, + 2 + ], + "sub_items": [], + "path": "advisories-ignore-N---AdvisoriesIgnoreYanked", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore", + "advisories.ignore[N]", + "advisories.ignore[N]::AdvisoriesIgnoreYanked" + ] + } + } + ], + "path": "advisories-ignore-N-", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore", + "advisories.ignore[N]" + ] + } + } + ], + "path": "advisories-ignore", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories", + "advisories.ignore" + ] + } + } + ], + "path": "advisories", + "source_path": null, + "parent_names": [ + "Config file", + "", + "advisories" + ] + } + }, + { + "Chapter": { + "name": "bans", + "content": "# `bans`\n\n**Type:** `object`
\n**Key:** `optional`\n\nChecks for specific crates in your graph, as well as duplicates.\n\nThis section is considered when running `cargo deny check bans`.\n\n\n## `allow`\n\n**Type:** `array`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 1 + ], + "sub_items": [ + { + "Chapter": { + "name": "bans.allow", + "content": "# `allow`\n\n**Type:** `array`
\n**Key:** `optional`\n\nDetermines specific crates that are allowed. If the `allow` list has one or more entries, then\nany crate not in that list will be denied, so use with care. Each entry uses the same\n[PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec)\nas other parts of cargo-deny's configuration.\n\n\n## `[N]`\n\n**Type:** [`PackageSpec`](/checks2/schema/type-index/PackageSpec.md) `string`", + "number": [ + 4, + 0, + 1, + 0 + ], + "sub_items": [], + "path": "bans-allow", + "source_path": null, + "parent_names": [ + "Config file", + "", + "bans", + "bans.allow" + ] + } + } + ], + "path": "bans", + "source_path": null, + "parent_names": [ + "Config file", + "", + "bans" + ] + } + }, + { + "Chapter": { + "name": "graph", + "content": "# `graph`\n\n**Type:** `object`
\n**Key:** `optional`\n\nThe graph table configures how the dependency graph is constructed and thus which crates the\nchecks are performed against\n\n\n## `targets`\n\n**Type:** `array`
\n**Key:** `optional`\n\n## `exclude`\n\n**Type:** `array`
\n**Key:** `optional`\n\n## `all-features`\n\n**Type:** `boolean`
\n**Key:** `optional`\n\n## `no-default-features`\n\n**Type:** `boolean`
\n**Key:** `optional`\n\n## `features`\n\n**Type:** `array`
\n**Key:** `optional`\n\n## `exclude-dev`\n\n**Type:** `boolean`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 2 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.targets", + "content": "# `targets`\n\n**Type:** `array`
\n**Key:** `optional`\n\nBy default, cargo-deny will consider every single crate that is resolved by cargo, including\ntarget specific dependencies e.g.\n\n```toml\n[target.x86_64-pc-windows-msvc.dependencies]\nwinapi = \"0.3.8\"\n\n[target.'cfg(target_os = \"fuchsia\")'.dependencies]\nfuchsia-cprng = \"0.1.1\"\n```\n\nBut unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is\nnever actually going to be compiled or linked into your project, so checking it is pointless for you.\n\nThe `targets` field allows you to specify one or more targets which you **actually** build for.\nEvery dependency link to a crate is checked against this list, and if none of the listed targets\nsatisfy the target constraint, the dependency link is ignored. If a crate has no dependency links\nto it, it is not included into the crate graph that the checks are\nexecuted against.\n\n\n## `[N]`\n\n", + "number": [ + 4, + 0, + 2, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.targets[N]", + "content": "# `[N]`\n\n\n\n## `TargetString`\n\n**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string`\n\n## `TargetAdvanced`\n\n**Type:** `object`", + "number": [ + 4, + 0, + 2, + 0, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.targets[N]::TargetAdvanced", + "content": "# `TargetAdvanced`\n\n**Type:** `object`\n\nAdvanced configurations to apply for the target triple\n\n## Examples\n\n- ```toml\n [[graph.targets]]\n triple = \"aarch64-apple-darwin\"\n ```\n- ```toml\n [[graph.targets]]\n triple = \"x86_64-pc-windows-msvc\"\n features = [\"some-feature\"]\n ```\n\n## `triple`\n\n**Type:** [`TargetString`](/checks2/schema/type-index/TargetString.md) `string`
\n**Key:** `required`\n\n## `features`\n\n**Type:** `string`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 2, + 0, + 0, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.targets[N]::TargetAdvanced.features", + "content": "# `features`\n\n**Type:** `string`
\n**Key:** `optional`\n\nRust `cfg()` expressions support the [`target_feature = \"feature-name\"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute)\npredicate, but at the moment, the only way to actually pass them when compiling is to use\nthe `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more\n`target_feature`s you plan to build with, for a particular target triple. At the time of\nthis writing, cargo-deny does not attempt to validate that the features you specify are\nactually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1).\n", + "number": [ + 4, + 0, + 2, + 0, + 0, + 0, + 0 + ], + "sub_items": [], + "path": "graph-targets-N---TargetAdvanced-features", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.targets", + "graph.targets[N]", + "graph.targets[N]::TargetAdvanced", + "graph.targets[N]::TargetAdvanced.features" + ] + } + } + ], + "path": "graph-targets-N---TargetAdvanced", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.targets", + "graph.targets[N]", + "graph.targets[N]::TargetAdvanced" + ] + } + } + ], + "path": "graph-targets-N-", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.targets", + "graph.targets[N]" + ] + } + } + ], + "path": "graph-targets", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.targets" + ] + } + }, + { + "Chapter": { + "name": "graph.exclude", + "content": "# `exclude`\n\n**Type:** `array`
\n**Key:** `optional`\n\nJust as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\ncommand line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html)\nthat will cause the crate(s) in question to be excluded from the crate graph that is used\nfor the operation you are performing.\n\nNote that excluding a crate is recursive, if any of its transitive dependencies are only referenced\nvia the excluded crate, they will also be excluded from the crate graph.\n\n\n## Example\n\n```toml\n[graph]\nexclude = \"some-crate@0.1.0\"\n```\n\n## `[N]`\n\n**Type:** `string`", + "number": [ + 4, + 0, + 2, + 1 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.exclude[N]", + "content": "# `[N]`\n\n**Type:** `string`", + "number": [ + 4, + 0, + 2, + 1, + 0 + ], + "sub_items": [], + "path": "graph-exclude-N-", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.exclude", + "graph.exclude[N]" + ] + } + } + ], + "path": "graph-exclude", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.exclude" + ] + } + }, + { + "Chapter": { + "name": "graph.all-features", + "content": "# `all-features`\n\n**Type:** `boolean`
\n**Key:** `optional`\n\nIf set to `true`, `--all-features` will be used when collecting metadata.", + "number": [ + 4, + 0, + 2, + 2 + ], + "sub_items": [], + "path": "graph-all-features", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.all-features" + ] + } + }, + { + "Chapter": { + "name": "graph.no-default-features", + "content": "# `no-default-features`\n\n**Type:** `boolean`
\n**Key:** `optional`\n\nIf set to `true`, `--no-default-features` will be used when collecting metadata.", + "number": [ + 4, + 0, + 2, + 3 + ], + "sub_items": [], + "path": "graph-no-default-features", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.no-default-features" + ] + } + }, + { + "Chapter": { + "name": "graph.features", + "content": "# `features`\n\n**Type:** `array`
\n**Key:** `optional`\n\nIf set, and `--features` is not specified on the cmd line, these features will be used when\ncollecting metadata.\n\n\n## Example\n\n```toml\n[graph]\nfeatures = \"some-feature\"\n```\n\n## `[N]`\n\n**Type:** `string`", + "number": [ + 4, + 0, + 2, + 4 + ], + "sub_items": [ + { + "Chapter": { + "name": "graph.features[N]", + "content": "# `[N]`\n\n**Type:** `string`", + "number": [ + 4, + 0, + 2, + 4, + 0 + ], + "sub_items": [], + "path": "graph-features-N-", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.features", + "graph.features[N]" + ] + } + } + ], + "path": "graph-features", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.features" + ] + } + }, + { + "Chapter": { + "name": "graph.exclude-dev", + "content": "# `exclude-dev`\n\n**Type:** `boolean`
\n**Key:** `optional`\n\nIf set to `true`, all `dev-dependencies`, even one for workspace crates, are not included\nin the crate graph used for any of the checks. This option can also be enabled on cmd line\nwith `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev)\nor [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev)\nthe `check` subcommand.\n", + "number": [ + 4, + 0, + 2, + 5 + ], + "sub_items": [], + "path": "graph-exclude-dev", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph", + "graph.exclude-dev" + ] + } + } + ], + "path": "graph", + "source_path": null, + "parent_names": [ + "Config file", + "", + "graph" + ] + } + }, + { + "Chapter": { + "name": "output", + "content": "# `output`\n\n**Type:** `object`
\n**Key:** `optional`\n\nThe output table provides options for how/if diagnostics are outputted\n\n## `feature-depth`\n\n**Type:** `integer`
\n**Key:** `optional`", + "number": [ + 4, + 0, + 3 + ], + "sub_items": [ + { + "Chapter": { + "name": "output.feature-depth", + "content": "# `feature-depth`\n\n**Type:** `integer`
\n**Key:** `optional`\n\nThe maximum depth that features will be displayed when inclusion graphs are shown in\ndiagnostics, unless specified via `--feature-depth` on the command line. Only applies to\ndiagnostics that actually print features.\n\n\n## Default\n\n```toml\n[output]\nfeature-depth = 1\n```", + "number": [ + 4, + 0, + 3, + 0 + ], + "sub_items": [], + "path": "output-feature-depth", + "source_path": null, + "parent_names": [ + "Config file", + "", + "output", + "output.feature-depth" + ] + } + } + ], + "path": "output", + "source_path": null, + "parent_names": [ + "Config file", + "", + "output" + ] + } + } + ], + "path": "", + "source_path": null, + "parent_names": [ + "Config file", + "" + ] + } + } + ], + "path": "Config-file", + "source_path": null, + "parent_names": [ + "Config file" + ] + } + }, + { + "Chapter": { + "name": "Type Index", + "content": "# Type Index\n\nThis is an index of common types used across the schema.", + "number": [ + 5 + ], + "sub_items": [ + { + "Chapter": { + "name": "IgnoreReason", + "content": "# `IgnoreReason`\n\n**Type:** `string`", + "number": [ + 5, + 0 + ], + "sub_items": [ + { + "Chapter": { + "name": "", + "content": "# `IgnoreReason`\n\n**Type:** `string`\n\nFree-form string that can be used to describe the reason why the advisory is ignored.", + "number": [ + 5, + 0, + 0 + ], + "sub_items": [], + "path": "", + "source_path": null, + "parent_names": [ + "Type Index", + "IgnoreReason", + "" + ] + } + } + ], + "path": "IgnoreReason", + "source_path": null, + "parent_names": [ + "Type Index", + "IgnoreReason" + ] + } + }, + { + "Chapter": { + "name": "LintLevel", + "content": "# `LintLevel`\n\n**Type:** `string (enum)`", + "number": [ + 5, + 1 + ], + "sub_items": [ + { + "Chapter": { + "name": "", + "content": "# `LintLevel`\n\n**Type:** `string (enum)`\n\n## Possible values\n\n- `\"deny\"` - Emit an error with details about the problem, and fail the check.\n- `\"warn\"` - Print a warning for each propblem, but don't fail the check.\n- `\"allow\"` - Print a note about the problem, but don't fail the check.", + "number": [ + 5, + 1, + 0 + ], + "sub_items": [], + "path": "", + "source_path": null, + "parent_names": [ + "Type Index", + "LintLevel", + "" + ] + } + } + ], + "path": "LintLevel", + "source_path": null, + "parent_names": [ + "Type Index", + "LintLevel" + ] + } + }, + { + "Chapter": { + "name": "PackageSpec", + "content": "# `PackageSpec`\n\n**Type:** `string`", + "number": [ + 5, + 2 + ], + "sub_items": [ + { + "Chapter": { + "name": "", + "content": "# `PackageSpec`\n\n**Type:** `string`\n\nMany configuration options require a package specifier at a minimum, which we'll describe here.\nThe options that use package specifiers will be called out in their individual documentation.\nWe'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples.\n\n### String format\n\nIf the particular only requires a package spec at a minimum, then the string format can be used,\nwhich comes in three forms.\n\n#### Simple\n\n```toml\n# Will match any version of the simple crate\ndeny = [\"simple\"]\n```\n\nThe simplest string is one which is just the crate name. In this case, the version requirement\nused when checking will be `*` meaning it will match against all versions of that crate in the graph.\n\n#### With Version Requirements\n\n```toml\n# Will match only these versions of the simple crate that match the predicate(s)\ndeny = [\"simple:<=0.1,>0.2\"]\n```\n\nIf you want to apply version requirements (predicates) to the crate, simply append them following\na `:` separator.\n\n#### Exact\n\n```toml\n# Will match only this exact version of the simple crate\ndeny = [\n \"simple@0.1.0\",\n # This is semantically equivalent to the above\n \"simple:=0.1.0\",\n]\n```\n\nThe exact form is a specialization of the version requirements, where the semver after the `@`\nis transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact).\n\n### Table format\n\n#### Crate format\n\n```toml\ndeny = [\n { crate = \"simple@0.1.0\" }, # equivalent to \"simple@0.1.0\"\n { crate = \"simple\", wrappers = [\"example\"] },\n]\n```\n\nThe crate format is a replacement for the old `name` and/or `version` table format. It uses\nthe string format described above in a single `crate` key.\n\n#### Old format\n\n```toml\ndeny = [\n { name = \"simple\" },\n { name = \"simple\", version = \"*\" },\n { name = \"simple\", wrappers = [\"example\"] }\n]\n```\n\nThe old format uses a required `name` key and an optional `version` key. This format is deprecated\nand should not be used.\n", + "number": [ + 5, + 2, + 0 + ], + "sub_items": [], + "path": "", + "source_path": null, + "parent_names": [ + "Type Index", + "PackageSpec", + "" + ] + } + } + ], + "path": "PackageSpec", + "source_path": null, + "parent_names": [ + "Type Index", + "PackageSpec" + ] + } + }, + { + "Chapter": { + "name": "TargetString", + "content": "# `TargetString`\n\n**Type:** `string`", + "number": [ + 5, + 3 + ], + "sub_items": [ + { + "Chapter": { + "name": "", + "content": "# `TargetString`\n\n**Type:** `string`\n\nThe [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target\nyou wish to filter target specific dependencies with. If the target triple specified is **not**\none of the targets builtin to `rustc`, the configuration check for that target will be limited\nto only the raw `[target..dependencies]` style of target configuration, as `cfg()`\nexpressions require us to know the details about the target.\n\n\n## Examples\n\n- ```toml\n value = \"x86_64-unknown-linux-gnu\"\n ```\n- ```toml\n value = \"x86_64-pc-windows-msvc\"\n ```\n- ```toml\n value = \"aarch64-apple-darwin\"\n ```", + "number": [ + 5, + 3, + 0 + ], + "sub_items": [], + "path": "", + "source_path": null, + "parent_names": [ + "Type Index", + "TargetString", + "" + ] + } + } + ], + "path": "TargetString", + "source_path": null, + "parent_names": [ + "Type Index", + "TargetString" + ] + } + } + ], + "path": "Type-Index", + "source_path": null, + "parent_names": [ + "Type Index" + ] + } + } + ], + "__non_exhaustive": null +} \ No newline at end of file diff --git a/config-spec/advisories.tsp b/config-spec/advisories.tsp new file mode 100644 index 00000000..431a4f4c --- /dev/null +++ b/config-spec/advisories.tsp @@ -0,0 +1,187 @@ +import "@typespec/json-schema"; +import "./schemd.tsp"; +import "./package-spec.tsp"; + +using JsonSchema; +using Schemd; + +@examples( + [ + { + `db-path`: "~/.cargo/advisory-dbs", + `db-urls`: ["https://github.com/RustSec/advisory-db"], + vulnerability: "deny", + unmaintained: "warn", + unsound: "warn", + yanked: "warn", + notice: "warn", + ignore: [ + "RUSTSEC-0000-0000", + "crate@0.1", + { + crate: "yanked", + reason: "a new version has not been released", + } + ], + `severity-threshold`: "medium", + } + ] +) +model Advisories { + /** + * URLs to one or more advisory databases. + */ + `db-urls`?: url[] = ["https://github.com/RustSec/advisory-db"]; + + /** + * Path to the root directory into which one or more advisory databases are cloned into. + * + * This value supports basic shell expansion: + * + * - `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) + * - `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + * - `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + * - `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + * or the fallback value if it doesn't exist (everything between the `:-` and `}`) + * - `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + * if it exists, otherwise expands to `$(home::home_dir())/.cargo` + * + * Note that the path must be valid utf-8, after expansion. + */ + `db-path`?: string = "$CARGO_HOME/advisory-dbs"; + + /** + * The advisories section has an upcoming breaking change, with deprecation warnings for several + * fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + * + * The breaking change is as follows: + * + * - `vulnerability` - Removed, all vulnerability advisories now emit errors. + * - `unmaintained` - Removed, all unmaintained advisories now emit errors. + * - `unsound` - Removed, all unsound advisories now emit errors. + * - `notice` - Removed, all notice advisories now emit errors. + * - `severity-threshold` - Removed, all vulnerability advisories now emit errors. + * + * As before, if you want to ignore a specific advisory, add it to the `ignore` field. + */ + version?: 2; + + /** + * Determines what happens when a crate with a security vulnerability is encountered. + */ + #deprecated "see `version` field" + vulnerability?: LintLevel = LintLevel.deny; + + /** + * Determines what happens when a crate with an `unmaintained` advisory is encountered. + */ + #deprecated "see `version` field" + unmaintained?: LintLevel = LintLevel.warn; + + /** + * Determines what happens when a crate with an `unsound` advisory is encountered. + */ + #deprecated "see `version` field" + unsound?: LintLevel = LintLevel.warn; + + /** + * Determines what happens when a crate with a `notice` advisory is encountered. + * + * **NOTE**: As of 2019-12-17 there are no `notice` advisories in the + * [RustSec Advisory DB](https://github.com/RustSec/advisory-db) + */ + #deprecated "see `version` field" + notice?: LintLevel = LintLevel.warn; + + /** + * Determines what happens when a crate with a version that has been yanked from its source + * registry is encountered. + */ + yanked?: LintLevel = LintLevel.warn; + + /** + * Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. + * Putting an identifier in this array will cause the advisory to be treated as a note, rather + * than a warning or error. + * + * In addition, yanked crate versions can be ignored by specifying a + * [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + * with an optional `reason`. + */ + @examples( + [ + [ + "RUSTSEC-0000-0000", + { + id: "RUSTSEC-0000-0000", + reason: "this vulnerability does not affect us as we don't use the particular code path", + }, + "yanked@0.1.1", + { + crate: "yanked-crate@0.1.1", + }, + { + reason: "a semver compatible version hasn't been published yet", + } + ] + ] + ) + ignore?: AdvisoriesIgnoreItem[] = []; +} + +union AdvisoriesIgnoreItem { + /** + * Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`) + */ + @doc("goo") + @summary("bruh") + String: string, + + @docHeader("Ignore an advisory") + Advisory: AdvisoriesIgnoreAdvisory, + + @docHeader("Ignore a yanked crate version") + @extension("foo", Json<"bruh">) + Yanked: AdvisoriesIgnoreYanked, +} + +model AdvisoriesIgnoreAdvisory { + /** + * The unique identifier of the advisory to ignore + */ + @examples(["RUSTSEC-2019-0001"]) + id: string; + + @docInline + reason?: IgnoreReason; +} + +model AdvisoriesIgnoreYanked { + /** + * The yanked crate version to ignore. + */ + crate: PackageSpec; + reason?: IgnoreReason; +} + +/** + * Free-form string that can be used to describe the reason why the advisory is ignored. + */ +scalar IgnoreReason extends string; + +enum LintLevel { + /** + * Emit an error with details about the problem, and fail the check. + */ + deny, + + /** + * Print a warning for each propblem, but don't fail the check. + */ + warn, + + /** + * Print a note about the problem, but don't fail the check. + */ + allow, +} diff --git a/config-spec/bans.tsp b/config-spec/bans.tsp new file mode 100644 index 00000000..924e24fb --- /dev/null +++ b/config-spec/bans.tsp @@ -0,0 +1,12 @@ +import "./schemd.tsp"; +import "./package-spec.tsp"; + +model Bans { + /** + * Determines specific crates that are allowed. If the `allow` list has one or more entries, then + * any crate not in that list will be denied, so use with care. Each entry uses the same + * [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + * as other parts of cargo-deny's configuration. + */ + allow?: PackageSpec[] = []; +} diff --git a/config-spec/graph.tsp b/config-spec/graph.tsp new file mode 100644 index 00000000..58840da7 --- /dev/null +++ b/config-spec/graph.tsp @@ -0,0 +1,114 @@ +import "./schemd.tsp"; +using Schemd; + +model Graph { + /** + * By default, cargo-deny will consider every single crate that is resolved by cargo, including + * target specific dependencies e.g. + * + * ```toml + * [target.x86_64-pc-windows-msvc.dependencies] + * winapi = "0.3.8" + * + * [target.'cfg(target_os = "fuchsia")'.dependencies] + * fuchsia-cprng = "0.1.1" + * ``` + * + * But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is + * never actually going to be compiled or linked into your project, so checking it is pointless for you. + * + * The `targets` field allows you to specify one or more targets which you **actually** build for. + * Every dependency link to a crate is checked against this list, and if none of the listed targets + * satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links + * to it, it is not included into the crate graph that the checks are + * executed against. + */ + targets?: Target[]; + + /** + * Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + * command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) + * that will cause the crate(s) in question to be excluded from the crate graph that is used + * for the operation you are performing. + * + * Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced + * via the excluded crate, they will also be excluded from the crate graph. + */ + @examples(["some-crate@0.1.0"]) + exclude?: string[] = []; + + /** + * If set to `true`, `--all-features` will be used when collecting metadata + */ + `all-features`?: boolean = false; + + /** + * If set to `true`, `--no-default-features` will be used when collecting metadata. + */ + `no-default-features`?: boolean = false; + + /** + * If set, and `--features` is not specified on the cmd line, these features + * will be used when collecting metadata. + */ + @examples(["some-feature"]) + features?: string[] = []; + + /** + * If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included + * in the crate graph used for any of the checks. This option can also be enabled on cmd line + * with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + * or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) + * the `check` subcommand. + */ + `exclude-dev`?: boolean = false; +} + +union Target { + String: TargetString, + Advanced: TargetAdvanced, +} + +/** + * Advanced configurations to apply for the target triple + */ +@examples( + [ + { + triple: "aarch64-apple-darwin", + }, + { + triple: "x86_64-pc-windows-msvc", + features: ["some-feature"], + } + ] +) +model TargetAdvanced { + triple: TargetString; + + /** + * Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) + * predicate, but at the moment, the only way to actually pass them when compiling is to use + * the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more + * `target_feature`s you plan to build with, for a particular target triple. At the time of + * this writing, cargo-deny does not attempt to validate that the features you specify are + * actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). + */ + features?: string[] = []; +} + +/** + * The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target + * you wish to filter target specific dependencies with. If the target triple specified is **not** + * one of the targets builtin to `rustc`, the configuration check for that target will be limited + * to only the raw `[target..dependencies]` style of target configuration, as `cfg()` + * expressions require us to know the details about the target. + */ +@examples( + [ + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "aarch64-apple-darwin" + ] +) +scalar TargetString extends string; diff --git a/config-spec/main.tsp b/config-spec/main.tsp new file mode 100644 index 00000000..0b53cc6c --- /dev/null +++ b/config-spec/main.tsp @@ -0,0 +1,47 @@ +import "@typespec/json-schema"; +import "./schemd.tsp"; + +import "./advisories.tsp"; +import "./bans.tsp"; +import "./graph.tsp"; +import "./output.tsp"; + +namespace CargoDeny; + +using TypeSpec.JsonSchema; +using Schemd; + +/** + * Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html + */ +@summary("Configuration file for cargo-deny, by default called `deny.toml`") +@schemdSchema +@jsonSchema("https://github.com/EmbarkStudios/cargo-deny/config-spec") +model CargoDenyConfig { + /** + * Checks advisory databases for crates with security vulnerabilities, + * or that have been marked as unmaintained, or which have been yanked from + * their source registry. + * + * This section is considered when running `cargo deny check advisories`. + */ + advisories?: Advisories; + + /** + * Checks for specific crates in your graph, as well as duplicates. + * + * This section is considered when running `cargo deny check bans`. + */ + bans?: Bans; + + /** + * The graph table configures how the dependency graph is constructed and thus which crates the + * checks are performed against + */ + graph?: Graph; + + /** + * The output table provides options for how/if diagnostics are outputted + */ + output?: Output; +} diff --git a/config-spec/output.tsp b/config-spec/output.tsp new file mode 100644 index 00000000..05b6b975 --- /dev/null +++ b/config-spec/output.tsp @@ -0,0 +1,8 @@ +model Output { + /** + * The maximum depth that features will be displayed when inclusion graphs are shown in + * diagnostics, unless specified via `--feature-depth` on the command line. Only applies to + * diagnostics that actually print features. + */ + `feature-depth`?: uint32 = 1; +} diff --git a/config-spec/package-lock.json b/config-spec/package-lock.json new file mode 100644 index 00000000..690df45b --- /dev/null +++ b/config-spec/package-lock.json @@ -0,0 +1,781 @@ +{ + "name": "config-spec", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "config-spec", + "version": "0.1.0", + "dependencies": { + "@typespec/compiler": "0.56", + "@typespec/json-schema": "0.56" + }, + "devDependencies": { + "typescript": "5.4.5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/compiler": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.56.0.tgz", + "integrity": "sha512-K+VhXycoeqcoSGtB0/l1XYco4V2qRsCOOwqklVM4Yew7kTcKVfz7CT7a6a2OKWDMNg5iijZtRBoM5YF50XtQug==", + "dependencies": { + "@babel/code-frame": "~7.24.2", + "ajv": "~8.12.0", + "change-case": "~5.4.4", + "globby": "~14.0.1", + "mustache": "~4.2.0", + "picocolors": "~1.0.0", + "prettier": "~3.2.5", + "prompts": "~2.4.2", + "semver": "^7.6.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "yaml": "~2.4.1", + "yargs": "~17.7.2" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@typespec/json-schema": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-0.56.0.tgz", + "integrity": "sha512-DHjKvencrFJDu6p2Rdc4aw/ht+slfPnsFee++uq44z8UdMguSx0WDfw4N9I/l7rTkKTLg5LpoRV8MzdihjJNFQ==", + "dependencies": { + "yaml": "~2.4.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.56.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", + "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/config-spec/package-spec.tsp b/config-spec/package-spec.tsp new file mode 100644 index 00000000..3d8c2742 --- /dev/null +++ b/config-spec/package-spec.tsp @@ -0,0 +1,75 @@ +// Using verbose `@doc()` syntax due to a bug: +// https://github.com/microsoft/typespec/issues/3370 +@doc( +""" +Many configuration options require a package specifier at a minimum, which we'll describe here. +The options that use package specifiers will be called out in their individual documentation. +We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + +### String format + +If the particular only requires a package spec at a minimum, then the string format can be used, +which comes in three forms. + +#### Simple + +```toml +# Will match any version of the simple crate +deny = ["simple"] +``` + +The simplest string is one which is just the crate name. In this case, the version requirement +used when checking will be `*` meaning it will match against all versions of that crate in the graph. + +#### With Version Requirements + +```toml +# Will match only these versions of the simple crate that match the predicate(s) +deny = ["simple:<=0.1,>0.2"] +``` + +If you want to apply version requirements (predicates) to the crate, simply append them following +a `:` separator. + +#### Exact + +```toml +# Will match only this exact version of the simple crate +deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", +] +``` + +The exact form is a specialization of the version requirements, where the semver after the `@` +is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + +### Table format + +#### Crate format + +```toml +deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, +] +``` + +The crate format is a replacement for the old `name` and/or `version` table format. It uses +the string format described above in a single `crate` key. + +#### Old format + +```toml +deny = [ + { name = "simple" }, + { name = "simple", version = "*" }, + { name = "simple", wrappers = ["example"] } +] +``` + +The old format uses a required `name` key and an optional `version` key. This format is deprecated +and should not be used. +""") +scalar PackageSpec extends string; diff --git a/config-spec/package.json b/config-spec/package.json new file mode 100644 index 00000000..a2a8ce40 --- /dev/null +++ b/config-spec/package.json @@ -0,0 +1,13 @@ +{ + "name": "config-spec", + "version": "0.1.0", + "type": "module", + "private": true, + "dependencies": { + "@typespec/compiler": "0.56", + "@typespec/json-schema": "0.56" + }, + "devDependencies": { + "typescript": "5.4.5" + } +} diff --git a/config-spec/schemd.tsp b/config-spec/schemd.tsp new file mode 100644 index 00000000..c6878fef --- /dev/null +++ b/config-spec/schemd.tsp @@ -0,0 +1,27 @@ +import "./schemd"; + +namespace Schemd; + +/** + * Add examples to the target type. + */ +extern dec examples(target: unknown, value: unknown[]); + +/** + * Generate `schemd` metadata for the schema on the target type. + */ +extern dec schemdSchema(target: unknown); + +/** + * Set a header that will be used instead of a generated one for this schema + * in documentation. + */ +extern dec docHeader( + target: + | Reflection.Model + | Reflection.Enum + | Reflection.Union + | Reflection.ModelProperty + | Reflection.UnionVariant, + header: valueof string +); diff --git a/config-spec/schemd/decorators.js b/config-spec/schemd/decorators.js new file mode 100644 index 00000000..98c0d25e --- /dev/null +++ b/config-spec/schemd/decorators.js @@ -0,0 +1,185 @@ +//@ts-check +import { ListenerFlow, getDoc, navigateType } from "@typespec/compiler"; +import { createRekeyableMap } from "@typespec/compiler/utils"; +import * as jsonSchema from "@typespec/json-schema"; +import { $lib } from "./lib.js"; + +export function $logType(context, target) { + console.log(target); +} + +export const $examples = makeExtension("examples"); + +/** + * @param {string} key + */ +function makeExtension(key) { + return (context, target, value) => { + setExtension(context, target, key, value); + }; +} + +/** + * @param {import("@typespec/compiler").DecoratorContext} context + * @param {import("@typespec/compiler").Type} target + * @param {string} key + * @param {unknown} value + */ +function setExtension(context, target, key, value) { + jsonSchema.$extension(context, target, key, { + kind: "Model", + name: "Json", + namespace: { name: "JsonSchema" }, + properties: createRekeyableMap([["value", { type: value }]]) + }) +} + +/** + * @param {import("@typespec/compiler").DecoratorContext} context + * @param {import("@typespec/compiler").Type} target + * @param {string} header + */ +export function $docHeader(context, target, header) { + console.log("Setting docs header"); + + if (target.kind == "ModelProperty" || target.kind == "UnionVariant") { + const xSchemd = states.xSchemd(context, target.type); + if (xSchemd.docHeader == null) { + xSchemd.docHeader = header; + return; + } + context.program.reportDiagnostic({ + code: "schemd/docs-header-conflict", + message: + `Docs header on the ${target.kind} conflicts with the` + + `docs header on the type of this ${target.kind} itself. ` + + "The docs header on the type will be used, and this one " + + "will be ignored.", + target, + severity: "warning", + }); + return; + } + + const xSchemd = states.xSchemd(context, target); + xSchemd.docHeader = header; +} + +export function $docInline(context, target, doc) { + +} + +/** + * @param {import("@typespec/compiler").DecoratorContext} context + * @param {import("@typespec/compiler").Type} target + */ +export function $schemdSchema(context, target) { + traverseTypes(target, type => { + switch (type.kind) { + case "Enum": + case "Union": + case "Scalar": + case "Model": { + const id = jsonSchema.getId(context.program, type); + if (id == null && type.name != null) { + jsonSchema.$id(context, type, `#/$defs/${type.name}`); + } + } + } + + switch (type.kind) { + case "Enum": { + const xSchemd = states.xSchemd(context, type); + xSchemd.members = [...type.members.values()].map(member => ({ + description: getDoc(context.program, member) ?? null + })); + } + } + }) +} + +const symbols = { + xSchemd: $lib.createStateSymbol("x-schemd"), +}; + +const states = { + /** + * @param {import("@typespec/compiler").DecoratorContext} context + * @param {import("@typespec/compiler").Type} target + * @returns {{ + * members?: { + * description?: string | null + * }[], + * docHeader?: string + * }} + */ + xSchemd: (context, target) => { + const map = context.program.stateMap(symbols.xSchemd); + if (map.has(target)) { + return map.get(target); + } + + // HACK: make the JSONSchema emitter think as if the value + // specified here is a constant literal defined directly in + // terms of a JS object shape. + const obj = { + kind: "EnumMember", + value: {} + }; + setExtension(context, target, "x-schemd", obj); + map.set(target, obj.value); + return obj.value; + } +} + + +/** + * @param {import("@typespec/compiler").Type} type + * @param {(type: import("@typespec/compiler").Type) => ListenerFlow | undefined | void} visit + */ +function traverseTypes(type, visit) { + visit(type); + const recurse = (type) => traverseTypes(type, visit); + + switch (type.kind) { + case "Model": { + for (const property of type.properties.values()) { + recurse(property); + } + if (type.indexer != null) { + recurse(type.indexer.key); + recurse(type.indexer.value); + } + if (type.baseModel) { + recurse(type.baseModel); + } + break; + } + case "ModelProperty": { + recurse(type.type); + break; + } + case "Tuple": { + for (const element of type.values) { + recurse(element); + } + break; + } + case "Union": { + for (const variant of type.variants.values()) { + recurse(variant); + } + break; + } + case "UnionVariant": { + recurse(type.type); + break; + } + case "Enum": { + for (const member of type.members.values()) { + recurse(member); + } + break; + } + } +} diff --git a/config-spec/schemd/index.js b/config-spec/schemd/index.js new file mode 100644 index 00000000..8c750625 --- /dev/null +++ b/config-spec/schemd/index.js @@ -0,0 +1,14 @@ +import { setTypeSpecNamespace } from "@typespec/compiler"; +import * as decorators from "./decorators.js"; +export { $lib } from "./lib.js"; + +function decorator(fn) { + const namespace = "Schemd"; + setTypeSpecNamespace(namespace, fn); + return fn; +} + +export const $schemdSchema = decorator(decorators.$schemdSchema); +export const $examples = decorator(decorators.$examples); +export const $logType = decorator(decorators.$logType); +export const $docHeader = decorator(decorators.$docHeader); diff --git a/config-spec/schemd/lib.js b/config-spec/schemd/lib.js new file mode 100644 index 00000000..5a78e2b5 --- /dev/null +++ b/config-spec/schemd/lib.js @@ -0,0 +1,6 @@ +import { createTypeSpecLibrary } from "@typespec/compiler"; + +export const $lib = createTypeSpecLibrary({ + name: "schemd", + diagnostics: {}, +}); diff --git a/config-spec/tsconfig.json b/config-spec/tsconfig.json new file mode 100644 index 00000000..159314e2 --- /dev/null +++ b/config-spec/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "forceConsistentCasingInFileNames": true, + "module": "ES2022", + "moduleResolution": "Node16", + "esModuleInterop": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "sourceMap": true, + "declarationMap": true, + "strict": true, + "declaration": true, + "stripInternal": true, + "noEmitHelpers": false, + "target": "ES2022", + "types": ["node"], + "lib": ["es2022", "DOM"], + "experimentalDecorators": true, + "newLine": "LF" + } +} diff --git a/config-spec/tsp-output/@typespec/json-schema/Foo.json b/config-spec/tsp-output/@typespec/json-schema/Foo.json new file mode 100644 index 00000000..ee823bf7 --- /dev/null +++ b/config-spec/tsp-output/@typespec/json-schema/Foo.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://my-domain.ua", + "type": "object", + "properties": { + "bar": { + "$ref": "Bar.json" + } + }, + "required": [ + "bar" + ], + "$defs": { + "Bar": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "Bar.json", + "type": "object", + "properties": {} + } + } +} \ No newline at end of file diff --git a/config-spec/tsp-output/@typespec/json-schema/Foo.yaml b/config-spec/tsp-output/@typespec/json-schema/Foo.yaml new file mode 100644 index 00000000..594f0f1e --- /dev/null +++ b/config-spec/tsp-output/@typespec/json-schema/Foo.yaml @@ -0,0 +1,14 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: https://my-domain.ua +type: object +properties: + bar: + $ref: "#/$defs/Bar" +required: + - bar +$defs: + Bar: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Bar" + type: object + properties: {} diff --git a/config-spec/tsp-output/@typespec/json-schema/PackageSpec.yaml b/config-spec/tsp-output/@typespec/json-schema/PackageSpec.yaml new file mode 100644 index 00000000..4efdb508 --- /dev/null +++ b/config-spec/tsp-output/@typespec/json-schema/PackageSpec.yaml @@ -0,0 +1,11 @@ +type: string +description: |- + ```toml + deny = [ + { name = "simple" }, + { name = "simple", version = "*" }, + { name = "simple", wrappers = ["example"] } + ] + ``` +$schema: https://json-schema.org/draft/2020-12/schema +$id: my-domain.ua diff --git a/config-spec/tsp-output/CargoDenyConfig.yaml b/config-spec/tsp-output/CargoDenyConfig.yaml new file mode 100644 index 00000000..c5cb66b3 --- /dev/null +++ b/config-spec/tsp-output/CargoDenyConfig.yaml @@ -0,0 +1,416 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: https://github.com/EmbarkStudios/cargo-deny/config-spec +type: object +properties: + advisories: + $ref: "#/$defs/Advisories" + description: |- + Checks advisory databases for crates with security vulnerabilities, + or that have been marked as unmaintained, or which have been yanked from + their source registry. + + This section is considered when running `cargo deny check advisories`. + bans: + $ref: "#/$defs/Bans" + description: |- + Checks for specific crates in your graph, as well as duplicates. + + This section is considered when running `cargo deny check bans`. + graph: + $ref: "#/$defs/Graph" + description: |- + The graph table configures how the dependency graph is constructed and thus which crates the + checks are performed against + output: + $ref: "#/$defs/Output" + description: The output table provides options for how/if diagnostics are outputted +description: Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html +title: Configuration file for cargo-deny, by default called `deny.toml` +$defs: + Advisories: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Advisories" + type: object + properties: + db-urls: + type: array + items: + type: string + format: uri + default: + - https://github.com/RustSec/advisory-db + description: URLs to one or more advisory databases. + db-path: + type: string + default: $CARGO_HOME/advisory-dbs + description: |- + Path to the root directory into which one or more advisory databases are cloned into. + + This value supports basic shell expansion: + + - `~` - Expands to [`home::home_dir`](https://docs.rs/home/latest/home/fn.home_dir.html) + - `$VARNAME` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + - `${VARNAME}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + - `${VARNAME:-fallback}` - Expands to [`std::env::var("VARNAME")`](https://doc.rust-lang.org/std/env/fn.var.html) + or the fallback value if it doesn't exist (everything between the `:-` and `}`) + - `$CARGO_HOME` - Expands to [`std::env::var("CARGO_HOME")`](https://doc.rust-lang.org/std/env/fn.var.html) + if it exists, otherwise expands to `$(home::home_dir())/.cargo` + + Note that the path must be valid utf-8, after expansion. + version: + type: number + const: 2 + description: |- + The advisories section has an upcoming breaking change, with deprecation warnings for several + fields that will be removed. Setting `version = 2` will opt-in to the future default behavior. + + The breaking change is as follows: + + - `vulnerability` - Removed, all vulnerability advisories now emit errors. + - `unmaintained` - Removed, all unmaintained advisories now emit errors. + - `unsound` - Removed, all unsound advisories now emit errors. + - `notice` - Removed, all notice advisories now emit errors. + - `severity-threshold` - Removed, all vulnerability advisories now emit errors. + + As before, if you want to ignore a specific advisory, add it to the `ignore` field. + vulnerability: + $ref: "#/$defs/LintLevel" + default: deny + description: Determines what happens when a crate with a security vulnerability is encountered. + deprecated: true + unmaintained: + $ref: "#/$defs/LintLevel" + default: warn + description: Determines what happens when a crate with an `unmaintained` advisory is encountered. + deprecated: true + unsound: + $ref: "#/$defs/LintLevel" + default: warn + description: Determines what happens when a crate with an `unsound` advisory is encountered. + deprecated: true + notice: + $ref: "#/$defs/LintLevel" + default: warn + description: |- + Determines what happens when a crate with a `notice` advisory is encountered. + + **NOTE**: As of 2019-12-17 there are no `notice` advisories in the + [RustSec Advisory DB](https://github.com/RustSec/advisory-db) + deprecated: true + yanked: + $ref: "#/$defs/LintLevel" + default: warn + description: |- + Determines what happens when a crate with a version that has been yanked from its source + registry is encountered. + ignore: + type: array + items: + $ref: "#/$defs/AdvisoriesIgnoreItem" + default: [] + description: |- + Every advisory in the advisory database contains a unique identifier, eg. `RUSTSEC-2019-0001`. + Putting an identifier in this array will cause the advisory to be treated as a note, rather + than a warning or error. + + In addition, yanked crate versions can be ignored by specifying a + [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + with an optional `reason`. + examples: + - - RUSTSEC-0000-0000 + - id: RUSTSEC-0000-0000 + reason: this vulnerability does not affect us as we don't use the particular code path + - yanked@0.1.1 + - crate: yanked-crate@0.1.1 + - reason: a semver compatible version hasn't been published yet + examples: + - db-path: ~/.cargo/advisory-dbs + db-urls: + - https://github.com/RustSec/advisory-db + vulnerability: deny + unmaintained: warn + unsound: warn + yanked: warn + notice: warn + ignore: + - RUSTSEC-0000-0000 + - crate@0.1 + - crate: yanked + reason: a new version has not been released + severity-threshold: medium + Bans: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Bans" + type: object + properties: + allow: + type: array + items: + $ref: "#/$defs/PackageSpec" + default: [] + description: |- + Determines specific crates that are allowed. If the `allow` list has one or more entries, then + any crate not in that list will be denied, so use with care. Each entry uses the same + [PackageSpec](https://embarkstudios.github.io/cargo-deny/checks/cfg.html#package-spec) + as other parts of cargo-deny's configuration. + Graph: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Graph" + type: object + properties: + targets: + type: array + items: + $ref: "#/$defs/Target" + description: |- + By default, cargo-deny will consider every single crate that is resolved by cargo, including + target specific dependencies e.g. + + ```toml + [target.x86_64-pc-windows-msvc.dependencies] + winapi = "0.3.8" + + [target.'cfg(target_os = "fuchsia")'.dependencies] + fuchsia-cprng = "0.1.1" + ``` + + But unless you are actually targeting `x86_64-fuchsia` or `aarch64-fuchsia`, the `fuchsia-cprng` is + never actually going to be compiled or linked into your project, so checking it is pointless for you. + + The `targets` field allows you to specify one or more targets which you **actually** build for. + Every dependency link to a crate is checked against this list, and if none of the listed targets + satisfy the target constraint, the dependency link is ignored. If a crate has no dependency links + to it, it is not included into the crate graph that the checks are + executed against. + exclude: + type: array + items: + type: string + default: [] + description: |- + Just as with the [`--exclude`](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + command line option, this field allows you to specify one or more [Package ID specifications](https://doc.rust-lang.org/cargo/commands/cargo-pkgid.html) + that will cause the crate(s) in question to be excluded from the crate graph that is used + for the operation you are performing. + + Note that excluding a crate is recursive, if any of its transitive dependencies are only referenced + via the excluded crate, they will also be excluded from the crate graph. + examples: + - some-crate@0.1.0 + all-features: + type: boolean + default: false + description: If set to `true`, `--all-features` will be used when collecting metadata + no-default-features: + type: boolean + default: false + description: If set to `true`, `--no-default-features` will be used when collecting metadata. + features: + type: array + items: + type: string + default: [] + description: |- + If set, and `--features` is not specified on the cmd line, these features + will be used when collecting metadata. + examples: + - some-feature + exclude-dev: + type: boolean + default: false + description: |- + If set to `true`, all `dev-dependencies`, even one for workspace crates, are not included + in the crate graph used for any of the checks. This option can also be enabled on cmd line + with `--exclude-dev` either [before](https://embarkstudios.github.io/cargo-deny/cli/common.html#--exclude-dev) + or [after](https://embarkstudios.github.io/cargo-deny/cli/check.html#--exclude-dev) + the `check` subcommand. + Output: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Output" + type: object + properties: + feature-depth: + type: integer + minimum: 0 + maximum: 4294967295 + default: 1 + description: |- + The maximum depth that features will be displayed when inclusion graphs are shown in + diagnostics, unless specified via `--feature-depth` on the command line. Only applies to + diagnostics that actually print features. + LintLevel: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/LintLevel" + type: string + enum: + - deny + - warn + - allow + x-schemd: + members: + - description: Emit an error with details about the problem, and fail the check. + - description: Print a warning for each propblem, but don't fail the check. + - description: Print a note about the problem, but don't fail the check. + AdvisoriesIgnoreItem: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/AdvisoriesIgnoreItem" + anyOf: + - type: string + - $ref: "#/$defs/AdvisoriesIgnoreAdvisory" + - $ref: "#/$defs/AdvisoriesIgnoreYanked" + PackageSpec: + type: string + description: |- + Many configuration options require a package specifier at a minimum, which we'll describe here. + The options that use package specifiers will be called out in their individual documentation. + We'll use the [`bans.deny`](bans/cfg.md#the-deny-field-optional) option in the following examples. + + ### String format + + If the particular only requires a package spec at a minimum, then the string format can be used, + which comes in three forms. + + #### Simple + + ```toml + # Will match any version of the simple crate + deny = ["simple"] + ``` + + The simplest string is one which is just the crate name. In this case, the version requirement + used when checking will be `*` meaning it will match against all versions of that crate in the graph. + + #### With Version Requirements + + ```toml + # Will match only these versions of the simple crate that match the predicate(s) + deny = ["simple:<=0.1,>0.2"] + ``` + + If you want to apply version requirements (predicates) to the crate, simply append them following + a `:` separator. + + #### Exact + + ```toml + # Will match only this exact version of the simple crate + deny = [ + "simple@0.1.0", + # This is semantically equivalent to the above + "simple:=0.1.0", + ] + ``` + + The exact form is a specialization of the version requirements, where the semver after the `@` + is transformed to be [= (Exact)](https://docs.rs/semver/latest/semver/enum.Op.html#opexact). + + ### Table format + + #### Crate format + + ```toml + deny = [ + { crate = "simple@0.1.0" }, # equivalent to "simple@0.1.0" + { crate = "simple", wrappers = ["example"] }, + ] + ``` + + The crate format is a replacement for the old `name` and/or `version` table format. It uses + the string format described above in a single `crate` key. + + #### Old format + + ```toml + deny = [ + { name = "simple" }, + { name = "simple", version = "*" }, + { name = "simple", wrappers = ["example"] } + ] + ``` + + The old format uses a required `name` key and an optional `version` key. This format is deprecated + and should not be used. + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/PackageSpec" + Target: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/Target" + anyOf: + - $ref: "#/$defs/TargetString" + - $ref: "#/$defs/TargetAdvanced" + AdvisoriesIgnoreAdvisory: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/AdvisoriesIgnoreAdvisory" + type: object + properties: + id: + type: string + description: The unique identifier of the advisory to ignore + examples: + - RUSTSEC-2019-0001 + reason: + $ref: "#/$defs/IgnoreReason" + required: + - id + x-schemd: + docHeader: Ignore an advisory + AdvisoriesIgnoreYanked: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/AdvisoriesIgnoreYanked" + type: object + properties: + crate: + $ref: "#/$defs/PackageSpec" + description: The yanked crate version to ignore. + reason: + $ref: "#/$defs/IgnoreReason" + required: + - crate + x-schemd: + docHeader: Ignore a yanked crate version + TargetString: + type: string + description: |- + The [target triple](https://forge.rust-lang.org/release/platform-support.html) for the target + you wish to filter target specific dependencies with. If the target triple specified is **not** + one of the targets builtin to `rustc`, the configuration check for that target will be limited + to only the raw `[target..dependencies]` style of target configuration, as `cfg()` + expressions require us to know the details about the target. + examples: + - x86_64-unknown-linux-gnu + - x86_64-pc-windows-msvc + - aarch64-apple-darwin + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/TargetString" + TargetAdvanced: + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/TargetAdvanced" + type: object + properties: + triple: + $ref: "#/$defs/TargetString" + features: + type: array + items: + type: string + default: [] + description: |- + Rust `cfg()` expressions support the [`target_feature = "feature-name"`](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute) + predicate, but at the moment, the only way to actually pass them when compiling is to use + the `RUSTFLAGS` environment variable. The `features` field allows you to specify 1 or more + `target_feature`s you plan to build with, for a particular target triple. At the time of + this writing, cargo-deny does not attempt to validate that the features you specify are + actually valid for the target triple, but this is [planned](https://github.com/EmbarkStudios/cfg-expr/issues/1). + required: + - triple + description: Advanced configurations to apply for the target triple + examples: + - triple: aarch64-apple-darwin + - triple: x86_64-pc-windows-msvc + features: + - some-feature + IgnoreReason: + type: string + description: Free-form string that can be used to describe the reason why the advisory is ignored. + $schema: https://json-schema.org/draft/2020-12/schema + $id: "#/$defs/IgnoreReason" diff --git a/config-spec/tspconfig.yaml b/config-spec/tspconfig.yaml new file mode 100644 index 00000000..40ff6792 --- /dev/null +++ b/config-spec/tspconfig.yaml @@ -0,0 +1,5 @@ +emit: + - "@typespec/json-schema" +options: + "@typespec/json-schema": + file-type: yaml diff --git a/cspell.yml b/cspell.yml new file mode 100644 index 00000000..667568fd --- /dev/null +++ b/cspell.yml @@ -0,0 +1,3 @@ +words: + - schemd + - rekeyable diff --git a/deny.template.toml b/deny.template.toml index 23a94040..2f40c845 100644 --- a/deny.template.toml +++ b/deny.template.toml @@ -1,4 +1,4 @@ -#:schema deny.schema.json +#:schema ./config-spec/tsp-output/@typespec/json-schema/CargoDenyConfig.json # This template contains all of the possible sections and their default values @@ -13,6 +13,7 @@ # Root options + # The graph table configures how the dependency graph is constructed and thus # which crates the checks are performed against [graph] diff --git a/docs/book.toml b/docs/book.toml index 32ec9cc6..a324f8a7 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -5,9 +5,9 @@ multilingual = false src = "src" title = "cargo-deny" -[preprocessor.dashie] -command = "./target/debug/dashie mdbook preprocessor" -dashie_schema = "../deny.schema.yml" +[preprocessor.schemd] +command = "./target/debug/schemd mdbook preprocessor" +schemd_schema = "../config-spec/tsp-output/CargoDenyConfig.yaml" [output.html] diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d4007400..474be34e 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -20,5 +20,5 @@ - [sources](checks/sources/README.md) - [config](checks/sources/cfg.md) - [diagnostics](checks/sources/diags.md) -- [Config file {{ dashie-root }}]() -- [Type Index {{ dashie-type-index }}]() +- [Config file {{ schemd-root }}]() +- [Type Index {{ schemd-type-index }}]() diff --git a/docus/src/plugin/index.ts b/docus/src/plugin/index.ts index ce1e82d3..aae333b3 100644 --- a/docus/src/plugin/index.ts +++ b/docus/src/plugin/index.ts @@ -3,7 +3,7 @@ import { z } from "zod"; const PluginOptions = z .object({ - dashieSchemaPath: z.string(), + schemdSchemaPath: z.string(), }) .strict(); @@ -13,14 +13,14 @@ export function validateOptions({ options }: { options: unknown }) { return PluginOptions.parse(options) } -export default function dashiePlugin(context: LoadContext, options: PluginOptions): Plugin { +export default function schemdPlugin(context: LoadContext, options: PluginOptions): Plugin { return { - name: "docus-plugin-dashie", + name: "docus-plugin-schemd", async contentLoaded({ content, actions }) { const { addRoute } = actions; addRoute({ - path: "/dashie", - component: "@theme/Dashie", + path: "/schemd", + component: "@theme/Schemd", exact: true, }); }, diff --git a/dashie/Cargo.toml b/schemd/Cargo.toml similarity index 95% rename from dashie/Cargo.toml rename to schemd/Cargo.toml index 3220b7c0..49e6d809 100644 --- a/dashie/Cargo.toml +++ b/schemd/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "dashie" +name = "schemd" version = "0.1.0" edition = "2021" @@ -38,3 +38,6 @@ semver = "1.0" # Renaming `fs-err` to just `fs` for convenience fs = { package = "fs-err", version = "2.11" } buildstructor = "0.5" +heck = "0.5" + +duplicate = "1.0" diff --git a/dashie/src/cli.rs b/schemd/src/cli.rs similarity index 100% rename from dashie/src/cli.rs rename to schemd/src/cli.rs diff --git a/dashie/src/cli/codegen/json_schema.rs b/schemd/src/cli/codegen/json_schema.rs similarity index 75% rename from dashie/src/cli/codegen/json_schema.rs rename to schemd/src/cli/codegen/json_schema.rs index e7c5bb5d..1623d52e 100644 --- a/dashie/src/cli/codegen/json_schema.rs +++ b/schemd/src/cli/codegen/json_schema.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use crate::serdex; -use crate::source::{EnumVariantSchema, RootSchema, Schema, Traverse}; +use crate::source::{RootSchema, Schema, Traverse}; /// Generate the JSON schema based on the input YML schema. pub(crate) fn gen(root: &RootSchema) -> Result { @@ -55,27 +55,18 @@ impl<'a> GenContext<'a> { fn normalize_enum(&self, schema: &mut Schema) -> Result { let mut inlined = self.root.inline_referenced_definition(schema)?; - let Some(enum_variants) = &mut inlined.enum_schema else { + let Some(enum_variants) = inlined.enum_variants() else { return Ok(()); }; - let (values, descriptions): (Vec<_>, Vec<_>) = enum_variants - .iter_mut() - .map(|variant| { - let (value, description) = variant.value_and_description(); - - let description = description.unwrap_or_default(); - - (EnumVariantSchema::Undocumented(value), description) - }) - .unzip(); + let descriptions: Vec> = enum_variants + .map(|variant| variant.x_schemd?.description) + .collect(); inlined.x_taplo = Some(serde_json::json!({ "docs": { "enumValues": descriptions } })); - *enum_variants = values; - *schema = inlined; Ok(()) diff --git a/dashie/src/cli/codegen/mod.rs b/schemd/src/cli/codegen/mod.rs similarity index 58% rename from dashie/src/cli/codegen/mod.rs rename to schemd/src/cli/codegen/mod.rs index f3ede47a..c7c04525 100644 --- a/dashie/src/cli/codegen/mod.rs +++ b/schemd/src/cli/codegen/mod.rs @@ -7,15 +7,15 @@ use camino::Utf8PathBuf; /// Update generated code that is checked in to source control. #[derive(clap::Args, Debug)] pub(crate) struct CodegenCommand { - /// Path to file containing the Dashie schema that we need to process. - dashie_schema: Utf8PathBuf, + /// Path to file containing the Schemd schema that we need to process. + schemd_schema: Utf8PathBuf, } impl CodegenCommand { pub(crate) fn run(self) -> Result { - let dashie_schema = source::RootSchema::from_file(self.dashie_schema)?; + let schemd_schema = source::RootSchema::from_file(self.schemd_schema)?; - json_schema::gen(&dashie_schema)?; + json_schema::gen(&schemd_schema)?; Ok(()) } diff --git a/dashie/src/cli/mdbook/mod.rs b/schemd/src/cli/mdbook/mod.rs similarity index 100% rename from dashie/src/cli/mdbook/mod.rs rename to schemd/src/cli/mdbook/mod.rs diff --git a/dashie/src/cli/mdbook/preprocessor/mod.rs b/schemd/src/cli/mdbook/preprocessor/mod.rs similarity index 100% rename from dashie/src/cli/mdbook/preprocessor/mod.rs rename to schemd/src/cli/mdbook/preprocessor/mod.rs diff --git a/dashie/src/cli/mdbook/preprocessor/preprocess.rs b/schemd/src/cli/mdbook/preprocessor/preprocess.rs similarity index 84% rename from dashie/src/cli/mdbook/preprocessor/preprocess.rs rename to schemd/src/cli/mdbook/preprocessor/preprocess.rs index 93006f77..6362b111 100644 --- a/dashie/src/cli/mdbook/preprocessor/preprocess.rs +++ b/schemd/src/cli/mdbook/preprocessor/preprocess.rs @@ -1,14 +1,16 @@ use crate::md_doc::mir; use crate::prelude::*; -use crate::{source, md_doc}; +use crate::{md_ast, md_doc, source}; use camino::Utf8PathBuf; +use heck::ToKebabCase; use mdbook::book::{self, Book}; use mdbook::preprocess::PreprocessorContext; use mdbook::BookItem; use serde::Deserialize; +use std::path::PathBuf; -const ROOT_PLACEHOLDER: &str = "{{ dashie-root }}"; -const TYPE_INDEX_PLACEHOLDER: &str = "{{ dashie-type-index }}"; +const ROOT_PLACEHOLDER: &str = "{{ schemd-root }}"; +const TYPE_INDEX_PLACEHOLDER: &str = "{{ schemd-type-index }}"; pub(super) fn run(ctx: PreprocessorContext, book: Book) -> Result { Context::new(ctx)?.run(book) @@ -20,7 +22,7 @@ struct Context { } impl Context { - const NAME: &'static str = "dashie"; + const NAME: &'static str = "schemd"; fn new(ctx: PreprocessorContext) -> Result { let config = Config::from_ctx(&ctx)?; @@ -45,11 +47,11 @@ impl Context { fn run(&self, mut book: Book) -> Result { let schema_path: Utf8PathBuf = self .config - .dashie_schema + .schemd_schema .as_ref() .map(|path| self.ctx.root.join(path).try_into()) .transpose()? - .unwrap_or_else(|| "dashie.schema.yml".into()); + .unwrap_or_else(|| "schemd.schema.yml".into()); let schema = source::RootSchema::from_file(schema_path)?; @@ -83,6 +85,17 @@ impl Context { } } + if let Ok(path) = std::env::var("SCHEMD_DUMP_BOOK") { + let book = crate::serdex::json::to_string_pretty(&book); + let path = if path.trim().is_empty() { + "./book.json" + } else { + path.as_str() + }; + + fs::write(path, book)?; + } + Ok(book) } @@ -105,11 +118,10 @@ impl Context { parent_names: &[String], section_number: book::SectionNumber, ) -> book::Chapter { - let parent_names: Vec<_> = parent_names - .iter() - .cloned() - .chain([document.name.clone()]) - .collect(); + // We convert everything to kebab case to make sure the path is URL friendly + let doc_name = document.name.to_kebab_case(); + + let next_parent_names: Vec<_> = parent_names.iter().cloned().chain([doc_name]).collect(); let sub_items = document .data @@ -118,22 +130,21 @@ impl Context { .enumerate() .map(|(i, child)| { let section_number = section_number.iter().copied().chain([i as u32]).collect(); - let chapter = Self::mir_into_mdbook(child, &parent_names, section_number); + let chapter = Self::mir_into_mdbook(child, &next_parent_names, section_number); book::BookItem::Chapter(chapter) }) .collect(); let content = document.data.section.to_markdown(1); - let path = document.name.clone().into(); book::Chapter { name: document.name, content, number: Some(section_number), sub_items, - path: Some(path), + path: Some(<_>::from_iter(next_parent_names)), source_path: None, - parent_names, + parent_names: parent_names.to_vec(), } } } @@ -191,10 +202,10 @@ impl<'book> PlaceholderChapter<'book> { #[derive(Default, Deserialize, Debug)] struct Config { - /// Path to file containing the Dashie schema that we need to process. + /// Path to file containing the Schemd schema that we need to process. /// If a relative path is provided, it is resolved relative to the root of /// the config file itself. - dashie_schema: Option, + schemd_schema: Option, } impl Config { @@ -206,7 +217,7 @@ impl Config { #[derive(Deserialize, Debug)] struct PreprocessorConfig { - dashie: Option, + schemd: Option, } // HACK: we read the original `book.toml` file source to provider better @@ -221,14 +232,14 @@ impl Config { let config = config .preprocessor - .and_then(|preprocessor| preprocessor.dashie) + .and_then(|preprocessor| preprocessor.schemd) .unwrap_or_default(); Ok(config) } } -// pub(crate) fn gen(root: &dashie_schema::RootSchema) -> Result<()> { +// pub(crate) fn gen(root: &schemd_schema::RootSchema) -> Result<()> { // let out_dir = "docs/src/checks2"; // let header = "config"; diff --git a/dashie/src/entrypoint.rs b/schemd/src/entrypoint.rs similarity index 96% rename from dashie/src/entrypoint.rs rename to schemd/src/entrypoint.rs index 087df064..3612dd8f 100644 --- a/dashie/src/entrypoint.rs +++ b/schemd/src/entrypoint.rs @@ -19,7 +19,7 @@ pub fn run() -> ExitCode { fn try_run() -> Result { let env_filter = tracing_subscriber::EnvFilter::builder() - .with_env_var("DASHIE_LOG") + .with_env_var("SCHEMD_LOG") .with_default_directive(LevelFilter::INFO.into()) .from_env_lossy(); diff --git a/dashie/src/error.rs b/schemd/src/error.rs similarity index 100% rename from dashie/src/error.rs rename to schemd/src/error.rs diff --git a/dashie/src/lib.rs b/schemd/src/lib.rs similarity index 96% rename from dashie/src/lib.rs rename to schemd/src/lib.rs index d895b02d..1b4aac9f 100644 --- a/dashie/src/lib.rs +++ b/schemd/src/lib.rs @@ -3,6 +3,7 @@ mod source; mod entrypoint; mod md_doc; mod error; +mod md_ast; mod serdex; pub use entrypoint::run; diff --git a/dashie/src/main.rs b/schemd/src/main.rs similarity index 68% rename from dashie/src/main.rs rename to schemd/src/main.rs index e8102365..54c5f2d8 100644 --- a/dashie/src/main.rs +++ b/schemd/src/main.rs @@ -1,3 +1,3 @@ fn main() -> std::process::ExitCode { - dashie::run() + schemd::run() } diff --git a/dashie/src/md_doc/mir/mdast.rs b/schemd/src/md_ast.rs similarity index 86% rename from dashie/src/md_doc/mir/mdast.rs rename to schemd/src/md_ast.rs index 9ee3b2e1..cab8603e 100644 --- a/dashie/src/md_doc/mir/mdast.rs +++ b/schemd/src/md_ast.rs @@ -1,5 +1,8 @@ +use itertools::Either; use pulldown_cmark::{CowStr, Event, LinkType, Tag}; +const SPECIAL_CHARS: &str = "#\\_*<>`|[]"; + pub(crate) enum MdNode<'a> { Many(Vec), @@ -37,7 +40,7 @@ impl<'a> MdNode<'a> { visit(Event::Code(CowStr::Borrowed(code))); } MdNode::Text(text) => { - visit(Event::Text(CowStr::Borrowed(text))); + visit(Event::Text(escape(text))); } MdNode::Link { label, url } => { let link = TagGuard::new( @@ -146,6 +149,27 @@ impl<'a> MdNode<'a> { } } +pub(crate) fn escape(input: &impl AsRef) -> CowStr<'_> { + let input = input.as_ref(); + + // Optimization when no escaping is needed + if input.chars().all(|c| !SPECIAL_CHARS.contains(c)) { + return input.into(); + } + + input + .chars() + .flat_map(|char| { + if SPECIAL_CHARS.contains(char) { + Either::Left(['\\', char].into_iter()) + } else { + Either::Right([char].into_iter()) + } + }) + .collect::() + .into() +} + struct TagGuard<'e, 'v> { end: Option>, visit: &'v mut dyn FnMut(Event<'e>), @@ -153,7 +177,7 @@ struct TagGuard<'e, 'v> { impl Drop for TagGuard<'_, '_> { fn drop(&mut self) { - (self.visit)(self.end.take().unwrap()) + (self.visit)(self.end.take().unwrap()); } } @@ -170,7 +194,7 @@ impl<'e, 'v> TagGuard<'e, 'v> { } fn visit(&mut self, event: Event<'e>) { - (self.visit)(event) + (self.visit)(event); } fn nest(&mut self, start: Tag<'e>) -> TagGuard<'e, '_> { diff --git a/dashie/src/md_doc/hir/mod.rs b/schemd/src/md_doc/hir/mod.rs similarity index 77% rename from dashie/src/md_doc/hir/mod.rs rename to schemd/src/md_doc/hir/mod.rs index e3a21fe4..3965bc44 100644 --- a/dashie/src/md_doc/hir/mod.rs +++ b/schemd/src/md_doc/hir/mod.rs @@ -5,7 +5,7 @@ pub(crate) use node::*; mod simplifying; use crate::prelude::*; -use crate::source::{self, ArraySchema, ObjectSchema, OneOfVariantSchema, RootSchema}; +use crate::source::{self, ArraySchema, ObjectSchema, RootSchema}; use buildstructor::buildstructor; use std::collections::BTreeMap; @@ -25,7 +25,7 @@ impl Dom { ) -> Result { let ctx = LoweringContext { root: schema, - max_nesting_in_file: max_nesting_in_file.unwrap_or(3), + max_nesting_in_file: max_nesting_in_file.unwrap_or(0), allow_unused_definitions: allow_unused_definitions.unwrap_or(false), }; @@ -122,7 +122,7 @@ impl LoweringContext { self.simplify()?; let root = PathedSourceSchema::origin(PathOrigin::Root, self.root.schema.clone()); - let root = self.schema_node(root)?; + let root = self.schema_node(0, root)?; let definitions = self .root @@ -132,7 +132,7 @@ impl LoweringContext { let origin = PathOrigin::Definition(def_name.clone()); let schema = PathedSourceSchema::origin(origin, schema.clone()); - Ok((def_name.clone(), self.schema_node(schema)?)) + Ok((def_name.clone(), self.schema_node(0, schema)?)) }) .collect::>()?; @@ -142,7 +142,7 @@ impl LoweringContext { }) } - fn schema_node(&self, schema: PathedSourceSchema) -> Result { + fn schema_node(&self, path_anchor: usize, schema: PathedSourceSchema) -> Result { // if let Some(reference) = schema.inner.reference.clone() { // self.schema_node_ref(schema, reference) // } else { @@ -173,41 +173,65 @@ impl LoweringContext { let schema = schema.inner; + let should_be_nested = Self::should_be_nested(&schema); + let children = if let Some(array) = schema.array_schema { Self::array_children(&path, array)? } else if let Some(object) = schema.object_schema { Self::object_children(&path, object)? - } else if let Some(variants) = schema.one_of { - Self::one_of_children(&path, variants)? + } else if let Some(schema_list) = schema.schema_list() { + Self::schema_list_children(&path, schema_list)? } else { vec![] }; - let children = children - .into_iter() - .map(|child| self.schema_node(child)) - .try_collect()?; - let data = SchemaDocData { title: schema.title, description: schema.description, default: schema.default, examples: schema.examples, + header: schema.x_schemd.and_then(|x_schemd| x_schemd.doc_header), }; + // let mut path = path; + // let remainder = || (path.segments.len()) % (usize::from(self.max_nesting_in_file)); + let doc = if let Some(reference) = schema.reference.clone() { SchemaDoc::Ref(SchemaDocRef { reference, data }) - } else if (path.segments.len() + 1) % (usize::from(self.max_nesting_in_file) + 1) == 0 { + } else if !path.segments.is_empty() && should_be_nested { SchemaDoc::Nested(data) } else { + // dbg!(&path); + // path.segments + // .drain(0..dbg!(remainder()) - usize::from(self.max_nesting_in_file)); SchemaDoc::Embedded(data) }; - let schema = Schema { path, ty, doc }; + let schema = Schema { + path, + path_anchor, + ty, + doc, + }; + + let path_anchor = if let SchemaDoc::Nested(_) = schema.doc { + schema.path.segments.len() + } else { + path_anchor + }; + + let children = children + .into_iter() + .map(|child| self.schema_node(path_anchor, child)) + .try_collect()?; Ok(SchemaNode { schema, children }) } + fn should_be_nested(schema: &source::Schema) -> bool { + schema.object_schema.is_some() || schema.schema_list().is_some() + } + fn array_children(path: &Path, array: ArraySchema) -> Result> { let path = path.add_segment(PathSegment::Index); let items = PathedSourceSchema::new(path, *array.items); @@ -231,33 +255,35 @@ impl LoweringContext { Ok(properties) } - fn one_of_children( + fn schema_list_children( path: &Path, - variants: Vec, + list: source::SchemaList<&source::Schema>, ) -> Result> { - let names: Vec<_> = variants - .clone() - .into_iter() - .map(|variant| variant.name().map(ToOwned::to_owned)) + let names: Vec<_> = list + .items + .iter() + .map(source::SchemaListItem::name) .try_collect()?; - let duplicates: Vec<_> = names.iter().duplicates().collect(); + let duplicates: Vec<_> = names.iter().copied().duplicates().collect(); ensure!( duplicates.is_empty(), - "Duplicate variant names found in one_of schema.\n\ + "Duplicate member names found in {:?} schema.\n\ Path: {path}\n\ Duplicates: {duplicates:?}\n\ - Variants: {variants:#?}", + Items: {names:#?}", + list.kind, ); - let variants = variants - .into_iter() + let variants = list + .items + .iter() .zip(names) .map(|(variant, name)| { - let path = path.add_segment(PathSegment::Variant(name)); + let path = path.add_segment(PathSegment::Variant(name.to_owned())); - PathedSourceSchema::new(path, variant.schema) + PathedSourceSchema::new(path, variant.schema.clone()) }) .collect(); diff --git a/dashie/src/md_doc/hir/node.rs b/schemd/src/md_doc/hir/node.rs similarity index 75% rename from dashie/src/md_doc/hir/node.rs rename to schemd/src/md_doc/hir/node.rs index ed717568..ce4cf545 100644 --- a/dashie/src/md_doc/hir/node.rs +++ b/schemd/src/md_doc/hir/node.rs @@ -1,5 +1,5 @@ -use crate::source; use crate::prelude::*; +use crate::source; use serde_json::Value; use std::fmt; @@ -21,10 +21,23 @@ impl SchemaNode { #[derive(Debug)] pub(crate) struct Schema { pub(crate) path: Path, + + /// The index of the segment in the [`Schema::path`] that defines the path to + /// the nearest parent nested node (or root node). It is used to avoid prefixing + /// the path with the parent's path when generating docs. + pub(crate) path_anchor: usize, + pub(crate) ty: Type, pub(crate) doc: SchemaDoc, } +impl Schema { + pub(crate) fn path_from_anchor(&self) -> Path { + let segments = self.path.segments[self.path_anchor..].to_vec(); + self.path.clone().with_segments(segments) + } +} + #[derive(Debug)] pub(crate) enum SchemaDoc { /// Documentation should be embedded in the same file. The value is [`None`] @@ -45,6 +58,13 @@ impl SchemaDoc { _ => None, } } + + pub(crate) fn data(&self) -> &SchemaDocData { + match self { + SchemaDoc::Embedded(data) | SchemaDoc::Nested(data) => data, + SchemaDoc::Ref(reference) => &reference.data, + } + } } #[derive(Debug)] @@ -57,6 +77,9 @@ pub(crate) struct SchemaDocRef { #[derive(Debug)] pub(crate) struct SchemaDocData { + /// Specifies a custom header that overrides the default one + pub(crate) header: Option, + pub(crate) title: Option, pub(crate) description: Option, pub(crate) default: Option, @@ -86,6 +109,13 @@ impl Path { segments, } } + + pub(crate) fn with_segments(self, segments: Vec) -> Self { + Self { + origin: self.origin, + segments, + } + } } impl fmt::Display for Path { @@ -94,7 +124,7 @@ impl fmt::Display for Path { if let Some(first_segment) = segments.next() { if let PathSegment::Variant(_) = first_segment { - write!(f, "As {first_segment}")?; + write!(f, "as {first_segment}")?; } else { write!(f, "{first_segment}")?; } @@ -103,7 +133,7 @@ impl fmt::Display for Path { segments.try_for_each(|segment| match &segment { PathSegment::Field(_) => write!(f, ".{segment}"), PathSegment::Index => write!(f, "{segment}"), - PathSegment::Variant(_) => write!(f, "::{segment}"), + PathSegment::Variant(_) => write!(f, " as {segment}"), }) } } @@ -118,6 +148,7 @@ impl fmt::Display for PathSegment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self { PathSegment::Field(field) => f.write_str(&field.name), + // Other good variants: // . // [..] PathSegment::Index => f.write_str("[N]"), @@ -133,6 +164,12 @@ pub(crate) enum PathSegment { Variant(String), } +impl PathSegment { + pub(crate) fn is_index(&self) -> bool { + matches!(self, PathSegment::Index) + } +} + #[derive(Clone, Debug)] pub(crate) struct Field { pub(crate) name: String, @@ -143,15 +180,15 @@ pub(crate) struct Field { pub(crate) struct LeafType { pub(crate) ty: Option, pub(crate) format: Option, - pub(crate) enum_schema: Option>, + pub(crate) enum_schema: Option>, } impl LeafType { - fn from_dashie_schema(schema: &source::Schema) -> Self { + fn from_schemd_schema(schema: &source::Schema) -> Self { Self { ty: schema.ty.clone(), format: schema.format.clone(), - enum_schema: schema.enum_schema.clone(), + enum_schema: schema.enum_variants().map(Vec::from_iter), } } } @@ -167,12 +204,12 @@ pub(crate) struct Type { impl Type { pub(crate) fn from_source_schema(schema: &source::Schema) -> Self { - let inner = LeafType::from_dashie_schema(schema); + let inner = LeafType::from_schemd_schema(schema); let array_items_ty = schema .array_schema .as_ref() - .map(|array| LeafType::from_dashie_schema(&array.items)); + .map(|array| LeafType::from_schemd_schema(&array.items)); Self { inner, diff --git a/dashie/src/md_doc/hir/simplifying.rs b/schemd/src/md_doc/hir/simplifying.rs similarity index 95% rename from dashie/src/md_doc/hir/simplifying.rs rename to schemd/src/md_doc/hir/simplifying.rs index 1da11d52..8d93b776 100644 --- a/dashie/src/md_doc/hir/simplifying.rs +++ b/schemd/src/md_doc/hir/simplifying.rs @@ -3,6 +3,7 @@ use crate::prelude::*; use crate::source::{self, Traverse}; use std::collections::{BTreeMap, BTreeSet}; use std::ops::ControlFlow; +use indexmap::IndexMap; impl LoweringContext { pub(crate) fn simplify(&mut self) -> Result> { @@ -20,7 +21,7 @@ impl LoweringContext { .filter_map(|entry| entry.schema.referenced_definition_name()) .counts(); - let unused_defs: Vec<_> = self + let unused_defs: IndexMap<_, _> = self .root .definitions .iter() @@ -28,9 +29,10 @@ impl LoweringContext { .collect(); if !unused_defs.is_empty() { + let unused_defs = crate::serdex::json::to_string_pretty(unused_defs); crate::error::fail_or_warn( self.allow_unused_definitions, - format_err!("Found unused definitions: {unused_defs:#?}"), + format_err!("Found unused definitions: {unused_defs}"), )?; } diff --git a/dashie/src/md_doc/mir/mod.rs b/schemd/src/md_doc/mir/mod.rs similarity index 88% rename from dashie/src/md_doc/mir/mod.rs rename to schemd/src/md_doc/mir/mod.rs index f6ae7b4b..5344ae8b 100644 --- a/dashie/src/md_doc/mir/mod.rs +++ b/schemd/src/md_doc/mir/mod.rs @@ -1,19 +1,17 @@ -mod mdast; - use super::hir::{ self, LeafType, Path, PathOrigin, PathSegment, Schema, SchemaDoc, SchemaDocData, SchemaNode, Type, }; use crate::prelude::*; use camino::{Utf8Path, Utf8PathBuf}; +use heck::ToKebabCase; use itertools::Itertools; use serde_json::{json, Value}; +use std::borrow::Cow; use std::collections::BTreeMap; impl hir::Dom { pub(crate) fn lower(&self) -> Dom { - dbg!(&self); - let context = Context {}; context.doc(self) } @@ -86,19 +84,12 @@ impl Context { } fn schema_nested(&self, node: &SchemaNode, doc: &SchemaDocData) -> Document { - let name = node - .schema - .path - .segments - .last() - .unwrap_or(&PathSegment::Index) - .to_string(); - - let nested = NamedDocument { - // name: node.schema.path.to_string(), - name, - data: self.schema_embedded(node, doc), - }; + let doc_name = doc + .header + .clone() + .unwrap_or_else(|| node.schema.path_from_anchor().to_string()); + + let nested = NamedDocument::new(doc_name, self.schema_embedded(node, doc)); // let url = format!("./{name}.md"); let body = [ @@ -156,19 +147,42 @@ impl Context { } fn section_header(&self, schema: &Schema) -> String { - let Some(last_segment) = schema.path.segments.last() else { + if let Some(header) = schema.doc.data().header.clone() { + return header; + } + + if schema.path.segments.is_empty() { return match &schema.path.origin { PathOrigin::Definition(def) => format!("`{def}`"), PathOrigin::Root => "Root".to_owned(), }; - }; + } + + let header = schema.path_from_anchor().to_string(); - format!("`{last_segment}`") - // match &last_segment { - // PathSegment::Field(_) => format!("`{}`", schema.path), - // PathSegment::Index => format!("`{}`", schema.path), - // PathSegment::Variant(_) => format!("`{}`", schema.path), + // if last_segment.is_index() { + // let begin = schema.path.segments[0..schema.path.segments.len() - 1] + // .iter() + // .rposition(|segment| !segment.is_index()) + // .unwrap_or(0); + + // let subpath = schema.path.segments[begin..].to_vec(); + // let subpath = schema.path.clone().with_segments(subpath); + // return format!("`{subpath}`"); // } + + let ty = schema.ty.inner.ty.as_deref(); + let array_items_ty = schema + .ty + .array_items_ty + .as_ref() + .and_then(|ty| ty.ty.as_deref()); + + match (ty, array_items_ty) { + (Some("object"), _) => format!("`[{header}]`"), + (Some("array"), Some("object")) => format!("`[[{header}]]`"), + _ => format!("`{header}`"), + } } fn section_body(&self, schema: &Schema, doc: &SchemaDocData) -> String { @@ -196,12 +210,12 @@ impl Context { fn tag_for_type(&self, schema: &Schema) -> Option { let reference = schema.doc.reference().map(|reference| { let (label, url) = reference - .strip_prefix("#/definitions/") + .strip_prefix("#/$defs/") // TODO: unhardcode .map(|definition| { ( definition, - format!("/checks2/schema/type-index/{definition}.md"), + format!("/type-index/{}.md", definition.to_kebab_case()), ) }) .unwrap_or_else(|| ("{ExternalSchema}", reference.to_owned())); @@ -300,8 +314,8 @@ impl Context { .as_ref()? .iter() .map(|enum_variant| { - let (value, description) = enum_variant.value_and_description(); - let value = format!("`{value}`"); + let value = format!("`{}`", enum_variant.value); + let description = enum_variant.description(); let doc = itertools::chain([value.as_str()], description).format(" - "); format!("- {doc}") @@ -332,11 +346,11 @@ impl Context { let mut value = wrap(&key.segments, value.clone()); - let is_primitive = !value.is_object() && !value.is_array(); + let needs_wrapping = !value.is_object(); // TOML doesn't support primitive values at the top level, so we use // a hack to wrap it into an object - if is_primitive { + if needs_wrapping { value = json!({ "value": value }); } diff --git a/dashie/src/md_doc/mod.rs b/schemd/src/md_doc/mod.rs similarity index 100% rename from dashie/src/md_doc/mod.rs rename to schemd/src/md_doc/mod.rs diff --git a/dashie/src/serdex/json.rs b/schemd/src/serdex/json.rs similarity index 100% rename from dashie/src/serdex/json.rs rename to schemd/src/serdex/json.rs diff --git a/dashie/src/serdex/mod.rs b/schemd/src/serdex/mod.rs similarity index 100% rename from dashie/src/serdex/mod.rs rename to schemd/src/serdex/mod.rs diff --git a/dashie/src/source/mod.rs b/schemd/src/source/mod.rs similarity index 68% rename from dashie/src/source/mod.rs rename to schemd/src/source/mod.rs index 6ffc857e..b424ccc3 100644 --- a/dashie/src/source/mod.rs +++ b/schemd/src/source/mod.rs @@ -5,10 +5,13 @@ pub(crate) use traversal::*; use crate::prelude::*; use crate::serdex; use camino::Utf8Path; +use duplicate::duplicate_item; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::{BTreeMap, BTreeSet}; +use std::fmt; +use std::ops::Deref; type Object = BTreeMap; @@ -17,6 +20,8 @@ pub(crate) struct RootSchema { #[serde(flatten)] pub(crate) schema: Schema, + // Use an aliases to support more recent versions of JSONSchema + #[serde(alias = "$defs")] pub(crate) definitions: BTreeMap, /// Keep the rest of the fields in the schema so they are not lost during @@ -59,10 +64,16 @@ pub(crate) struct Schema { pub(crate) array_schema: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "enum")] - pub(crate) enum_schema: Option>, + pub(crate) enum_schema: Option>, + + #[serde(skip_serializing_if = "Option::is_none", rename = "anyOf")] + pub(crate) any_of: Option>, + + #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] + pub(crate) one_of: Option>, #[serde(skip_serializing_if = "Option::is_none", rename = "oneOf")] - pub(crate) one_of: Option>, + pub(crate) all_of: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub(crate) title: Option, @@ -80,6 +91,10 @@ pub(crate) struct Schema { #[serde(skip_serializing_if = "Option::is_none", rename = "x-taplo")] pub(crate) x_taplo: Option, + /// Extensions for schemd itself + #[serde(skip_serializing_if = "Option::is_none", rename = "x-schemd")] + pub(crate) x_schemd: Option, + /// If [`Some`] specifies the original reference that was inlined into this /// from a [`Self::reference`]. #[serde(skip_serializing_if = "Option::is_none")] @@ -87,38 +102,30 @@ pub(crate) struct Schema { } #[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(untagged)] -pub(crate) enum EnumVariantSchema { - Documented(DocumentedEnumSchema), - Undocumented(Value), -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub(crate) struct DocumentedEnumSchema { - pub(crate) description: String, +#[serde(rename_all = "camelCase")] +pub(crate) struct XSchemd { + /// Adds metadata to each member of an enum. + #[serde(skip_serializing_if = "Option::is_none")] + members: Option>>, - #[serde(flatten)] - value: CustomEnumValue, + /// Set a header that will be used instead of a generated one for this schema + /// in documentation. + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) doc_header: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(untagged)] -enum CustomEnumValue { - Named { value: Value, name: String }, - Inferred { value: String }, -} +pub(crate) struct XSchemdMember { + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) description: Option, -#[derive(Serialize, Deserialize, Debug, Clone)] -pub(crate) struct OneOfVariantSchema { /// Override the name of the variant. It's main use case is when generating /// a Rust enum, which requires a name for each variant. However, it's also - /// useful for documentation purposes as a succinct display name for the + /// useful for documentation purposes as a succinct display name for the /// variant. By default the variant name is inferred from the `$ref` or /// from the `type` clause of the schema. + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) name: Option, - - #[serde(flatten)] - pub(crate) schema: Schema, } // /// Unfortunately we can't use an internally-tagged enum here with associated data @@ -161,16 +168,56 @@ pub(crate) struct SchemaEntry<'a> { } impl Schema { - pub(crate) fn is_primitive(&self) -> bool { - self.object_schema.is_none() - && self.array_schema.is_none() - && self.enum_schema.is_none() - && self.one_of.is_none() + fn x_schemd_members( + x_schemd: &Option, + ) -> impl Iterator> + '_ { + x_schemd + .as_ref() + .and_then(|x_schemd| x_schemd.members.as_deref()) + .into_iter() + .flatten() + .map(Clone::clone) + // Pad the missing members with `None`s at the end + .chain(std::iter::repeat(None)) + } + + #[duplicate_item( + schema_list reference(x) as_ref iter; + [schema_list] [&x] [as_ref] [iter]; + [schema_list_mut] [&mut x] [as_mut] [iter_mut]; + )] + pub(crate) fn schema_list(self: reference([Self])) -> Option> { + let (schemas, kind) = None + .or_else(|| self.any_of.as_ref().zip(Some(SchemaListKind::AnyOf))) + .or_else(|| self.one_of.as_ref().zip(Some(SchemaListKind::OneOf))) + .or_else(|| self.all_of.as_ref().zip(Some(SchemaListKind::AllOf)))?; + + let items = schemas + .iter() + .zip(Self::x_schemd_members(&self.x_schemd)) + .map(|(schema, x_schemd)| SchemaListItem { schema, x_schemd }) + .collect(); + + Some(SchemaList { kind, items }) } - /// Returns all schemas stored inside of this one. It doesn't resolve - /// references. The iterator is depth-first. - pub(crate) fn entries<'a>(&'a self) -> impl Iterator> { + pub(crate) fn enum_variants(&self) -> Option + '_> { + let enum_schema = self.enum_schema.as_deref()?; + + let iter = enum_schema + .iter() + .zip(Self::x_schemd_members(&self.x_schemd)) + .map(|(value, x_schemd)| EnumVariant { + value: value.clone(), + x_schemd, + }); + + Some(iter) + } + + /// Returns all schemas stored inside of this one. It doesn't traverse through + /// `$ref`s in schemas. The iterator is depth-first. + pub(crate) fn entries(&self) -> impl Iterator> { let mut stack = vec![SchemaEntry { schema: self, level: 0, @@ -185,17 +232,20 @@ impl Schema { .iter() .flat_map(|object| object.properties.values()); - let one_of_variants = schema - .one_of + let schema_list = schema.schema_list(); + let schema_list_items = schema_list .iter() - .flatten() - .map(|variant| &variant.schema); + .flat_map(|list| &list.items) + .map(|item| item.schema); - let array_items = schema.array_schema.iter().map(|array| array.items.as_ref()); + let array_items = schema + .array_schema + .as_ref() + .map(|array| array.items.as_ref()); let new_entries = std::iter::empty() .chain(object_properties) - .chain(one_of_variants) + .chain(schema_list_items) .chain(array_items) .map(|schema| SchemaEntry { schema, @@ -236,23 +286,23 @@ impl Schema { self.try_downcast_into(object_schema, "object") } - pub(crate) fn try_as_enum(&self) -> Result<&[EnumVariantSchema]> { + pub(crate) fn try_as_enum(&self) -> Result<&[Value]> { self.try_downcast_as(&self.enum_schema, "enum") .map(Vec::as_slice) } - pub(crate) fn try_into_enum(self) -> Result> { + pub(crate) fn try_into_enum(self) -> Result> { let enum_schema = self.enum_schema.clone(); self.try_downcast_into(enum_schema, "enum") } - pub(crate) fn try_as_one_of(&self) -> Result<&[OneOfVariantSchema]> { - self.try_downcast_as(&self.one_of, "one-of") + pub(crate) fn try_as_one_of(&self) -> Result<&[Schema]> { + self.try_downcast_as(&self.any_of, "one-of") .map(Vec::as_slice) } - pub(crate) fn try_into_one_of(self) -> Result> { - let one_of_schema = self.one_of.clone(); + pub(crate) fn try_into_one_of(self) -> Result> { + let one_of_schema = self.any_of.clone(); self.try_downcast_into(one_of_schema, "one-of") } @@ -263,7 +313,7 @@ impl Schema { } pub(crate) fn referenced_definition_name(&self) -> Option<&str> { - self.reference.as_ref()?.strip_prefix("#/definitions/") + self.reference.as_ref()?.strip_prefix("#/$defs/") } pub(crate) fn is_undocumented_primitive(&self) -> bool { @@ -277,12 +327,15 @@ impl Schema { object_schema: None, array_schema: None, enum_schema: None, + any_of: None, one_of: None, + all_of: None, title: None, description: None, reference: None, default: None, x_taplo: None, + x_schemd: None, inlined_from: _, } if examples.is_empty() @@ -342,45 +395,58 @@ impl RootSchema { } } -impl OneOfVariantSchema { +#[derive(Debug, Clone)] +pub(crate) struct EnumVariant { + pub(crate) value: Value, + pub(crate) x_schemd: Option, +} + +impl EnumVariant { + pub(crate) fn description(&self) -> Option<&str> { + self.x_schemd.as_ref()?.description.as_deref() + } +} + +#[derive(Debug)] +pub(crate) struct SchemaList { + pub(crate) kind: SchemaListKind, + pub(crate) items: Vec>, +} + +#[derive(Debug)] +pub(crate) enum SchemaListKind { + OneOf, + AnyOf, + AllOf, +} + +#[derive(Debug)] +pub(crate) struct SchemaListItem { + pub(crate) schema: T, + pub(crate) x_schemd: Option, +} + +impl SchemaListItem +where + T: Deref + fmt::Debug, +{ pub(crate) fn name(&self) -> Result<&str> { - self.name - .as_deref() + self.x_schemd + .as_ref() + .and_then(|x_schemd| x_schemd.name.as_deref()) .or_else(|| { self.schema .reference .as_ref() .or(self.schema.inlined_from.as_ref())? .as_str() - .strip_prefix("#/definitions/") + .strip_prefix("#/$defs/") }) .or(self.schema.ty.as_deref()) .with_context(|| format!("Expected name for one-of variant, but got: {self:#?}")) } } -impl CustomEnumValue { - fn to_json_value(&self) -> Value { - match self { - CustomEnumValue::Named { value, name: _ } => value.clone(), - CustomEnumValue::Inferred { value } => value.clone().into(), - } - } -} - -impl EnumVariantSchema { - pub(crate) fn value_and_description(&self) -> (Value, Option<&str>) { - match self { - EnumVariantSchema::Documented(schema) => { - let value = schema.value.to_json_value(); - let description = schema.description.as_str(); - (value, Some(description)) - } - EnumVariantSchema::Undocumented(value) => (value.clone(), None), - } - } -} - fn merge_json_mut(dest: &mut T, src: &T) { let mut dest_value = serde_json::to_value(&*dest).unwrap(); let src_value = serde_json::to_value(src).unwrap(); diff --git a/dashie/src/source/traversal.rs b/schemd/src/source/traversal.rs similarity index 90% rename from dashie/src/source/traversal.rs rename to schemd/src/source/traversal.rs index 249de5fe..701e579d 100644 --- a/dashie/src/source/traversal.rs +++ b/schemd/src/source/traversal.rs @@ -35,9 +35,9 @@ impl Traverse for Schema { array.items.try_traverse_mut(visit)?; } - if let Some(one_of) = &mut self.one_of { - for variant in one_of { - variant.schema.try_traverse_mut(visit)?; + if let Some(list) = &mut self.schema_list_mut() { + for item in &mut list.items { + item.schema.try_traverse_mut(visit)?; } } From e7e46ff3ab73dc9c7997e5f6897e2fa6cd71aee9 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 19 May 2024 01:22:16 +0000 Subject: [PATCH 20/20] Next iteratio --- Cargo.toml | 2 +- config-spec/advisories.tsp | 7 +- config-spec/bans.tsp | 2 +- config-spec/graph.tsp | 2 +- config-spec/main.tsp | 6 +- config-spec/package-lock.json | 36 +- config-spec/package.json | 8 +- config-spec/schemd/decorators.js | 185 ---- config-spec/schemd/index.js | 14 - config-spec/schemd/lib.js | 6 - config-spec/tsp-output/CargoDenyConfig.yaml | 2 + cspell.yml | 1 + schemd/{ => cli}/Cargo.toml | 0 schemd/{ => cli}/src/cli.rs | 0 .../{ => cli}/src/cli/codegen/json_schema.rs | 0 schemd/{ => cli}/src/cli/codegen/mod.rs | 0 schemd/{ => cli}/src/cli/mdbook/mod.rs | 0 .../src/cli/mdbook/preprocessor/mod.rs | 0 .../src/cli/mdbook/preprocessor/preprocess.rs | 0 schemd/{ => cli}/src/entrypoint.rs | 0 schemd/{ => cli}/src/error.rs | 0 schemd/{ => cli}/src/lib.rs | 0 schemd/{ => cli}/src/main.rs | 0 schemd/{ => cli}/src/md_ast.rs | 0 schemd/{ => cli}/src/md_doc/hir/mod.rs | 0 schemd/{ => cli}/src/md_doc/hir/node.rs | 0 .../{ => cli}/src/md_doc/hir/simplifying.rs | 0 schemd/{ => cli}/src/md_doc/mir/mod.rs | 0 schemd/{ => cli}/src/md_doc/mod.rs | 0 schemd/{ => cli}/src/serdex/json.rs | 0 schemd/{ => cli}/src/serdex/mod.rs | 0 schemd/{ => cli}/src/source/mod.rs | 0 schemd/{ => cli}/src/source/traversal.rs | 0 schemd/tsp/.gitignore | 4 + .../schemd.tsp => schemd/tsp/lib/main.tsp | 12 +- schemd/tsp/package-lock.json | 871 ++++++++++++++++++ schemd/tsp/package.json | 22 + schemd/tsp/src/decorators/common.ts | 63 ++ schemd/tsp/src/decorators/index.ts | 60 ++ schemd/tsp/src/decorators/schemd-schema.ts | 30 + schemd/tsp/src/index.ts | 3 + schemd/tsp/src/lib.ts | 6 + schemd/tsp/src/utils.ts | 51 + {config-spec => schemd/tsp}/tsconfig.json | 21 +- 44 files changed, 1167 insertions(+), 247 deletions(-) delete mode 100644 config-spec/schemd/decorators.js delete mode 100644 config-spec/schemd/index.js delete mode 100644 config-spec/schemd/lib.js rename schemd/{ => cli}/Cargo.toml (100%) rename schemd/{ => cli}/src/cli.rs (100%) rename schemd/{ => cli}/src/cli/codegen/json_schema.rs (100%) rename schemd/{ => cli}/src/cli/codegen/mod.rs (100%) rename schemd/{ => cli}/src/cli/mdbook/mod.rs (100%) rename schemd/{ => cli}/src/cli/mdbook/preprocessor/mod.rs (100%) rename schemd/{ => cli}/src/cli/mdbook/preprocessor/preprocess.rs (100%) rename schemd/{ => cli}/src/entrypoint.rs (100%) rename schemd/{ => cli}/src/error.rs (100%) rename schemd/{ => cli}/src/lib.rs (100%) rename schemd/{ => cli}/src/main.rs (100%) rename schemd/{ => cli}/src/md_ast.rs (100%) rename schemd/{ => cli}/src/md_doc/hir/mod.rs (100%) rename schemd/{ => cli}/src/md_doc/hir/node.rs (100%) rename schemd/{ => cli}/src/md_doc/hir/simplifying.rs (100%) rename schemd/{ => cli}/src/md_doc/mir/mod.rs (100%) rename schemd/{ => cli}/src/md_doc/mod.rs (100%) rename schemd/{ => cli}/src/serdex/json.rs (100%) rename schemd/{ => cli}/src/serdex/mod.rs (100%) rename schemd/{ => cli}/src/source/mod.rs (100%) rename schemd/{ => cli}/src/source/traversal.rs (100%) create mode 100644 schemd/tsp/.gitignore rename config-spec/schemd.tsp => schemd/tsp/lib/main.tsp (63%) create mode 100644 schemd/tsp/package-lock.json create mode 100644 schemd/tsp/package.json create mode 100644 schemd/tsp/src/decorators/common.ts create mode 100644 schemd/tsp/src/decorators/index.ts create mode 100644 schemd/tsp/src/decorators/schemd-schema.ts create mode 100644 schemd/tsp/src/index.ts create mode 100644 schemd/tsp/src/lib.ts create mode 100644 schemd/tsp/src/utils.ts rename {config-spec => schemd/tsp}/tsconfig.json (62%) diff --git a/Cargo.toml b/Cargo.toml index e73671af..aa742146 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["schemd"] +members = ["schemd/cli"] [package] name = "cargo-deny" diff --git a/config-spec/advisories.tsp b/config-spec/advisories.tsp index 431a4f4c..08d790b2 100644 --- a/config-spec/advisories.tsp +++ b/config-spec/advisories.tsp @@ -1,8 +1,6 @@ -import "@typespec/json-schema"; -import "./schemd.tsp"; +import "@schemd/tsp"; import "./package-spec.tsp"; -using JsonSchema; using Schemd; @examples( @@ -133,15 +131,12 @@ union AdvisoriesIgnoreItem { /** * Either an advisory ID (e.g. `RUSTSEC-2019-0001`) or a package spec (e.g. `yanked@0.1.1`) */ - @doc("goo") - @summary("bruh") String: string, @docHeader("Ignore an advisory") Advisory: AdvisoriesIgnoreAdvisory, @docHeader("Ignore a yanked crate version") - @extension("foo", Json<"bruh">) Yanked: AdvisoriesIgnoreYanked, } diff --git a/config-spec/bans.tsp b/config-spec/bans.tsp index 924e24fb..9418a914 100644 --- a/config-spec/bans.tsp +++ b/config-spec/bans.tsp @@ -1,4 +1,4 @@ -import "./schemd.tsp"; +import "@schemd/tsp"; import "./package-spec.tsp"; model Bans { diff --git a/config-spec/graph.tsp b/config-spec/graph.tsp index 58840da7..a7d6d955 100644 --- a/config-spec/graph.tsp +++ b/config-spec/graph.tsp @@ -1,4 +1,4 @@ -import "./schemd.tsp"; +import "@schemd/tsp"; using Schemd; model Graph { diff --git a/config-spec/main.tsp b/config-spec/main.tsp index 0b53cc6c..a1492e31 100644 --- a/config-spec/main.tsp +++ b/config-spec/main.tsp @@ -1,13 +1,11 @@ import "@typespec/json-schema"; -import "./schemd.tsp"; +import "@schemd/tsp"; import "./advisories.tsp"; import "./bans.tsp"; import "./graph.tsp"; import "./output.tsp"; -namespace CargoDeny; - using TypeSpec.JsonSchema; using Schemd; @@ -15,8 +13,8 @@ using Schemd; * Full documentation is at https://embarkstudios.github.io/cargo-deny/checks/cfg.html */ @summary("Configuration file for cargo-deny, by default called `deny.toml`") -@schemdSchema @jsonSchema("https://github.com/EmbarkStudios/cargo-deny/config-spec") +@schemdSchema model CargoDenyConfig { /** * Checks advisory databases for crates with security vulnerabilities, diff --git a/config-spec/package-lock.json b/config-spec/package-lock.json index 690df45b..e22fa34b 100644 --- a/config-spec/package-lock.json +++ b/config-spec/package-lock.json @@ -8,11 +8,22 @@ "name": "config-spec", "version": "0.1.0", "dependencies": { - "@typespec/compiler": "0.56", - "@typespec/json-schema": "0.56" - }, + "@schemd/tsp": "../schemd/tsp", + "@typespec/compiler": "^0.56", + "@typespec/json-schema": "^0.56" + } + }, + "../schemd/tsp": { + "version": "1.0.0", + "license": "MIT", "devDependencies": { - "typescript": "5.4.5" + "@types/node": "^20.12", + "prettier": "^3.2", + "typescript": "^5.4" + }, + "peerDependencies": { + "@typespec/compiler": "^0.56", + "@typespec/json-schema": "^0.56" } }, "node_modules/@babel/code-frame": { @@ -81,6 +92,10 @@ "node": ">= 8" } }, + "node_modules/@schemd/tsp": { + "resolved": "../schemd/tsp", + "link": true + }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -617,19 +632,6 @@ "node": ">=8.0" } }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", diff --git a/config-spec/package.json b/config-spec/package.json index a2a8ce40..5794ef29 100644 --- a/config-spec/package.json +++ b/config-spec/package.json @@ -4,10 +4,8 @@ "type": "module", "private": true, "dependencies": { - "@typespec/compiler": "0.56", - "@typespec/json-schema": "0.56" - }, - "devDependencies": { - "typescript": "5.4.5" + "@typespec/compiler": "^0.56", + "@typespec/json-schema": "^0.56", + "@schemd/tsp": "../schemd/tsp" } } diff --git a/config-spec/schemd/decorators.js b/config-spec/schemd/decorators.js deleted file mode 100644 index 98c0d25e..00000000 --- a/config-spec/schemd/decorators.js +++ /dev/null @@ -1,185 +0,0 @@ -//@ts-check -import { ListenerFlow, getDoc, navigateType } from "@typespec/compiler"; -import { createRekeyableMap } from "@typespec/compiler/utils"; -import * as jsonSchema from "@typespec/json-schema"; -import { $lib } from "./lib.js"; - -export function $logType(context, target) { - console.log(target); -} - -export const $examples = makeExtension("examples"); - -/** - * @param {string} key - */ -function makeExtension(key) { - return (context, target, value) => { - setExtension(context, target, key, value); - }; -} - -/** - * @param {import("@typespec/compiler").DecoratorContext} context - * @param {import("@typespec/compiler").Type} target - * @param {string} key - * @param {unknown} value - */ -function setExtension(context, target, key, value) { - jsonSchema.$extension(context, target, key, { - kind: "Model", - name: "Json", - namespace: { name: "JsonSchema" }, - properties: createRekeyableMap([["value", { type: value }]]) - }) -} - -/** - * @param {import("@typespec/compiler").DecoratorContext} context - * @param {import("@typespec/compiler").Type} target - * @param {string} header - */ -export function $docHeader(context, target, header) { - console.log("Setting docs header"); - - if (target.kind == "ModelProperty" || target.kind == "UnionVariant") { - const xSchemd = states.xSchemd(context, target.type); - if (xSchemd.docHeader == null) { - xSchemd.docHeader = header; - return; - } - context.program.reportDiagnostic({ - code: "schemd/docs-header-conflict", - message: - `Docs header on the ${target.kind} conflicts with the` + - `docs header on the type of this ${target.kind} itself. ` + - "The docs header on the type will be used, and this one " + - "will be ignored.", - target, - severity: "warning", - }); - return; - } - - const xSchemd = states.xSchemd(context, target); - xSchemd.docHeader = header; -} - -export function $docInline(context, target, doc) { - -} - -/** - * @param {import("@typespec/compiler").DecoratorContext} context - * @param {import("@typespec/compiler").Type} target - */ -export function $schemdSchema(context, target) { - traverseTypes(target, type => { - switch (type.kind) { - case "Enum": - case "Union": - case "Scalar": - case "Model": { - const id = jsonSchema.getId(context.program, type); - if (id == null && type.name != null) { - jsonSchema.$id(context, type, `#/$defs/${type.name}`); - } - } - } - - switch (type.kind) { - case "Enum": { - const xSchemd = states.xSchemd(context, type); - xSchemd.members = [...type.members.values()].map(member => ({ - description: getDoc(context.program, member) ?? null - })); - } - } - }) -} - -const symbols = { - xSchemd: $lib.createStateSymbol("x-schemd"), -}; - -const states = { - /** - * @param {import("@typespec/compiler").DecoratorContext} context - * @param {import("@typespec/compiler").Type} target - * @returns {{ - * members?: { - * description?: string | null - * }[], - * docHeader?: string - * }} - */ - xSchemd: (context, target) => { - const map = context.program.stateMap(symbols.xSchemd); - if (map.has(target)) { - return map.get(target); - } - - // HACK: make the JSONSchema emitter think as if the value - // specified here is a constant literal defined directly in - // terms of a JS object shape. - const obj = { - kind: "EnumMember", - value: {} - }; - setExtension(context, target, "x-schemd", obj); - map.set(target, obj.value); - return obj.value; - } -} - - -/** - * @param {import("@typespec/compiler").Type} type - * @param {(type: import("@typespec/compiler").Type) => ListenerFlow | undefined | void} visit - */ -function traverseTypes(type, visit) { - visit(type); - const recurse = (type) => traverseTypes(type, visit); - - switch (type.kind) { - case "Model": { - for (const property of type.properties.values()) { - recurse(property); - } - if (type.indexer != null) { - recurse(type.indexer.key); - recurse(type.indexer.value); - } - if (type.baseModel) { - recurse(type.baseModel); - } - break; - } - case "ModelProperty": { - recurse(type.type); - break; - } - case "Tuple": { - for (const element of type.values) { - recurse(element); - } - break; - } - case "Union": { - for (const variant of type.variants.values()) { - recurse(variant); - } - break; - } - case "UnionVariant": { - recurse(type.type); - break; - } - case "Enum": { - for (const member of type.members.values()) { - recurse(member); - } - break; - } - } -} diff --git a/config-spec/schemd/index.js b/config-spec/schemd/index.js deleted file mode 100644 index 8c750625..00000000 --- a/config-spec/schemd/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import { setTypeSpecNamespace } from "@typespec/compiler"; -import * as decorators from "./decorators.js"; -export { $lib } from "./lib.js"; - -function decorator(fn) { - const namespace = "Schemd"; - setTypeSpecNamespace(namespace, fn); - return fn; -} - -export const $schemdSchema = decorator(decorators.$schemdSchema); -export const $examples = decorator(decorators.$examples); -export const $logType = decorator(decorators.$logType); -export const $docHeader = decorator(decorators.$docHeader); diff --git a/config-spec/schemd/lib.js b/config-spec/schemd/lib.js deleted file mode 100644 index 5a78e2b5..00000000 --- a/config-spec/schemd/lib.js +++ /dev/null @@ -1,6 +0,0 @@ -import { createTypeSpecLibrary } from "@typespec/compiler"; - -export const $lib = createTypeSpecLibrary({ - name: "schemd", - diagnostics: {}, -}); diff --git a/config-spec/tsp-output/CargoDenyConfig.yaml b/config-spec/tsp-output/CargoDenyConfig.yaml index c5cb66b3..cc8dd466 100644 --- a/config-spec/tsp-output/CargoDenyConfig.yaml +++ b/config-spec/tsp-output/CargoDenyConfig.yaml @@ -350,6 +350,8 @@ $defs: - RUSTSEC-2019-0001 reason: $ref: "#/$defs/IgnoreReason" + x-schemd: + docInline: true required: - id x-schemd: diff --git a/cspell.yml b/cspell.yml index 667568fd..5311023c 100644 --- a/cspell.yml +++ b/cspell.yml @@ -1,3 +1,4 @@ words: - schemd - rekeyable + - typespec diff --git a/schemd/Cargo.toml b/schemd/cli/Cargo.toml similarity index 100% rename from schemd/Cargo.toml rename to schemd/cli/Cargo.toml diff --git a/schemd/src/cli.rs b/schemd/cli/src/cli.rs similarity index 100% rename from schemd/src/cli.rs rename to schemd/cli/src/cli.rs diff --git a/schemd/src/cli/codegen/json_schema.rs b/schemd/cli/src/cli/codegen/json_schema.rs similarity index 100% rename from schemd/src/cli/codegen/json_schema.rs rename to schemd/cli/src/cli/codegen/json_schema.rs diff --git a/schemd/src/cli/codegen/mod.rs b/schemd/cli/src/cli/codegen/mod.rs similarity index 100% rename from schemd/src/cli/codegen/mod.rs rename to schemd/cli/src/cli/codegen/mod.rs diff --git a/schemd/src/cli/mdbook/mod.rs b/schemd/cli/src/cli/mdbook/mod.rs similarity index 100% rename from schemd/src/cli/mdbook/mod.rs rename to schemd/cli/src/cli/mdbook/mod.rs diff --git a/schemd/src/cli/mdbook/preprocessor/mod.rs b/schemd/cli/src/cli/mdbook/preprocessor/mod.rs similarity index 100% rename from schemd/src/cli/mdbook/preprocessor/mod.rs rename to schemd/cli/src/cli/mdbook/preprocessor/mod.rs diff --git a/schemd/src/cli/mdbook/preprocessor/preprocess.rs b/schemd/cli/src/cli/mdbook/preprocessor/preprocess.rs similarity index 100% rename from schemd/src/cli/mdbook/preprocessor/preprocess.rs rename to schemd/cli/src/cli/mdbook/preprocessor/preprocess.rs diff --git a/schemd/src/entrypoint.rs b/schemd/cli/src/entrypoint.rs similarity index 100% rename from schemd/src/entrypoint.rs rename to schemd/cli/src/entrypoint.rs diff --git a/schemd/src/error.rs b/schemd/cli/src/error.rs similarity index 100% rename from schemd/src/error.rs rename to schemd/cli/src/error.rs diff --git a/schemd/src/lib.rs b/schemd/cli/src/lib.rs similarity index 100% rename from schemd/src/lib.rs rename to schemd/cli/src/lib.rs diff --git a/schemd/src/main.rs b/schemd/cli/src/main.rs similarity index 100% rename from schemd/src/main.rs rename to schemd/cli/src/main.rs diff --git a/schemd/src/md_ast.rs b/schemd/cli/src/md_ast.rs similarity index 100% rename from schemd/src/md_ast.rs rename to schemd/cli/src/md_ast.rs diff --git a/schemd/src/md_doc/hir/mod.rs b/schemd/cli/src/md_doc/hir/mod.rs similarity index 100% rename from schemd/src/md_doc/hir/mod.rs rename to schemd/cli/src/md_doc/hir/mod.rs diff --git a/schemd/src/md_doc/hir/node.rs b/schemd/cli/src/md_doc/hir/node.rs similarity index 100% rename from schemd/src/md_doc/hir/node.rs rename to schemd/cli/src/md_doc/hir/node.rs diff --git a/schemd/src/md_doc/hir/simplifying.rs b/schemd/cli/src/md_doc/hir/simplifying.rs similarity index 100% rename from schemd/src/md_doc/hir/simplifying.rs rename to schemd/cli/src/md_doc/hir/simplifying.rs diff --git a/schemd/src/md_doc/mir/mod.rs b/schemd/cli/src/md_doc/mir/mod.rs similarity index 100% rename from schemd/src/md_doc/mir/mod.rs rename to schemd/cli/src/md_doc/mir/mod.rs diff --git a/schemd/src/md_doc/mod.rs b/schemd/cli/src/md_doc/mod.rs similarity index 100% rename from schemd/src/md_doc/mod.rs rename to schemd/cli/src/md_doc/mod.rs diff --git a/schemd/src/serdex/json.rs b/schemd/cli/src/serdex/json.rs similarity index 100% rename from schemd/src/serdex/json.rs rename to schemd/cli/src/serdex/json.rs diff --git a/schemd/src/serdex/mod.rs b/schemd/cli/src/serdex/mod.rs similarity index 100% rename from schemd/src/serdex/mod.rs rename to schemd/cli/src/serdex/mod.rs diff --git a/schemd/src/source/mod.rs b/schemd/cli/src/source/mod.rs similarity index 100% rename from schemd/src/source/mod.rs rename to schemd/cli/src/source/mod.rs diff --git a/schemd/src/source/traversal.rs b/schemd/cli/src/source/traversal.rs similarity index 100% rename from schemd/src/source/traversal.rs rename to schemd/cli/src/source/traversal.rs diff --git a/schemd/tsp/.gitignore b/schemd/tsp/.gitignore new file mode 100644 index 00000000..a7210201 --- /dev/null +++ b/schemd/tsp/.gitignore @@ -0,0 +1,4 @@ +temp +log +node_modules +dist diff --git a/config-spec/schemd.tsp b/schemd/tsp/lib/main.tsp similarity index 63% rename from config-spec/schemd.tsp rename to schemd/tsp/lib/main.tsp index c6878fef..a8c37b82 100644 --- a/config-spec/schemd.tsp +++ b/schemd/tsp/lib/main.tsp @@ -1,9 +1,11 @@ -import "./schemd"; +import "../dist/src/index.js"; namespace Schemd; /** * Add examples to the target type. + * + * @param value The examples array expressed via TypeSpec's literals syntax. */ extern dec examples(target: unknown, value: unknown[]); @@ -25,3 +27,11 @@ extern dec docHeader( | Reflection.UnionVariant, header: valueof string ); + +/** + * Embed the documentation from the underlying referenced type by inlining + * it in the current type's documentation. + */ +extern dec docInline( + target: Reflection.ModelProperty | Reflection.UnionVariant +); diff --git a/schemd/tsp/package-lock.json b/schemd/tsp/package-lock.json new file mode 100644 index 00000000..62a94b5a --- /dev/null +++ b/schemd/tsp/package-lock.json @@ -0,0 +1,871 @@ +{ + "name": "schemd", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "schemd", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/node": "^20.12", + "prettier": "^3.2", + "typescript": "^5.4" + }, + "peerDependencies": { + "@typespec/compiler": "^0.56", + "@typespec/json-schema": "^0.56" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@typespec/compiler": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.56.0.tgz", + "integrity": "sha512-K+VhXycoeqcoSGtB0/l1XYco4V2qRsCOOwqklVM4Yew7kTcKVfz7CT7a6a2OKWDMNg5iijZtRBoM5YF50XtQug==", + "peer": true, + "dependencies": { + "@babel/code-frame": "~7.24.2", + "ajv": "~8.12.0", + "change-case": "~5.4.4", + "globby": "~14.0.1", + "mustache": "~4.2.0", + "picocolors": "~1.0.0", + "prettier": "~3.2.5", + "prompts": "~2.4.2", + "semver": "^7.6.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "yaml": "~2.4.1", + "yargs": "~17.7.2" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@typespec/json-schema": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-0.56.0.tgz", + "integrity": "sha512-DHjKvencrFJDu6p2Rdc4aw/ht+slfPnsFee++uq44z8UdMguSx0WDfw4N9I/l7rTkKTLg5LpoRV8MzdihjJNFQ==", + "peer": true, + "dependencies": { + "yaml": "~2.4.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.56.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "peer": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "peer": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "peer": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "peer": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "peer": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "peer": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "peer": true + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "peer": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "peer": true, + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "peer": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "peer": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "peer": true + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "peer": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "peer": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "peer": true, + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "peer": true, + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "peer": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "peer": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "peer": true, + "engines": { + "node": ">=12" + } + } + } +} diff --git a/schemd/tsp/package.json b/schemd/tsp/package.json new file mode 100644 index 00000000..7ef419b0 --- /dev/null +++ b/schemd/tsp/package.json @@ -0,0 +1,22 @@ +{ + "name": "@schemd/tsp", + "version": "1.0.0", + "license": "MIT", + "type": "module", + "main": "dist/src/index.js", + "tspMain": "lib/main.tsp", + "scripts": { + "fmt": "prettier --write .", + "build": "tsc", + "watch": "tsc --watch" + }, + "peerDependencies": { + "@typespec/compiler": "^0.56", + "@typespec/json-schema": "^0.56" + }, + "devDependencies": { + "@types/node": "^20.12", + "typescript": "^5.4", + "prettier": "^3.2" + } +} diff --git a/schemd/tsp/src/decorators/common.ts b/schemd/tsp/src/decorators/common.ts new file mode 100644 index 00000000..d16e5835 --- /dev/null +++ b/schemd/tsp/src/decorators/common.ts @@ -0,0 +1,63 @@ +import * as tsp from "@typespec/compiler"; +import * as tspUtils from "@typespec/compiler/utils"; +import { $lib } from "../lib.js"; +import * as tspJsonSchema from "@typespec/json-schema"; + +const symbols = { + xSchemd: $lib.createStateSymbol("x-schemd"), +}; + +export const states = { + xSchemd: (context: tsp.DecoratorContext, target: tsp.Type): XSchemd => { + const map = context.program.stateMap(symbols.xSchemd); + if (map.has(target)) { + return map.get(target); + } + + // HACK: make the JSONSchema emitter think as if the value + // specified here is a constant literal defined directly in + // terms of a JS object shape. + const obj = { + kind: "EnumMember", + value: {}, + }; + setJsonSchemaExtension(context, target, "x-schemd", obj); + map.set(target, obj.value); + return obj.value; + }, +}; + +type XSchemd = { + members?: XSchemdMember[]; + docHeader?: string; + docInline?: boolean; +}; + +type XSchemdMember = { + title?: string; + description?: string; +}; + +export function setJsonSchemaExtension( + context: tsp.DecoratorContext, + target: tsp.Type, + key: string, + value: unknown +) { + const namespace = { name: "JsonSchema" }; + const properties = tspUtils.createRekeyableMap([["value", { type: value }]]); + + tspJsonSchema.$extension(context, target, key, { + kind: "Model", + name: "Json", + // We ignore type errors here because we construct partial objects of these + // types here. This is a workaround for the lack of proper library support + // to set custom extensions for JSON Schema: + // https://github.com/microsoft/typespec/issues/3336 + // + // @ts-expect-error + namespace, + // @ts-expect-error + properties, + }); +} diff --git a/schemd/tsp/src/decorators/index.ts b/schemd/tsp/src/decorators/index.ts new file mode 100644 index 00000000..ffe41a73 --- /dev/null +++ b/schemd/tsp/src/decorators/index.ts @@ -0,0 +1,60 @@ +import * as tsp from "@typespec/compiler"; +import { setJsonSchemaExtension, states } from "./common.js"; + +export * from "./schemd-schema.js"; + +/** + * @internal Log the type to the console. + */ +export function $logType(_context: tsp.DecoratorContext, target: unknown) { + console.log(target); +} + +export const $examples = makeExtension("examples"); + +function makeExtension(key: string) { + return (context: tsp.DecoratorContext, target: tsp.Type, value: string) => { + setJsonSchemaExtension(context, target, key, value); + }; +} + +export function $docHeader( + context: tsp.DecoratorContext, + target: tsp.Type, + header: string +) { + console.log("Setting doc header"); + + // Workaround for https://github.com/microsoft/typespec/issues/3391 + if (target.kind == "ModelProperty" || target.kind == "UnionVariant") { + const xSchemd = states.xSchemd(context, target.type); + if (xSchemd.docHeader == null) { + xSchemd.docHeader = header; + return; + } + context.program.reportDiagnostic({ + code: "schemd/doc-header-conflict", + message: + `Doc header on the ${target.kind} conflicts with the` + + `doc header on the type of this ${target.kind} itself. ` + + "The doc header on the type will be used, and this one " + + "will be ignored.", + target, + severity: "warning", + }); + return; + } + + const xSchemd = states.xSchemd(context, target); + xSchemd.docHeader = header; +} + +// TODO: +export function $docInline( + context: tsp.DecoratorContext, + target: tsp.Type, +) { + const xSchemd = states.xSchemd(context, target); + + xSchemd.docInline = true; +} diff --git a/schemd/tsp/src/decorators/schemd-schema.ts b/schemd/tsp/src/decorators/schemd-schema.ts new file mode 100644 index 00000000..73fa2a40 --- /dev/null +++ b/schemd/tsp/src/decorators/schemd-schema.ts @@ -0,0 +1,30 @@ +import * as tsp from "@typespec/compiler"; +import * as tspJsonSchema from "@typespec/json-schema"; +import { states } from "./common.js"; +import { traverseTypes } from "../utils.js"; + +export function $schemdSchema(context: tsp.DecoratorContext, target: tsp.Type) { + traverseTypes(target, (type) => { + switch (type.kind) { + case "Enum": + case "Union": + case "Scalar": + case "Model": { + const id = tspJsonSchema.getId(context.program, type); + if (id == null && type.name != null) { + tspJsonSchema.$id(context, type, `#/$defs/${type.name}`); + } + } + } + + switch (type.kind) { + case "Enum": { + const xSchemd = states.xSchemd(context, type); + xSchemd.members = [...type.members.values()].map((member) => ({ + description: tsp.getDoc(context.program, member), + title: tsp.getSummary(context.program, member), + })); + } + } + }); +} diff --git a/schemd/tsp/src/index.ts b/schemd/tsp/src/index.ts new file mode 100644 index 00000000..cca49ea9 --- /dev/null +++ b/schemd/tsp/src/index.ts @@ -0,0 +1,3 @@ +export * from "./decorators/index.js"; +export { $lib } from "./lib.js"; +export const namespace = "Schemd"; diff --git a/schemd/tsp/src/lib.ts b/schemd/tsp/src/lib.ts new file mode 100644 index 00000000..613051df --- /dev/null +++ b/schemd/tsp/src/lib.ts @@ -0,0 +1,6 @@ +import * as tsp from "@typespec/compiler"; + +export const $lib = tsp.createTypeSpecLibrary({ + name: "@schemd/tsp", + diagnostics: {}, +}); diff --git a/schemd/tsp/src/utils.ts b/schemd/tsp/src/utils.ts new file mode 100644 index 00000000..089bbf37 --- /dev/null +++ b/schemd/tsp/src/utils.ts @@ -0,0 +1,51 @@ +import * as tsp from "@typespec/compiler"; + +export function traverseTypes( + type: tsp.Type, + visit: (type: tsp.Type) => void +): void { + visit(type); + const recurse = (type: tsp.Type) => traverseTypes(type, visit); + + switch (type.kind) { + case "Model": { + for (const property of type.properties.values()) { + recurse(property); + } + if (type.indexer != null) { + recurse(type.indexer.key); + recurse(type.indexer.value); + } + if (type.baseModel) { + recurse(type.baseModel); + } + break; + } + case "ModelProperty": { + recurse(type.type); + break; + } + case "Tuple": { + for (const element of type.values) { + recurse(element); + } + break; + } + case "Union": { + for (const variant of type.variants.values()) { + recurse(variant); + } + break; + } + case "UnionVariant": { + recurse(type.type); + break; + } + case "Enum": { + for (const member of type.members.values()) { + recurse(member); + } + break; + } + } +} diff --git a/config-spec/tsconfig.json b/schemd/tsp/tsconfig.json similarity index 62% rename from config-spec/tsconfig.json rename to schemd/tsp/tsconfig.json index 159314e2..a757c6c1 100644 --- a/config-spec/tsconfig.json +++ b/schemd/tsp/tsconfig.json @@ -1,9 +1,21 @@ { "compilerOptions": { + // This and next setting tells TypeScript to use the new ESM import system to resolve types. + "module": "Node16", + "moduleResolution": "Node16", + "target": "ES2022", + "lib": ["es2022"], + "types": ["node"], + + "rootDir": ".", + "outDir": "dist", + + + "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", + "composite": true, + "alwaysStrict": true, "forceConsistentCasingInFileNames": true, - "module": "ES2022", - "moduleResolution": "Node16", "esModuleInterop": true, "noImplicitAny": true, "noImplicitReturns": true, @@ -14,10 +26,7 @@ "declaration": true, "stripInternal": true, "noEmitHelpers": false, - "target": "ES2022", - "types": ["node"], - "lib": ["es2022", "DOM"], "experimentalDecorators": true, - "newLine": "LF" + "newLine": "LF", } }