feat(website): generate linter configuration page

This commit is contained in:
Boshen 2024-05-23 01:15:36 +08:00
parent 57d2bcacea
commit ead637bf50
No known key found for this signature in database
GPG key ID: 9C7A8C8AB22BEBD1
8 changed files with 160 additions and 98 deletions

137
Cargo.lock generated
View file

@ -76,7 +76,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -87,7 +87,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -170,7 +170,7 @@ checksum = "9a8d5b11f7fa1068e5bbac8ab6c8c2c6940047f69185987446b60c995d4bf89c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -252,6 +252,31 @@ dependencies = [
"half",
]
[[package]]
name = "ckb_schemars"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f21f99fca82a4eb8708e406e99246987b087ecc1e1babeece1a0b1d5238b1750"
dependencies = [
"ckb_schemars_derive",
"dyn-clone",
"indexmap",
"serde",
"serde_json",
]
[[package]]
name = "ckb_schemars_derive"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c813b4fadbdd9f33b1cf02a1ddfa9537d955c8d2fbe150d1fc1684dbf78e73"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals 0.26.0",
"syn 1.0.109",
]
[[package]]
name = "clean-path"
version = "0.2.1"
@ -403,7 +428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -594,7 +619,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1010,7 +1035,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1089,7 +1114,7 @@ dependencies = [
"napi-derive-backend",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1104,7 +1129,7 @@ dependencies = [
"quote",
"regex",
"semver",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1207,7 +1232,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1418,6 +1443,7 @@ dependencies = [
name = "oxc_linter"
version = "0.0.0"
dependencies = [
"ckb_schemars",
"convert_case",
"dashmap",
"insta",
@ -1443,7 +1469,6 @@ dependencies = [
"regex",
"rust-lapper",
"rustc-hash",
"schemars",
"serde",
"serde_json",
"static_assertions",
@ -1458,7 +1483,7 @@ dependencies = [
"itertools",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1793,7 +1818,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1847,7 +1872,7 @@ dependencies = [
"phf_shared",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1882,7 +1907,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -1914,7 +1939,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
"version_check",
"yansi",
]
@ -2178,31 +2203,6 @@ dependencies = [
"hashlink",
]
[[package]]
name = "schemars"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29"
dependencies = [
"dyn-clone",
"indexmap",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals 0.29.1",
"syn",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -2249,7 +2249,18 @@ checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
name = "serde_derive_internals"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
@ -2260,18 +2271,7 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2294,7 +2294,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2411,6 +2411,17 @@ dependencies = [
"is_ci",
]
[[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]]
name = "syn"
version = "2.0.63"
@ -2471,7 +2482,7 @@ checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2536,7 +2547,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2637,7 +2648,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2665,7 +2676,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2743,7 +2754,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals 0.28.0",
"syn",
"syn 2.0.63",
]
[[package]]
@ -2916,7 +2927,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
"wasm-bindgen-shared",
]
@ -2938,7 +2949,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -2973,11 +2984,11 @@ name = "website"
version = "0.0.0"
dependencies = [
"bpaf",
"ckb_schemars",
"handlebars",
"oxc_cli",
"oxc_linter",
"pico-args",
"schemars",
"serde",
"serde_json",
]
@ -3184,7 +3195,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]

View file

@ -173,7 +173,7 @@ unicode-width = "0.1.12"
saphyr = "0.0.1"
base64-simd = "0.8"
cfg-if = "1.0.0"
schemars = "0.8.20"
schemars = { version = "0.8.16", package = "ckb_schemars" } # contains fix for stripping newlines in description
[workspace.metadata.cargo-shear]
ignored = ["napi", "oxc_traverse"]

View file

@ -2,8 +2,9 @@ use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
/// Env
/// Predefine global variables.
// TODO: list the keys we support
// <https://eslint.org/docs/v8.x/use/configure/language-options#specifying-environments>
#[derive(Debug, Clone, Deserialize, JsonSchema)]
pub struct ESLintEnv(FxHashMap<String, bool>);

View file

@ -3,7 +3,8 @@ use serde::Deserialize;
use rustc_hash::FxHashMap;
/// <https://eslint.org/docs/v8.x/use/configure/language-options#using-configuration-files-1>
/// Add or remove global variables.
// <https://eslint.org/docs/v8.x/use/configure/language-options#using-configuration-files-1>
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ESLintGlobals(FxHashMap<String, GlobalValue>);

View file

@ -17,11 +17,41 @@ pub use self::{
settings::jsdoc::JSDocPluginSettings, settings::ESLintSettings,
};
/// ESLint Config
// <https://eslint.org/docs/v8.x/use/configure/configuration-files>
/// Oxlint Configuration File
///
/// This configuration is aligned with ESLint v8's configuration schema (`eslintrc.json`).
///
/// Usage: `oxlint -c oxlintrc.json`
///
/// ::: danger NOTE
///
/// Only the `.json` format is supported.
///
/// :::
///
/// Example
///
/// ```json
/// // oxlintrc.json
/// {
/// // Comments are supported.
/// "env": {
/// "browser": true
/// },
/// "globals": {
/// "foo": "readonly",
/// },
/// "settings": {
/// },
/// "rules": {
/// "eqeqeq": "warn",
/// },
/// }
/// ```
#[derive(Debug, Default, Deserialize, JsonSchema)]
#[serde(default)]
pub struct ESLintConfig {
/// See [Oxlint Rules](./rules)
pub(crate) rules: ESLintRules,
pub(crate) settings: ESLintSettings,
pub(crate) env: ESLintEnv,

View file

@ -1,6 +1,7 @@
use std::{borrow::Cow, fmt, ops::Deref};
use oxc_diagnostics::{Error, OxcDiagnostic};
use rustc_hash::FxHashMap;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
use serde::{
de::{self, Deserializer, Visitor},
@ -9,8 +10,6 @@ use serde::{
use crate::AllowWarnDeny;
// The `rules` field from ESLint config
//
// TS type is `Record<string, RuleConf>`
// - type SeverityConf = 0 | 1 | 2 | "off" | "warn" | "error";
// - type RuleConf = SeverityConf | [SeverityConf, ...any[]];
@ -45,7 +44,7 @@ impl JsonSchema for ESLintRules {
String(String),
Array(Vec<serde_json::Value>),
}
DummyRule::json_schema(gen)
gen.subschema_for::<FxHashMap<String, DummyRule>>()
}
}

View file

@ -11,12 +11,7 @@ use self::{
react::ReactPluginSettings,
};
// The `settings` field from ESLint config
// An object containing name-value pairs of information that should be available to all rules
//
// TS type is `Object`
// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L53>
// But each plugin extends this with their own properties.
/// Shared settings for plugins
#[derive(Debug, Deserialize, Default, JsonSchema)]
pub struct ESLintSettings {
#[serde(default)]

View file

@ -1,6 +1,6 @@
use handlebars::Handlebars;
use schemars::{
schema::{RootSchema, Schema, SchemaObject},
schema::{RootSchema, Schema, SchemaObject, SingleOrVec},
schema_for,
};
use serde::Serialize;
@ -13,7 +13,8 @@ pub fn generate_schema_json() {
}
pub fn generate_schema_markdown() {
let rendered = Renderer::new().render();
let root_schema = schema_for!(ESLintConfig);
let rendered = Renderer::new(root_schema).render();
println!("{rendered}");
}
@ -25,9 +26,11 @@ const ROOT: &str = "
const SECTION: &str = "
{{#each sections}}
{{level}} `{{title}}`
{{level}} {{title}}
{{#if instance_type}}
type: `{{instance_type}}`
{{/if}}
{{description}}
@ -46,7 +49,7 @@ struct Root {
struct Section {
level: String,
title: String,
instance_type: String,
instance_type: Option<String>,
description: String,
sections: Vec<Section>,
}
@ -57,12 +60,11 @@ struct Renderer {
}
impl Renderer {
fn new() -> Self {
fn new(root_schema: RootSchema) -> Self {
let mut handlebars = Handlebars::new();
handlebars.register_escape_fn(handlebars::no_escape);
assert!(handlebars.register_template_string("root", ROOT).is_ok());
assert!(handlebars.register_template_string("section", SECTION).is_ok());
let root_schema = schema_for!(ESLintConfig);
Self { handlebars, root_schema }
}
@ -78,10 +80,14 @@ impl Renderer {
}
}
fn get_referenced_schema(&self, reference: &str) -> &SchemaObject {
let definitions = &self.root_schema.definitions;
let definition = definitions.get(reference.trim_start_matches("#/definitions/"));
definition.map(Self::get_schema_object).unwrap()
fn get_referenced_schema<'a>(&'a self, object: &'a SchemaObject) -> &'a SchemaObject {
if let Some(reference) = &object.reference {
let definitions = &self.root_schema.definitions;
let definition = definitions.get(reference.trim_start_matches("#/definitions/"));
definition.map(Self::get_schema_object).unwrap()
} else {
object
}
}
fn render_root_schema(&self, root_schema: &RootSchema) -> Root {
@ -101,23 +107,42 @@ impl Renderer {
parent_key: Option<&str>,
schema: &SchemaObject,
) -> Vec<Section> {
let Some(object) = &schema.object else { return vec![] };
object
.properties
.iter()
.map(|(key, schema)| {
let key = parent_key.map_or_else(|| key.clone(), |k| format!("{k}.{key}"));
self.render_schema(depth + 1, &key, Self::get_schema_object(schema))
})
.collect::<Vec<_>>()
if let Some(array) = &schema.array {
return array
.items
.iter()
.map(|item| match item {
SingleOrVec::Single(schema) => {
let schema_object = Self::get_schema_object(schema);
let key = parent_key.map_or_else(String::new, |k| format!("{k}[n]"));
self.render_schema(depth + 1, &key, schema_object)
}
SingleOrVec::Vec(_) => panic!(),
})
.collect();
}
if let Some(object) = &schema.object {
return object
.properties
.iter()
.map(|(key, schema)| {
let key = parent_key.map_or_else(|| key.clone(), |k| format!("{k}.{key}"));
self.render_schema(depth + 1, &key, Self::get_schema_object(schema))
})
.collect::<Vec<_>>();
}
vec![]
}
fn render_schema(&self, depth: usize, key: &str, schema: &SchemaObject) -> Section {
let schema = schema.reference.as_ref().map_or(schema, |r| self.get_referenced_schema(r));
let schema = self.get_referenced_schema(schema);
Section {
level: "#".repeat(depth),
title: key.into(),
instance_type: serde_json::to_string(&schema.instance_type).unwrap().replace('"', ""),
instance_type: schema
.instance_type
.as_ref()
.map(|t| serde_json::to_string_pretty(t).unwrap().replace('"', "")),
description: schema
.metadata
.as_ref()