Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ default = ["full-compiler"]

[dependencies]
bitflags = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
dashmap = { version = "6.1.0" }
futures = "0.3.32"
regex = { workspace = true }
Expand Down
8 changes: 6 additions & 2 deletions ls/editors/code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ the following properties:
* `identifier` (string, required): The name of the metadata field to validate (e.g., `author`, `version`).
* `required` (boolean, optional): If `true`, the metadata field must be present in the rule. Defaults to `false`.
* `type` (string, optional): Specifies the expected type of the metadata value. Valid values are
`"string"`, `"integer"`, `"float"`, and `"bool"`. If the value does not match the specified type, a warning will
be generated.
`"string"`, `"integer"`, `"float"`, `"bool"`, and `"date"`. If the value does not match the specified type, a
warning will be generated.
* `format` (string, optional): When `type` is `"date"`, this property specifies the expected format of the
date string. The format string supports specifiers like `%Y` (year), `%m` (month), `%d` (day), `%H` (hour),
`%M` (minute), and `%S` (second). For example, for a date like `"2024-01-25"`, the format should be `"%Y-%m-%d"`.
For more information see: https://docs.rs/chrono/latest/chrono/format/strftime/index.html

For accessing these settings go to the Settings

Expand Down
6 changes: 5 additions & 1 deletion ls/editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,12 @@
},
"type": {
"type": "string",
"enum": ["string", "integer", "float", "bool"],
"enum": ["string", "integer", "float", "bool", "date"],
"description": "The expected type of the metadata value."
},
"format": {
"type": "string",
"description": "The expected format of the date string (e.g., `%Y-%m-%d`)."
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions ls/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ pub struct MetadataValidationRule {
/// Type of the metadata entry.
#[serde(rename = "type")]
pub ty: Option<String>,
/// Format of the metadata entry, if type is "date".
pub format: Option<String>,
}
117 changes: 84 additions & 33 deletions ls/src/features/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use dashmap::mapref::one::Ref;
use serde::{Deserialize, Serialize};

use crate::configuration::MetadataValidationRule;
use chrono::NaiveDate;

#[cfg(feature = "full-compiler")]
use crate::documents::document::Document;
Expand Down Expand Up @@ -88,44 +89,94 @@ pub fn compiler_diagnostics(
}

for validation_rule in metadata_validation {
let mut linter = linters::metadata(&validation_rule.identifier)
let linter = linters::metadata(&validation_rule.identifier)
.required(validation_rule.required);

if let Some(ty) = &validation_rule.ty {
let predicate = match ty.as_str() {
"string" => |meta: &yara_x_parser::ast::Meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::String(_)
)
},
"integer" => |meta: &yara_x_parser::ast::Meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Integer(_)
)
},
"float" => |meta: &yara_x_parser::ast::Meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Float(_)
)
},
"bool" => |meta: &yara_x_parser::ast::Meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Bool(_)
)
},
_ => continue,
match ty.as_str() {
"string" => {
compiler.add_linter(linter.validator(
|meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::String(_)
)
},
format!(
"`{}` must be a `string`",
validation_rule.identifier
),
));
}
"integer" => {
compiler.add_linter(linter.validator(
|meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Integer(_)
)
},
format!(
"`{}` must be a `integer`",
validation_rule.identifier
),
));
}
"float" => {
compiler.add_linter(linter.validator(
|meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Float(_)
)
},
format!(
"`{}` must be a `float`",
validation_rule.identifier
),
));
}
"bool" => {
compiler.add_linter(linter.validator(
|meta| {
matches!(
meta.value,
yara_x_parser::ast::MetaValue::Float(_)
)
},
format!(
"`{}` must be a `bool`",
validation_rule.identifier
),
));
}
"date" => {
let format = validation_rule
.format
.as_deref()
.unwrap_or("%Y-%m-%d");

compiler.add_linter(linter.validator(
|meta| {
if let yara_x_parser::ast::MetaValue::String(
value,
) = &meta.value
{
NaiveDate::parse_from_str(value.0, format)
.is_ok()
} else {
false
}
},
format!(
"`{}` must be a `date` with format `{}`",
validation_rule.identifier, format
),
));
}
_ => {}
};
linter = linter.validator(
predicate,
format!("`{}` must be a `{}`", validation_rule.identifier, ty),
);
}

compiler.add_linter(linter);
}

// VSCode don't handle well error messages with too many columns.
Expand Down
Loading