mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
feat(cli): flatten deno.json configuaration (#17799)
This commit is contained in:
parent
4192978c3a
commit
90a5ef5e34
28 changed files with 535 additions and 149 deletions
|
@ -279,7 +279,7 @@ impl Serialize for TsConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct LintRulesConfig {
|
||||
pub tags: Option<Vec<String>>,
|
||||
|
@ -287,7 +287,7 @@ pub struct LintRulesConfig {
|
|||
pub exclude: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
struct SerializedFilesConfig {
|
||||
pub include: Vec<String>,
|
||||
|
@ -319,6 +319,10 @@ impl SerializedFilesConfig {
|
|||
.collect::<Result<Vec<_>, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.include.is_empty() && self.exclude.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
|
@ -346,11 +350,57 @@ impl FilesConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
/// Choose between flat and nested files configuration.
|
||||
///
|
||||
/// `files` has precedence over `deprecated_files`.
|
||||
/// when `deprecated_files` is present, a warning is logged.
|
||||
///
|
||||
/// caveat: due to default values, it's not possible to distinguish between
|
||||
/// an empty configuration and a configuration with default values.
|
||||
/// `{ "files": {} }` is equivalent to `{ "files": { "include": [], "exclude": [] } }`
|
||||
/// and it wouldn't be able to emit warning for `{ "files": {}, "exclude": [] }`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `files` - Flat configuration.
|
||||
/// * `deprecated_files` - Nested configuration. ("Files")
|
||||
fn choose_files(
|
||||
files: SerializedFilesConfig,
|
||||
deprecated_files: SerializedFilesConfig,
|
||||
) -> SerializedFilesConfig {
|
||||
const DEPRECATED_FILES: &str =
|
||||
"Warning: \"files\" configuration is deprecated";
|
||||
const FLAT_CONFIG: &str = "\"include\" and \"exclude\"";
|
||||
|
||||
let (files_nonempty, deprecated_files_nonempty) =
|
||||
(!files.is_empty(), !deprecated_files.is_empty());
|
||||
|
||||
match (files_nonempty, deprecated_files_nonempty) {
|
||||
(true, true) => {
|
||||
log::warn!("{DEPRECATED_FILES} and ignored by {FLAT_CONFIG}.");
|
||||
files
|
||||
}
|
||||
(true, false) => files,
|
||||
(false, true) => {
|
||||
log::warn!("{DEPRECATED_FILES}. Please use {FLAT_CONFIG} instead.");
|
||||
deprecated_files
|
||||
}
|
||||
(false, false) => SerializedFilesConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// `lint` config representation for serde
|
||||
///
|
||||
/// fields `include` and `exclude` are expanded from [SerializedFilesConfig].
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
struct SerializedLintConfig {
|
||||
pub rules: LintRulesConfig,
|
||||
pub files: SerializedFilesConfig,
|
||||
pub include: Vec<String>,
|
||||
pub exclude: Vec<String>,
|
||||
|
||||
#[serde(rename = "files")]
|
||||
pub deprecated_files: SerializedFilesConfig,
|
||||
pub report: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -359,22 +409,26 @@ impl SerializedLintConfig {
|
|||
self,
|
||||
config_file_specifier: &ModuleSpecifier,
|
||||
) -> Result<LintConfig, AnyError> {
|
||||
let (include, exclude) = (self.include, self.exclude);
|
||||
let files = SerializedFilesConfig { include, exclude };
|
||||
|
||||
Ok(LintConfig {
|
||||
rules: self.rules,
|
||||
files: self.files.into_resolved(config_file_specifier)?,
|
||||
files: choose_files(files, self.deprecated_files)
|
||||
.into_resolved(config_file_specifier)?,
|
||||
report: self.report,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct LintConfig {
|
||||
pub rules: LintRulesConfig,
|
||||
pub files: FilesConfig,
|
||||
pub report: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub enum ProseWrap {
|
||||
Always,
|
||||
|
@ -382,7 +436,7 @@ pub enum ProseWrap {
|
|||
Preserve,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct FmtOptionsConfig {
|
||||
pub use_tabs: Option<bool>,
|
||||
|
@ -393,11 +447,75 @@ pub struct FmtOptionsConfig {
|
|||
pub semi_colons: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
impl FmtOptionsConfig {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.use_tabs.is_none()
|
||||
&& self.line_width.is_none()
|
||||
&& self.indent_width.is_none()
|
||||
&& self.single_quote.is_none()
|
||||
&& self.prose_wrap.is_none()
|
||||
&& self.semi_colons.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Choose between flat and nested fmt options.
|
||||
///
|
||||
/// `options` has precedence over `deprecated_options`.
|
||||
/// when `deprecated_options` is present, a warning is logged.
|
||||
///
|
||||
/// caveat: due to default values, it's not possible to distinguish between
|
||||
/// an empty configuration and a configuration with default values.
|
||||
/// `{ "fmt": {} } is equivalent to `{ "fmt": { "options": {} } }`
|
||||
/// and it wouldn't be able to emit warning for `{ "fmt": { "options": {}, "semiColons": "false" } }`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `options` - Flat options.
|
||||
/// * `deprecated_options` - Nested files configuration ("option").
|
||||
fn choose_fmt_options(
|
||||
options: FmtOptionsConfig,
|
||||
deprecated_options: FmtOptionsConfig,
|
||||
) -> FmtOptionsConfig {
|
||||
const DEPRECATED_OPTIONS: &str =
|
||||
"Warning: \"options\" configuration is deprecated";
|
||||
const FLAT_OPTION: &str = "\"flat\" options";
|
||||
|
||||
let (options_nonempty, deprecated_options_nonempty) =
|
||||
(!options.is_empty(), !deprecated_options.is_empty());
|
||||
|
||||
match (options_nonempty, deprecated_options_nonempty) {
|
||||
(true, true) => {
|
||||
log::warn!("{DEPRECATED_OPTIONS} and ignored by {FLAT_OPTION}.");
|
||||
options
|
||||
}
|
||||
(true, false) => options,
|
||||
(false, true) => {
|
||||
log::warn!("{DEPRECATED_OPTIONS}. Please use {FLAT_OPTION} instead.");
|
||||
deprecated_options
|
||||
}
|
||||
(false, false) => FmtOptionsConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// `fmt` config representation for serde
|
||||
///
|
||||
/// fields from `use_tabs`..`semi_colons` are expanded from [FmtOptionsConfig].
|
||||
/// fields `include` and `exclude` are expanded from [SerializedFilesConfig].
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields, rename_all = "camelCase")]
|
||||
struct SerializedFmtConfig {
|
||||
pub options: FmtOptionsConfig,
|
||||
pub files: SerializedFilesConfig,
|
||||
pub use_tabs: Option<bool>,
|
||||
pub line_width: Option<u32>,
|
||||
pub indent_width: Option<u8>,
|
||||
pub single_quote: Option<bool>,
|
||||
pub prose_wrap: Option<ProseWrap>,
|
||||
pub semi_colons: Option<bool>,
|
||||
#[serde(rename = "options")]
|
||||
pub deprecated_options: FmtOptionsConfig,
|
||||
pub include: Vec<String>,
|
||||
pub exclude: Vec<String>,
|
||||
#[serde(rename = "files")]
|
||||
pub deprecated_files: SerializedFilesConfig,
|
||||
}
|
||||
|
||||
impl SerializedFmtConfig {
|
||||
|
@ -405,23 +523,41 @@ impl SerializedFmtConfig {
|
|||
self,
|
||||
config_file_specifier: &ModuleSpecifier,
|
||||
) -> Result<FmtConfig, AnyError> {
|
||||
let (include, exclude) = (self.include, self.exclude);
|
||||
let files = SerializedFilesConfig { include, exclude };
|
||||
let options = FmtOptionsConfig {
|
||||
use_tabs: self.use_tabs,
|
||||
line_width: self.line_width,
|
||||
indent_width: self.indent_width,
|
||||
single_quote: self.single_quote,
|
||||
prose_wrap: self.prose_wrap,
|
||||
semi_colons: self.semi_colons,
|
||||
};
|
||||
|
||||
Ok(FmtConfig {
|
||||
options: self.options,
|
||||
files: self.files.into_resolved(config_file_specifier)?,
|
||||
options: choose_fmt_options(options, self.deprecated_options),
|
||||
files: choose_files(files, self.deprecated_files)
|
||||
.into_resolved(config_file_specifier)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct FmtConfig {
|
||||
pub options: FmtOptionsConfig,
|
||||
pub files: FilesConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
/// `test` config representation for serde
|
||||
///
|
||||
/// fields `include` and `exclude` are expanded from [SerializedFilesConfig].
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
struct SerializedTestConfig {
|
||||
pub files: SerializedFilesConfig,
|
||||
pub include: Vec<String>,
|
||||
pub exclude: Vec<String>,
|
||||
#[serde(rename = "files")]
|
||||
pub deprecated_files: SerializedFilesConfig,
|
||||
}
|
||||
|
||||
impl SerializedTestConfig {
|
||||
|
@ -429,21 +565,31 @@ impl SerializedTestConfig {
|
|||
self,
|
||||
config_file_specifier: &ModuleSpecifier,
|
||||
) -> Result<TestConfig, AnyError> {
|
||||
let (include, exclude) = (self.include, self.exclude);
|
||||
let files = SerializedFilesConfig { include, exclude };
|
||||
|
||||
Ok(TestConfig {
|
||||
files: self.files.into_resolved(config_file_specifier)?,
|
||||
files: choose_files(files, self.deprecated_files)
|
||||
.into_resolved(config_file_specifier)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct TestConfig {
|
||||
pub files: FilesConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
/// `bench` config representation for serde
|
||||
///
|
||||
/// fields `include` and `exclude` are expanded from [SerializedFilesConfig].
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
struct SerializedBenchConfig {
|
||||
pub files: SerializedFilesConfig,
|
||||
pub include: Vec<String>,
|
||||
pub exclude: Vec<String>,
|
||||
#[serde(rename = "files")]
|
||||
pub deprecated_files: SerializedFilesConfig,
|
||||
}
|
||||
|
||||
impl SerializedBenchConfig {
|
||||
|
@ -451,18 +597,22 @@ impl SerializedBenchConfig {
|
|||
self,
|
||||
config_file_specifier: &ModuleSpecifier,
|
||||
) -> Result<BenchConfig, AnyError> {
|
||||
let (include, exclude) = (self.include, self.exclude);
|
||||
let files = SerializedFilesConfig { include, exclude };
|
||||
|
||||
Ok(BenchConfig {
|
||||
files: self.files.into_resolved(config_file_specifier)?,
|
||||
files: choose_files(files, self.deprecated_files)
|
||||
.into_resolved(config_file_specifier)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct BenchConfig {
|
||||
pub files: FilesConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum LockConfig {
|
||||
Bool(bool),
|
||||
|
@ -999,6 +1149,12 @@ mod tests {
|
|||
use deno_core::serde_json::json;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn unpack_object<T>(result: Result<Option<T>, AnyError>, name: &str) -> T {
|
||||
result
|
||||
.unwrap_or_else(|err| panic!("error parsing {name} object but got {err}"))
|
||||
.unwrap_or_else(|| panic!("{name} object should be defined"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_config_file_absolute() {
|
||||
let path = test_util::testdata_path().join("module_graph/tsconfig.json");
|
||||
|
@ -1043,27 +1199,21 @@ mod tests {
|
|||
"strict": true
|
||||
},
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": ["src/"],
|
||||
"exclude": ["src/testdata/"]
|
||||
},
|
||||
"include": ["src/"],
|
||||
"exclude": ["src/testdata/"],
|
||||
"rules": {
|
||||
"tags": ["recommended"],
|
||||
"include": ["ban-untagged-todo"]
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"files": {
|
||||
"include": ["src/"],
|
||||
"exclude": ["src/testdata/"]
|
||||
},
|
||||
"options": {
|
||||
"useTabs": true,
|
||||
"lineWidth": 80,
|
||||
"indentWidth": 4,
|
||||
"singleQuote": true,
|
||||
"proseWrap": "preserve"
|
||||
}
|
||||
"include": ["src/"],
|
||||
"exclude": ["src/testdata/"],
|
||||
"useTabs": true,
|
||||
"lineWidth": 80,
|
||||
"indentWidth": 4,
|
||||
"singleQuote": true,
|
||||
"proseWrap": "preserve"
|
||||
},
|
||||
"tasks": {
|
||||
"build": "deno run --allow-read --allow-write build.ts",
|
||||
|
@ -1087,38 +1237,38 @@ mod tests {
|
|||
}),
|
||||
);
|
||||
|
||||
let lint_config = config_file
|
||||
.to_lint_config()
|
||||
.expect("error parsing lint object")
|
||||
.expect("lint object should be defined");
|
||||
assert_eq!(lint_config.files.include, vec![PathBuf::from("/deno/src/")]);
|
||||
assert_eq!(
|
||||
lint_config.files.exclude,
|
||||
vec![PathBuf::from("/deno/src/testdata/")]
|
||||
unpack_object(config_file.to_lint_config(), "lint"),
|
||||
LintConfig {
|
||||
files: FilesConfig {
|
||||
include: vec![PathBuf::from("/deno/src/")],
|
||||
exclude: vec![PathBuf::from("/deno/src/testdata/")],
|
||||
},
|
||||
rules: LintRulesConfig {
|
||||
include: Some(vec!["ban-untagged-todo".to_string()]),
|
||||
exclude: None,
|
||||
tags: Some(vec!["recommended".to_string()]),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
lint_config.rules.include,
|
||||
Some(vec!["ban-untagged-todo".to_string()])
|
||||
unpack_object(config_file.to_fmt_config(), "fmt"),
|
||||
FmtConfig {
|
||||
files: FilesConfig {
|
||||
include: vec![PathBuf::from("/deno/src/")],
|
||||
exclude: vec![PathBuf::from("/deno/src/testdata/")],
|
||||
},
|
||||
options: FmtOptionsConfig {
|
||||
use_tabs: Some(true),
|
||||
line_width: Some(80),
|
||||
indent_width: Some(4),
|
||||
single_quote: Some(true),
|
||||
prose_wrap: Some(ProseWrap::Preserve),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
lint_config.rules.tags,
|
||||
Some(vec!["recommended".to_string()])
|
||||
);
|
||||
assert!(lint_config.rules.exclude.is_none());
|
||||
|
||||
let fmt_config = config_file
|
||||
.to_fmt_config()
|
||||
.expect("error parsing fmt object")
|
||||
.expect("fmt object should be defined");
|
||||
assert_eq!(fmt_config.files.include, vec![PathBuf::from("/deno/src/")]);
|
||||
assert_eq!(
|
||||
fmt_config.files.exclude,
|
||||
vec![PathBuf::from("/deno/src/testdata/")],
|
||||
);
|
||||
assert_eq!(fmt_config.options.use_tabs, Some(true));
|
||||
assert_eq!(fmt_config.options.line_width, Some(80));
|
||||
assert_eq!(fmt_config.options.indent_width, Some(4));
|
||||
assert_eq!(fmt_config.options.single_quote, Some(true));
|
||||
|
||||
let tasks_config = config_file.to_tasks_config().unwrap().unwrap();
|
||||
assert_eq!(
|
||||
|
@ -1131,6 +1281,128 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
/// if either "include" or "exclude" is specified, "files" is ignored
|
||||
#[test]
|
||||
fn test_parse_config_with_deprecated_files_field() {
|
||||
let config_text = r#"{
|
||||
"lint": {
|
||||
"files": { "include": ["foo/"], "exclude": ["bar/"] },
|
||||
"include": ["src/"]
|
||||
},
|
||||
"fmt": {
|
||||
"files": { "include": ["foo/"], "exclude": ["bar/"] },
|
||||
"exclude": ["dist/"]
|
||||
},
|
||||
"bench": {
|
||||
"files": { "include": ["foo/"] },
|
||||
"include": ["src/"]
|
||||
},
|
||||
"test": {
|
||||
"files": { "include": ["foo/"] },
|
||||
"include": ["src/"]
|
||||
}
|
||||
}"#;
|
||||
let config_dir = ModuleSpecifier::parse("file:///deno/").unwrap();
|
||||
let config_specifier = config_dir.join("tsconfig.json").unwrap();
|
||||
let config_file = ConfigFile::new(config_text, &config_specifier).unwrap();
|
||||
|
||||
let lint_files = unpack_object(config_file.to_lint_config(), "lint").files;
|
||||
assert_eq!(
|
||||
lint_files,
|
||||
FilesConfig {
|
||||
include: vec![PathBuf::from("/deno/src/")],
|
||||
exclude: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
let fmt_files = unpack_object(config_file.to_fmt_config(), "fmt").files;
|
||||
assert_eq!(
|
||||
fmt_files,
|
||||
FilesConfig {
|
||||
exclude: vec![PathBuf::from("/deno/dist/")],
|
||||
include: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
let test_include = unpack_object(config_file.to_test_config(), "test")
|
||||
.files
|
||||
.include;
|
||||
assert_eq!(test_include, vec![PathBuf::from("/deno/src/")]);
|
||||
|
||||
let bench_include = unpack_object(config_file.to_bench_config(), "bench")
|
||||
.files
|
||||
.include;
|
||||
assert_eq!(bench_include, vec![PathBuf::from("/deno/src/")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_config_with_deprecated_files_field_only() {
|
||||
let config_text = r#"{
|
||||
"lint": { "files": { "include": ["src/"] } },
|
||||
"fmt": { "files": { "include": ["src/"] } },
|
||||
"test": { "files": { "exclude": ["dist/"] } },
|
||||
"bench": { "files": { "exclude": ["dist/"] } }
|
||||
}"#;
|
||||
let config_dir = ModuleSpecifier::parse("file:///deno/").unwrap();
|
||||
let config_specifier = config_dir.join("tsconfig.json").unwrap();
|
||||
let config_file = ConfigFile::new(config_text, &config_specifier).unwrap();
|
||||
|
||||
let lint_include = unpack_object(config_file.to_lint_config(), "lint")
|
||||
.files
|
||||
.include;
|
||||
assert_eq!(lint_include, vec![PathBuf::from("/deno/src/")]);
|
||||
|
||||
let fmt_include = unpack_object(config_file.to_fmt_config(), "fmt")
|
||||
.files
|
||||
.include;
|
||||
assert_eq!(fmt_include, vec![PathBuf::from("/deno/src/")]);
|
||||
|
||||
let test_exclude = unpack_object(config_file.to_test_config(), "test")
|
||||
.files
|
||||
.exclude;
|
||||
assert_eq!(test_exclude, vec![PathBuf::from("/deno/dist/")]);
|
||||
|
||||
let bench_exclude = unpack_object(config_file.to_bench_config(), "bench")
|
||||
.files
|
||||
.exclude;
|
||||
assert_eq!(bench_exclude, vec![PathBuf::from("/deno/dist/")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_config_with_deprecated_fmt_options() {
|
||||
let config_text_both = r#"{
|
||||
"fmt": {
|
||||
"options": {
|
||||
"semiColons": true
|
||||
},
|
||||
"semiColons": false
|
||||
}
|
||||
}"#;
|
||||
let config_text_deprecated = r#"{
|
||||
"fmt": {
|
||||
"options": {
|
||||
"semiColons": true
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let config_specifier =
|
||||
ModuleSpecifier::parse("file:///deno/tsconfig.json").unwrap();
|
||||
let config_file_both =
|
||||
ConfigFile::new(config_text_both, &config_specifier).unwrap();
|
||||
let config_file_deprecated =
|
||||
ConfigFile::new(config_text_deprecated, &config_specifier).unwrap();
|
||||
|
||||
fn unpack_options(config_file: ConfigFile) -> FmtOptionsConfig {
|
||||
unpack_object(config_file.to_fmt_config(), "fmt").options
|
||||
}
|
||||
|
||||
let fmt_options_both = unpack_options(config_file_both);
|
||||
assert_eq!(fmt_options_both.semi_colons, Some(false));
|
||||
|
||||
let fmt_options_deprecated = unpack_options(config_file_deprecated);
|
||||
assert_eq!(fmt_options_deprecated.semi_colons, Some(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_config_with_empty_file() {
|
||||
let config_text = "";
|
||||
|
|
|
@ -227,6 +227,20 @@
|
|||
"description": "Configuration for linter",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will be linted.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will not be linted.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -293,6 +307,20 @@
|
|||
"description": "Configuration for formatter",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will be formatted.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will not be formatted.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -312,6 +340,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"useTabs": {
|
||||
"description": "Whether to use tabs (true) or spaces (false) for indentation.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"lineWidth": {
|
||||
"description": "The width of a line the printer will try to stay under. Note that the printer may exceed this width in certain cases.",
|
||||
"type": "number",
|
||||
"default": 80
|
||||
},
|
||||
"indentWidth": {
|
||||
"description": "The number of characters for an indent.",
|
||||
"type": "number",
|
||||
"default": 2
|
||||
},
|
||||
"singleQuote": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use single quote (true) or double quote (false) for quotation.",
|
||||
"default": false
|
||||
},
|
||||
"proseWrap": {
|
||||
"description": "Define how prose should be wrapped in Markdown files.",
|
||||
"default": "always",
|
||||
"enum": [
|
||||
"always",
|
||||
"never",
|
||||
"preserve"
|
||||
]
|
||||
},
|
||||
"semiColons": {
|
||||
"description": "Whether to prefer using semicolons.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -368,6 +430,20 @@
|
|||
"description": "Configuration for deno test",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will be searched for tests.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will not be searched for tests.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -393,6 +469,20 @@
|
|||
"description": "Configuration for deno bench",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will be searched for benchmarks.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "List of files or directories that will not be searched for benchmarks.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -229,6 +229,12 @@ itest!(fmt_with_config {
|
|||
output: "fmt/fmt_with_config.out",
|
||||
});
|
||||
|
||||
itest!(fmt_with_deprecated_config {
|
||||
args:
|
||||
"fmt --config fmt/with_config/deno.deprecated.jsonc fmt/with_config/subdir",
|
||||
output: "fmt/fmt_with_deprecated_config.out",
|
||||
});
|
||||
|
||||
itest!(fmt_with_config_default {
|
||||
args: "fmt fmt/with_config/subdir",
|
||||
output: "fmt/fmt_with_config.out",
|
||||
|
|
|
@ -77,6 +77,12 @@ itest!(test_with_config2 {
|
|||
output: "test/collect2.out",
|
||||
});
|
||||
|
||||
itest!(test_with_deprecated_config {
|
||||
args: "test --config test/collect/deno.deprecated.jsonc test/collect",
|
||||
exit_code: 0,
|
||||
output: "test/collect.deprecated.out",
|
||||
});
|
||||
|
||||
itest!(test_with_malformed_config {
|
||||
args: "test --config test/collect/deno.malformed.jsonc",
|
||||
exit_code: 1,
|
||||
|
|
8
cli/tests/testdata/bench/collect/deno.jsonc
vendored
8
cli/tests/testdata/bench/collect/deno.jsonc
vendored
|
@ -1,7 +1,5 @@
|
|||
{
|
||||
"bench": {
|
||||
"files": {
|
||||
"exclude": ["./ignore"]
|
||||
}
|
||||
}
|
||||
"bench": {
|
||||
"exclude": ["./ignore"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"bench": {
|
||||
"dont_know_this_field": {}
|
||||
}
|
||||
"bench": {
|
||||
"dont_know_this_field": {}
|
||||
}
|
||||
}
|
||||
|
|
10
cli/tests/testdata/bench/collect/deno2.jsonc
vendored
10
cli/tests/testdata/bench/collect/deno2.jsonc
vendored
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"bench": {
|
||||
"files": {
|
||||
"include": ["./include/"],
|
||||
"exclude": ["./ignore", "./include/2_bench.ts"]
|
||||
}
|
||||
}
|
||||
"bench": {
|
||||
"include": ["./include/"],
|
||||
"exclude": ["./ignore", "./include/2_bench.ts"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "bench" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected `files`
|
||||
unknown field `dont_know_this_field`, expected one of `include`, `exclude`, `files`
|
||||
|
|
6
cli/tests/testdata/fmt/deno.malformed.jsonc
vendored
6
cli/tests/testdata/fmt/deno.malformed.jsonc
vendored
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"fmt": {
|
||||
"files": {
|
||||
"include": ["fmt_with_config/"],
|
||||
"exclude": ["fmt_with_config/b.ts"]
|
||||
},
|
||||
"include": ["fmt_with_config/"],
|
||||
"exclude": ["fmt_with_config/b.ts"],
|
||||
"dont_know_this_field": {},
|
||||
"options": {
|
||||
"useTabs": true
|
||||
|
|
8
cli/tests/testdata/fmt/deno.malformed2.jsonc
vendored
8
cli/tests/testdata/fmt/deno.malformed2.jsonc
vendored
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
"fmt": {
|
||||
"files": {
|
||||
"include": ["fmt_with_config/"],
|
||||
"exclude": ["fmt_with_config/b.ts"],
|
||||
"dont_know_this_field": {}
|
||||
},
|
||||
"include": ["fmt_with_config/"],
|
||||
"exclude": ["fmt_with_config/b.ts"],
|
||||
"dont_know_this_field": {},
|
||||
"options": {
|
||||
"useTabs": true
|
||||
}
|
||||
|
|
3
cli/tests/testdata/fmt/fmt_with_deprecated_config.out
vendored
Normal file
3
cli/tests/testdata/fmt/fmt_with_deprecated_config.out
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Warning: "options" configuration is deprecated. Please use "flat" options instead.
|
||||
Warning: "files" configuration is deprecated. Please use "include" and "exclude" instead.
|
||||
Checked 2 files
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "fmt" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected `options` or `files`
|
||||
unknown field `dont_know_this_field`, expected one of `useTabs`, `lineWidth`, `indentWidth`, `singleQuote`, `proseWrap`, `semiColons`, `options`, `include`, `exclude`, `files`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "fmt" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected `include` or `exclude`
|
||||
unknown field `dont_know_this_field`, expected one of `useTabs`, `lineWidth`, `indentWidth`, `singleQuote`, `proseWrap`, `semiColons`, `options`, `include`, `exclude`, `files`
|
||||
|
|
20
cli/tests/testdata/fmt/with_config/deno.deprecated.jsonc
vendored
Normal file
20
cli/tests/testdata/fmt/with_config/deno.deprecated.jsonc
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"fmt": {
|
||||
"files": {
|
||||
"include": [
|
||||
"./subdir/"
|
||||
],
|
||||
"exclude": [
|
||||
"./subdir/b.ts"
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"useTabs": true,
|
||||
"lineWidth": 40,
|
||||
"indentWidth": 8,
|
||||
"singleQuote": true,
|
||||
"proseWrap": "always",
|
||||
"semiColons": false
|
||||
}
|
||||
}
|
||||
}
|
28
cli/tests/testdata/fmt/with_config/deno.jsonc
vendored
28
cli/tests/testdata/fmt/with_config/deno.jsonc
vendored
|
@ -1,20 +1,16 @@
|
|||
{
|
||||
"fmt": {
|
||||
"files": {
|
||||
"include": [
|
||||
"./subdir/"
|
||||
],
|
||||
"exclude": [
|
||||
"./subdir/b.ts"
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"useTabs": true,
|
||||
"lineWidth": 40,
|
||||
"indentWidth": 8,
|
||||
"singleQuote": true,
|
||||
"proseWrap": "always",
|
||||
"semiColons": false
|
||||
}
|
||||
"include": [
|
||||
"./subdir/"
|
||||
],
|
||||
"exclude": [
|
||||
"./subdir/b.ts"
|
||||
],
|
||||
"useTabs": true,
|
||||
"lineWidth": 40,
|
||||
"indentWidth": 8,
|
||||
"singleQuote": true,
|
||||
"proseWrap": "always",
|
||||
"semiColons": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"]
|
||||
},
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"],
|
||||
"rules": {
|
||||
"tags": ["recommended"],
|
||||
"include": ["ban-untagged-todo"]
|
||||
|
|
6
cli/tests/testdata/lint/Deno.jsonc
vendored
6
cli/tests/testdata/lint/Deno.jsonc
vendored
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"]
|
||||
},
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"],
|
||||
"rules": {
|
||||
"tags": ["recommended"],
|
||||
"include": ["ban-untagged-todo"]
|
||||
|
|
6
cli/tests/testdata/lint/Deno.malformed.jsonc
vendored
6
cli/tests/testdata/lint/Deno.malformed.jsonc
vendored
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"]
|
||||
},
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"],
|
||||
"dont_know_this_field": {},
|
||||
"rules": {
|
||||
"tags": ["recommended"],
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"],
|
||||
"dont_know_this_field": {}
|
||||
},
|
||||
"include": ["with_config/"],
|
||||
"exclude": ["with_config/b.ts"],
|
||||
"dont_know_this_field": {},
|
||||
"rules": {
|
||||
"tags": ["recommended"],
|
||||
"include": ["ban-untagged-todo"]
|
||||
|
|
14
cli/tests/testdata/lint/Deno.no_tags.jsonc
vendored
14
cli/tests/testdata/lint/Deno.no_tags.jsonc
vendored
|
@ -1,13 +1,11 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"include": [
|
||||
"with_config/"
|
||||
],
|
||||
"exclude": [
|
||||
"with_config/b.ts"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"with_config/"
|
||||
],
|
||||
"exclude": [
|
||||
"with_config/b.ts"
|
||||
],
|
||||
"rules": {
|
||||
"include": [
|
||||
"ban-untagged-todo"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "lint" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected one of `rules`, `files`, `report`
|
||||
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "lint" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected `include` or `exclude`
|
||||
unknown field `dont_know_this_field`, expected one of `rules`, `include`, `exclude`, `files`, `report`
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
"lint": {
|
||||
"files": {
|
||||
"exclude": [
|
||||
"ignored.ts"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"ignored.ts"
|
||||
],
|
||||
"rules": {
|
||||
"exclude": [
|
||||
"camelcase"
|
||||
|
|
10
cli/tests/testdata/test/collect.deprecated.out
vendored
Normal file
10
cli/tests/testdata/test/collect.deprecated.out
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
Warning: "files" configuration is deprecated. Please use "include" and "exclude" instead.
|
||||
Check [WILDCARD]/test/collect/include/2_test.ts
|
||||
Check [WILDCARD]/test/collect/include/test.ts
|
||||
Check [WILDCARD]/test/collect/test.ts
|
||||
running 0 tests from ./test/collect/include/2_test.ts
|
||||
running 0 tests from ./test/collect/include/test.ts
|
||||
running 0 tests from ./test/collect/test.ts
|
||||
|
||||
ok | 0 passed | 0 failed ([WILDCARD])
|
||||
|
7
cli/tests/testdata/test/collect/deno.deprecated.jsonc
vendored
Normal file
7
cli/tests/testdata/test/collect/deno.deprecated.jsonc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"test": {
|
||||
"files": {
|
||||
"exclude": ["./ignore"]
|
||||
}
|
||||
}
|
||||
}
|
4
cli/tests/testdata/test/collect/deno.jsonc
vendored
4
cli/tests/testdata/test/collect/deno.jsonc
vendored
|
@ -1,7 +1,5 @@
|
|||
{
|
||||
"test": {
|
||||
"files": {
|
||||
"exclude": ["./ignore"]
|
||||
}
|
||||
"exclude": ["./ignore"]
|
||||
}
|
||||
}
|
||||
|
|
6
cli/tests/testdata/test/collect/deno2.jsonc
vendored
6
cli/tests/testdata/test/collect/deno2.jsonc
vendored
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"test": {
|
||||
"files": {
|
||||
"include": ["./include/"],
|
||||
"exclude": ["./ignore", "./include/2_test.ts"]
|
||||
}
|
||||
"include": ["./include/"],
|
||||
"exclude": ["./ignore", "./include/2_test.ts"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: Failed to parse "test" configuration
|
||||
|
||||
Caused by:
|
||||
unknown field `dont_know_this_field`, expected `files`
|
||||
unknown field `dont_know_this_field`, expected one of `include`, `exclude`, `files`
|
||||
|
|
Loading…
Reference in a new issue