diff --git a/docs/specs/error.yml b/docs/specs/error.yml index f700026de97..aecc2812a50 100644 --- a/docs/specs/error.yml +++ b/docs/specs/error.yml @@ -153,8 +153,8 @@ outputs: pig4.jpg: a.json: .errors.log: | - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'br2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":1,"end_line":1,"column":2,"end_column":5} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'br2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":2,"end_line":2,"column":2,"end_column":5} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'br2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":1,"end_line":1,"column":2,"end_column":5} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'br2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":2,"end_line":2,"column":2,"end_column":5} {"message_severity":"info","code":"exceed-max-file-errors","message":"Info count exceed '2'. Build will continue but newer logs in 'a.md' will be ignored.","file":"a.md","line":0,"end_line":0,"column":0,"end_column":0} --- diff --git a/docs/specs/markdown.yml b/docs/specs/markdown.yml index 11a9f40def8..953a39eec36 100644 --- a/docs/specs/markdown.yml +++ b/docs/specs/markdown.yml @@ -311,10 +311,10 @@ outputs: docs/a.json: | { "conceptual": "

body

" } .errors.log: | - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'script' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":1,"column":2} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'link' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":2,"column":2} - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'style' on tag 'div' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":3,"column":6} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'style' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":4,"column":2} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'script' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":1,"column":2} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'link' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":2,"column":2} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'style' on tag 'div' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":3,"column":6} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'style' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":4,"column":2} --- # markdown table with styles is allowed inputs: @@ -389,7 +389,7 @@ outputs: {"message_severity":"warning","code":"bookmark-not-found","message":"Cannot find bookmark '#title-3' in 'docs/a.md', did you mean '#title-1'?","file":"docs/b.md","line":2,"column":1} {"message_severity":"warning","code":"bookmark-not-found","message":"Cannot find bookmark '#title-3' in 'docs/a.md', did you mean '#title-1'?","file":"docs/a.md","line":4,"column":1} {"message_severity":"warning","code":"bookmark-not-found","message":"Cannot find bookmark '#title-3' in 'docs/a.md', did you mean '#title-1'?","file":"docs/d.md","line":1,"column":1} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'h2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":8,"column":2} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'h2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/a.md","line":8,"column":2} --- # only validate bookmarks when the referenced file existed inputs: @@ -520,10 +520,10 @@ outputs: docs/c.json: | { "conceptual": "

\n" } .errors.log: | - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'style' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/c.md","line":1,"column":4} - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'style' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/b.md","line":1,"column":4} - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'onclick' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/c.md","line":1,"column":27} - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'onclick' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/b.md","line":1,"column":27} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'style' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/c.md","line":1,"column":4} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'style' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/b.md","line":1,"column":4} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'onclick' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/c.md","line":1,"column":27} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'onclick' on tag 'a' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"docs/b.md","line":1,"column":27} --- # yaml header shouldn't be array inputs: diff --git a/docs/specs/moniker.yml b/docs/specs/moniker.yml index 6f193bcaaa7..828255effdd 100644 --- a/docs/specs/moniker.yml +++ b/docs/specs/moniker.yml @@ -1407,7 +1407,7 @@ inputs: outputs: docs/v1/a.json: .errors.log: | - {"message_severity":"error","code":"moniker-range-invalid","message":"Invalid moniker range '>= netcore-2.0': Moniker 'netcore-2.0' is not defined.","file":"docfx.yml","line":2,"column":17} + {"message_severity":"error","code":"moniker-range-missing","message":"Invalid moniker range '>= netcore-2.0': Moniker 'netcore-2.0' is not defined.","file":"docfx.yml","line":2,"column":17} --- # Invalid moniker range in file inputs: @@ -1432,8 +1432,8 @@ inputs: } outputs: .errors.log: | - {"message_severity":"error","code":"moniker-range-invalid","message":"Invalid moniker range 'netcore-1.2': Moniker 'netcore-1.2' is not defined.","file":"docs/v1/a.md","line":2,"column":15} - {"message_severity":"error","code":"moniker-range-invalid","message":"Invalid moniker range '<= netcore-1.2': Moniker 'netcore-1.2' is not defined.","file":"docs/v1/b.md","line":2,"column":1} + {"message_severity":"error","code":"moniker-range-missing","message":"Invalid moniker range 'netcore-1.2': Moniker 'netcore-1.2' is not defined.","file":"docs/v1/a.md","line":2,"column":15} + {"message_severity":"error","code":"moniker-range-missing","message":"Invalid moniker range '<= netcore-1.2': Moniker 'netcore-1.2' is not defined.","file":"docs/v1/b.md","line":2,"column":1} {"message_severity":"error","code":"moniker-range-out-of-scope","message":"No moniker intersection between docfx.yml/docfx.json and file metadata. Config moniker range '>= netcore-1.0' is 'netcore-1.0', while file monikers is ''.","file":"docs/v1/a.md","line":2,"column":15} {"message_severity":"warning","code":"moniker-zone-empty","message":"No intersection between zone and file level monikers. The result of zone level range string '<= netcore-1.2' is '', while file level monikers is 'netcore-1.0'.","file":"docs/v1/b.md","line":2,"column":1} --- @@ -1699,7 +1699,7 @@ inputs: } outputs: .errors.log: | - {"message_severity":"error","code":"moniker-range-invalid","message":"Invalid monikers: Moniker 'netcore-1.1' is not defined.","file":"docs/v1/TOC.md","line":2,"column":11} + {"message_severity":"error","code":"moniker-range-key-undefined","message":"Invalid monikers: Moniker 'netcore-1.1' is not defined.","file":"docs/v1/TOC.md","line":2,"column":11} {"message_severity":"error","code":"moniker-range-out-of-scope","message":"No moniker intersection between docfx.yml/docfx.json and file metadata. Config moniker range '>= netcore-2.0' is 'netcore-2.0', while file monikers is ''.","file":"docs/v1/TOC.md","line":2,"column":11} --- # Should take monikerRange as final monikers even it outputs empty diff --git a/docs/specs/validation/content-validation.yml b/docs/specs/validation/content-validation.yml index d082b9303fb..22b2ffd55f0 100644 --- a/docs/specs/validation/content-validation.yml +++ b/docs/specs/validation/content-validation.yml @@ -41,10 +41,10 @@ inputs: outputs: a.json: .errors.log: | - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'H2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":1,"column":2} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'BUTTON' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":2,"column":2} - {"message_severity":"info","code":"disallowed-html","message":"HTML tag 'h1' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":4,"column":2} - {"message_severity":"info","code":"disallowed-html","message":"HTML attribute 'onclick' on tag 'div' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":5,"column":6} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'H2' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":1,"column":2} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'BUTTON' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":2,"column":2} + {"message_severity":"info","code":"disallowed-html-tag","message":"HTML tag 'h1' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":4,"column":2} + {"message_severity":"info","code":"disallowed-html-attribute","message":"HTML attribute 'onclick' on tag 'div' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.","file":"a.md","line":5,"column":6} --- # Suppress disallowed HTML on archive content inputs: diff --git a/src/docfx/Errors.cs b/src/docfx/Errors.cs index f5f7594abf8..b2a1bcfa91a 100644 --- a/src/docfx/Errors.cs +++ b/src/docfx/Errors.cs @@ -457,11 +457,39 @@ public static Error MonikerOverlapping(string uid, List files, IEnumer => new Error(ErrorLevel.Error, "moniker-overlapping", $"Two or more documents with the same uid `{uid}`({StringUtility.Join(files)}) have defined overlapping moniker: {StringUtility.Join(overlappingMonikers)}."); /// - /// Failed to parse moniker string. + /// Failed to parse moniker string: moniker is not defined. /// /// Behavior: ✔️ Message: ❌ - public static Error MonikerRangeInvalid(SourceInfo? operand, FormattableString message) - => new Error(ErrorLevel.Error, "moniker-range-invalid", message, operand); + public static Error MonikerRangeMissing(SourceInfo operand, string moniker) + => new Error(ErrorLevel.Error, "moniker-range-missing", $"Invalid moniker range '{operand}': Moniker '{moniker}' is not defined.", operand); + + /// + /// Failed to parse moniker string: parse ends before reaching end of string + /// + /// Behavior: ✔️ Message: ❌ + public static Error MonikerRangeUnrecognized(SourceInfo? operand, string rangeString) + => new Error(ErrorLevel.Error, "moniker-range-unrecognized", $"Parse ends before reaching end of string, unrecognized string: '{rangeString}'.", operand); + + /// + /// Failed to parse moniker string: expect a comparator set + /// + /// Behavior: ✔️ Message: ❌ + public static Error MonikerRangeMissComparator(SourceInfo? operand, string rangeString) + => new Error(ErrorLevel.Error, "moniker-range-miss-comparator", $"Expect a comparator set, but got '{rangeString}'.", operand); + + /// + /// Failed to parse moniker string: expect a moniker string + /// + /// Behavior: ✔️ Message: ❌ + public static Error MonikerRangeMissMoniker(SourceInfo? operand, string rangeString) + => new Error(ErrorLevel.Error, "moniker-range-miss-moniker", $"Expect a moniker string, but got '{rangeString}'.", operand); + + /// + /// Failed to parse moniker string: Moniker key is not defined. + /// + /// Behavior: ✔️ Message: ❌ + public static Error MonikerRangeKeyUndefined(SourceInfo? operand, string key) + => new Error(ErrorLevel.Error, "moniker-range-key-undefined", $"Invalid monikers: Moniker '{key}' is not defined.", operand); /// /// MonikerRange is not defined in docfx.yml or doesn't match an article.md, @@ -755,13 +783,13 @@ public static Error Custom404Page(FilePath file) /// Html Tag value must be in allowed list /// public static Error DisallowedHtml(SourceInfo? source, string tag) - => new Error(ErrorLevel.Info, "disallowed-html", $"HTML tag '{tag}' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.", source, propertyPath: tag); + => new Error(ErrorLevel.Info, "disallowed-html-tag", $"HTML tag '{tag}' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.", source, propertyPath: tag); /// /// Html Attribute value must be in allowed list /// public static Error DisallowedHtml(SourceInfo? source, string tag, string attribute) - => new Error(ErrorLevel.Info, "disallowed-html", $"HTML attribute '{attribute}' on tag '{tag}' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.", source, propertyPath: $"{tag}_{attribute}"); + => new Error(ErrorLevel.Info, "disallowed-html-attribute", $"HTML attribute '{attribute}' on tag '{tag}' isn't allowed. Disallowed HTML poses a security risk and must be replaced with approved Docs Markdown syntax.", source, propertyPath: $"{tag}_{attribute}"); } public static class DependencyRepository diff --git a/src/docfx/docfx.csproj b/src/docfx/docfx.csproj index 80db66f2240..af0da93679d 100644 --- a/src/docfx/docfx.csproj +++ b/src/docfx/docfx.csproj @@ -41,6 +41,7 @@ + @@ -49,4 +50,4 @@ - + \ No newline at end of file diff --git a/src/docfx/lib/moniker/EvaluatorWithMonikersVisitor.cs b/src/docfx/lib/moniker/EvaluatorWithMonikersVisitor.cs index eacfe4aeabe..80b89e30bac 100644 --- a/src/docfx/lib/moniker/EvaluatorWithMonikersVisitor.cs +++ b/src/docfx/lib/moniker/EvaluatorWithMonikersVisitor.cs @@ -26,8 +26,7 @@ public EvaluatorWithMonikersVisitor(MonikerDefinitionModel monikerDefinition) { if (!MonikerOrder.TryGetValue(expression.Operand, out var moniker)) { - return (Errors.Versioning.MonikerRangeInvalid( - monikerRange, $"Invalid moniker range '{monikerRange}': Moniker '{expression.Operand}' is not defined."), Array.Empty()); + return (Errors.Versioning.MonikerRangeMissing(monikerRange, expression.Operand), Array.Empty()); } return expression.Operator switch diff --git a/src/docfx/lib/moniker/ExpressionCreator.cs b/src/docfx/lib/moniker/ExpressionCreator.cs index c81e015985f..ad4a23af73e 100644 --- a/src/docfx/lib/moniker/ExpressionCreator.cs +++ b/src/docfx/lib/moniker/ExpressionCreator.cs @@ -28,7 +28,7 @@ public static (List, IExpression?) Create(string rangeString, SourceInfo? errors.AddRange(rangeErrors); if (!string.IsNullOrWhiteSpace(rangeString)) { - errors.Add(Errors.Versioning.MonikerRangeInvalid(source, $"Parse ends before reaching end of string, unrecognized string: '{rangeString}'.")); + errors.Add(Errors.Versioning.MonikerRangeUnrecognized(source, rangeString)); } return (errors, expression); @@ -75,7 +75,7 @@ private static (List, IExpression?) GetComparatorSet(ref string rangeStri if (result is null) { - errors.Add(Errors.Versioning.MonikerRangeInvalid(source, $"Expect a comparator set, but got '{rangeString}'.")); + errors.Add(Errors.Versioning.MonikerRangeMissComparator(source, rangeString)); } return (errors, result); } @@ -101,7 +101,7 @@ private static bool TryGetComparator(ref string rangeString, SourceInfo? source, } else { - error = Errors.Versioning.MonikerRangeInvalid(source, $"Expect a moniker string, but got '{rangeString}'."); + error = Errors.Versioning.MonikerRangeMissMoniker(source, rangeString); return false; } } diff --git a/src/docfx/lib/moniker/MonikerRangeParser.cs b/src/docfx/lib/moniker/MonikerRangeParser.cs index c9e111b358f..1a73375dda1 100644 --- a/src/docfx/lib/moniker/MonikerRangeParser.cs +++ b/src/docfx/lib/moniker/MonikerRangeParser.cs @@ -29,7 +29,7 @@ public MonikerList Validate(ErrorBuilder errors, SourceInfo[] monikers) { if (!_monikersEvaluator.MonikerMap.ContainsKey(key)) { - errors.Add(Errors.Versioning.MonikerRangeInvalid(moniker, $"Invalid monikers: Moniker '{key}' is not defined.")); + errors.Add(Errors.Versioning.MonikerRangeKeyUndefined(moniker, key)); } else { diff --git a/test/docfx.Test/lib/MonikerRangeParserTest.cs b/test/docfx.Test/lib/MonikerRangeParserTest.cs index 0b7c7550130..92bdc7b3c84 100644 --- a/test/docfx.Test/lib/MonikerRangeParserTest.cs +++ b/test/docfx.Test/lib/MonikerRangeParserTest.cs @@ -140,7 +140,7 @@ public void TestNullDefinitionShouldFail() monikerRangeParser.Parse(errors, new SourceInfo("netcore-1.0")); Assert.Collection(errors, error => { - Assert.Equal("moniker-range-invalid", error.Code); + Assert.Equal("moniker-range-missing", error.Code); Assert.Equal("Invalid moniker range 'netcore-1.0': Moniker 'netcore-1.0' is not defined.", error.Message); }); }