@@ -2,7 +2,8 @@ import {dump as yamlDump} from 'js-yaml';
22import {
33 CodeAnalyzer ,
44 CodeAnalyzerConfig ,
5- ConfigDescription ,
5+ ConfigDescription , ConfigFieldDescription ,
6+ EngineConfig ,
67 Rule ,
78 RuleSelection ,
89 SeverityLevel
@@ -83,37 +84,51 @@ abstract class YamlFormatter {
8384 return yamlCode . replace ( / ( \r ? \n | $ ) / , ` ${ comment } $1` ) ;
8485 }
8586
86- private toYamlField ( fieldName : string , userValue : unknown , defaultValue : unknown ) : string {
87- if ( looksLikeAPathValue ( userValue ) && userValue === defaultValue ) {
88- // We special handle a path value when it is equal to the default value, making it equal null because
89- // chances are it is a derived file or folder value based on the specific environment that we do not want to
90- // actually want to hard code since checking in the config to CI/CD system may create a different value
91- const commentText : string = getMessage ( BundleName . ConfigModel , 'template.last-calculated-as' , [ JSON . stringify ( userValue ) ] ) ;
92- return this . toYamlUncheckedFieldWithInlineComment ( fieldName , null , commentText ) ;
93- } else if ( JSON . stringify ( userValue ) === JSON . stringify ( defaultValue ) ) {
94- return this . toYamlUncheckedField ( fieldName , userValue ) ;
87+ private toYamlFieldUsingFieldDescription ( fieldName : string , resolvedValue : unknown , fieldDescription : ConfigFieldDescription ) : string {
88+ const resolvedValueJson : string = JSON . stringify ( resolvedValue ) ;
89+ const defaultValueJson : string = JSON . stringify ( fieldDescription . defaultValue ) ;
90+
91+ if ( ! fieldDescription . wasSuppliedByUser && resolvedValueJson !== defaultValueJson ) {
92+ // Whenever the user did not supply the value themselves but the resolved value is different from the
93+ // default value, this means the value was not a "fixed" value but a value "calculated" at runtime.
94+ // Since "calculated" values often depend on the specific environment, we do not want to actually hard code
95+ // this value into the config since checking in the config to CI/CD system may create a different value.
96+ const commentText : string = getMessage ( BundleName . ConfigModel , 'template.last-calculated-as' , [ resolvedValueJson ] ) ;
97+ return this . toYamlUncheckedFieldWithInlineComment ( fieldName , fieldDescription . defaultValue , commentText ) ;
9598 }
9699
97- userValue = replaceAbsolutePathsWithRelativePathsWherePossible ( userValue , this . userContext . config . getConfigRoot ( ) + path . sep ) ;
100+ return this . toYamlField ( fieldName , resolvedValue , fieldDescription . defaultValue ) ;
101+ }
102+
103+ private toYamlField ( fieldName : string , resolvedValue : unknown , defaultValue : unknown ) : string {
104+ const resolvedValueJson : string = JSON . stringify ( resolvedValue ) ;
105+ const defaultValueJson : string = JSON . stringify ( defaultValue ) ;
98106
99- const commentText : string = getMessage ( BundleName . ConfigModel , 'template.modified-from' , [ JSON . stringify ( defaultValue ) ] ) ;
100- return this . toYamlUncheckedFieldWithInlineComment ( fieldName , userValue , commentText ) ;
107+ if ( resolvedValueJson === defaultValueJson ) {
108+ return this . toYamlUncheckedField ( fieldName , resolvedValue ) ;
109+ }
110+
111+ const commentText : string = getMessage ( BundleName . ConfigModel , 'template.modified-from' , [ defaultValueJson ] ) ;
112+ resolvedValue = replaceAbsolutePathsWithRelativePathsWherePossible ( resolvedValue , this . userContext . config . getConfigRoot ( ) + path . sep ) ;
113+ return this . toYamlUncheckedFieldWithInlineComment ( fieldName , resolvedValue , commentText ) ;
101114 }
102115
103116 toYaml ( ) : string {
104- const topLevelDescription : ConfigDescription = CodeAnalyzerConfig . getConfigDescription ( ) ;
105- return this . toYamlSectionHeadingComment ( topLevelDescription . overview ! ) + '\n' +
117+ const topLevelDescription : ConfigDescription = this . userContext . config . getConfigDescription ( ) ;
118+ return this . toYamlSectionHeadingComment ( topLevelDescription . overview ) + '\n' +
106119 '\n' +
107- this . toYamlComment ( topLevelDescription . fieldDescriptions ! . config_root ) + '\n' +
108- this . toYamlField ( 'config_root' , this . userContext . config . getConfigRoot ( ) , this . defaultContext . config . getConfigRoot ( ) ) + '\n' +
120+ this . toYamlComment ( topLevelDescription . fieldDescriptions . config_root . descriptionText ) + '\n' +
121+ this . toYamlFieldUsingFieldDescription ( 'config_root' , this . userContext . config . getConfigRoot ( ) ,
122+ topLevelDescription . fieldDescriptions . config_root ) + '\n' +
109123 '\n' +
110- this . toYamlComment ( topLevelDescription . fieldDescriptions ! . log_folder ) + '\n' +
111- this . toYamlField ( 'log_folder' , this . userContext . config . getLogFolder ( ) , this . defaultContext . config . getLogFolder ( ) ) + '\n' +
124+ this . toYamlComment ( topLevelDescription . fieldDescriptions . log_folder . descriptionText ) + '\n' +
125+ this . toYamlFieldUsingFieldDescription ( 'log_folder' , this . userContext . config . getLogFolder ( ) ,
126+ topLevelDescription . fieldDescriptions . log_folder ) + '\n' +
112127 '\n' +
113- this . toYamlComment ( topLevelDescription . fieldDescriptions ! . rules ) + '\n' +
128+ this . toYamlComment ( topLevelDescription . fieldDescriptions . rules . descriptionText ) + '\n' +
114129 this . toYamlRuleOverrides ( ) + '\n' +
115130 '\n' +
116- this . toYamlComment ( topLevelDescription . fieldDescriptions ! . engines ) + '\n' +
131+ this . toYamlComment ( topLevelDescription . fieldDescriptions . engines . descriptionText ) + '\n' +
117132 this . toYamlEngineOverrides ( ) + '\n' +
118133 '\n' +
119134 this . toYamlSectionHeadingComment ( getMessage ( BundleName . ConfigModel , 'template.common.end-of-config' ) ) + '\n' ;
@@ -176,23 +191,21 @@ abstract class YamlFormatter {
176191 }
177192
178193 private toYamlEngineOverridesForEngine ( engineName : string ) : string {
179- const engineConfigDescriptor = this . userContext . core . getEngineConfigDescription ( engineName ) ;
180- const userEngineConfig = this . userContext . core . getEngineConfig ( engineName ) ;
181- const defaultEngineConfig = this . defaultContext . core . getEngineConfig ( engineName ) ;
194+ const engineConfigDescriptor : ConfigDescription = this . userContext . core . getEngineConfigDescription ( engineName ) ;
195+ const userEngineConfig : EngineConfig = this . userContext . core . getEngineConfig ( engineName ) ;
182196
183197 let yamlCode : string = '\n' +
184- this . toYamlSectionHeadingComment ( engineConfigDescriptor . overview ! ) + '\n' +
198+ this . toYamlSectionHeadingComment ( engineConfigDescriptor . overview ) + '\n' +
185199 `${ engineName } :\n` ;
186200 // By fiat, the field description will always include, at minimum, an entry for "disable_engine", so we can
187201 // assume that the object is not undefined.
188- for ( const configField of Object . keys ( engineConfigDescriptor . fieldDescriptions ! ) ) {
189- const fieldDescription = engineConfigDescriptor . fieldDescriptions ! [ configField ] ;
190- const defaultValue = defaultEngineConfig [ configField ] ?? null ;
191- const userValue = userEngineConfig [ configField ] ?? defaultValue ;
202+ for ( const configField of Object . keys ( engineConfigDescriptor . fieldDescriptions ) ) {
203+ const fieldDescription : ConfigFieldDescription = engineConfigDescriptor . fieldDescriptions [ configField ] ;
204+ const userValue = userEngineConfig [ configField ] ?? fieldDescription . defaultValue ;
192205 // Add a leading newline to visually break up the property from the previous one.
193206 yamlCode += '\n' +
194- indent ( this . toYamlComment ( fieldDescription ) , 2 ) + '\n' +
195- indent ( this . toYamlField ( configField , userValue , defaultValue ) , 2 ) + '\n' ;
207+ indent ( this . toYamlComment ( fieldDescription . descriptionText ) , 2 ) + '\n' +
208+ indent ( this . toYamlFieldUsingFieldDescription ( configField , userValue , fieldDescription ) , 2 ) + '\n' ;
196209 }
197210 return yamlCode . trimEnd ( ) ;
198211 }
@@ -218,10 +231,6 @@ class StyledYamlFormatter extends YamlFormatter {
218231 }
219232}
220233
221- function looksLikeAPathValue ( value : unknown ) {
222- return typeof ( value ) === 'string' && ! value . includes ( '\n' ) && value . includes ( path . sep ) ;
223- }
224-
225234function replaceAbsolutePathsWithRelativePathsWherePossible ( value : unknown , parentFolder : string ) : unknown {
226235 if ( typeof value === 'string' ) {
227236 // Check if the string starts with the parent folder
0 commit comments