import * as vscode from 'vscode' ; import { ALSyntaxHelper } from './alSyntaxHelper' ; import { StringHelper } from '../tools/stringHelper' ; import { NameValue } from '../tools/nameValue' ; export class ALSyntaxWriter { private content : string ; private indentText : string ; private indentPart : string ; public applicationArea : string ; private propertiesCache : NameValue [ ] ; private fieldToolTip : string ; private fieldToolTipComment : string ; private useTableFieldDescriptionAsToolTip : boolean ; private noEmptyLinesAtTheEndOfWizardGeneratedFiles : boolean ; private eol : string ; constructor ( destUri ) { let config = vscode . workspace . getConfiguration ( 'alOutline' , destUri ) ; this . content = "" ; this . indentText = "" ; this . indentPart = "    " ; this . applicationArea = StringHelper . emptyIfNotDef ( config . get < string > ( 'defaultAppArea' ) ) ; this . fieldToolTip = StringHelper . emptyIfNotDef ( config . get < string > ( 'pageFieldToolTip' ) ) ; this . fieldToolTipComment = StringHelper . emptyIfNotDef ( config . get < string > ( 'pageFieldToolTipComment' ) ) ; this . useTableFieldDescriptionAsToolTip = ! ! config . get < boolean > ( 'useTableFieldDescriptionAsToolTip' ) ; this . noEmptyLinesAtTheEndOfWizardGeneratedFiles = ! ! config . get < boolean > ( 'noEmptyLinesAtTheEndOfWizardGeneratedFiles' ) ; this . propertiesCache = [ ] ; this . eol = StringHelper . getDefaultEndOfLine ( destUri ) ; } public toString ( ) { return this . content ; } public toWizardGeneratedString ( ) { if ( this . noEmptyLinesAtTheEndOfWizardGeneratedFiles ) return this . removeEndingEmptyLines ( ) ; return this . content ; } protected removeEndingEmptyLines ( ) { let len = this . content . length ; let eolen = this . eol . length ; while ( ( len > 0 ) && ( this . content . substring ( len - eolen , len ) == this . eol ) ) { len -= eolen ; } if ( len > 0 ) return this . content . substring ( 0 , len ) ; return '' ; } public incIndent ( ) { this . indentText += this . indentPart ; } public decIndent ( ) { if ( this . indentText . length > this . indentPart . length ) this . indentText = this . indentText . substr ( 0 , this . indentText . length - this . indentPart . length ) ; else this . indentText = "" ; } public setIndent ( value ) { let text = " " ; this . indentText = text . repeat ( value ) ; } public writeLine ( line ) { this . content += ( this . indentText + line + this . eol ) ; } public writeStartBlock ( ) { this . writeLine ( "{" ) ; this . incIndent ( ) ; } public writeEndBlock ( ) { this . decIndent ( ) ; this . writeLine ( "}" ) ; } public writeStartNamedBlock ( name ) { this . writeLine ( name ) ; this . writeStartBlock ( ) ; } public writeStartNameSourceBlock ( blockName , propertyName , propertySource ) { this . writeLine ( blockName + "(" + propertyName + "; " + propertySource + ")" ) ; this . writeStartBlock ( ) ; } public writeNameSourceBlock ( blockName , propertyName , propertySource ) { this . writeStartNameSourceBlock ( blockName , propertyName , propertySource ) ; this . writeEndBlock ( ) ; } public writeStartObject ( type , id , name ) { var objectIdText ; if ( ( id == '' ) || ( id == '0' ) ) objectIdText = 'id' ; else objectIdText = id . toString ( ) ; name = ALSyntaxHelper . toNameText ( name ) ; this . writeLine ( type + " " + objectIdText + " " + name ) ; this . writeStartBlock ( ) ; } public writeStartInterface ( name ) { name = ALSyntaxHelper . toNameText ( name ) ; this . writeLine ( "interface " + name ) ; this . writeStartBlock ( ) ; } public writeStartCodeunit ( id , name , interfaceName ) { var objectIdText ; if ( ( id == '' ) || ( id == '0' ) ) objectIdText = 'id' ; else objectIdText = id . toString ( ) ; name = ALSyntaxHelper . toNameText ( name ) ; let interfaceText = "" ; if ( ( interfaceName ) && ( interfaceName . length > 0 ) ) interfaceText = " implements " + ALSyntaxHelper . toNameText ( interfaceName ) ; this . writeLine ( "codeunit " + objectIdText + " " + name + interfaceText ) ; this . writeStartBlock ( ) ; } public writeStartExtensionObject ( type , id , extname , targetName ) { var objectIdText ; if ( ( id == '' ) || ( id == '0' ) ) objectIdText = 'id' ; else objectIdText = id . toString ( ) ; extname = ALSyntaxHelper . toNameText ( extname ) ; targetName = ALSyntaxHelper . toNameText ( targetName ) ; this . writeLine ( type + " " + objectIdText + " " + extname + " extends " + targetName ) ; this . writeStartBlock ( ) ; } public writeEndObject ( ) { this . writeEndBlock ( ) ; } public writeStartLayout ( ) { this . writeLine ( "layout" ) ; this . writeStartBlock ( ) ; } public writeEndLayout ( ) { this . writeEndBlock ( ) ; } public writeStartActions ( ) { this . writeLine ( "actions" ) ; this . writeStartBlock ( ) ; } public writeEndActions ( ) { this . writeEndBlock ( ) ; } public writeStartDataset ( ) { this . writeLine ( "dataset" ) ; this . writeStartBlock ( ) ; } public writeEndDataset ( ) { this . writeEndBlock ( ) ; } public writeStartRequestPage ( ) { this . writeLine ( "requestpage" ) ; this . writeStartBlock ( ) ; } public writeEndRequestPage ( ) { this . writeEndBlock ( ) ; } public writeStartFields ( ) { this . writeLine ( "fields" ) ; this . writeStartBlock ( ) ; } public writeEndFields ( ) { this . writeEndBlock ( ) ; } public writeStartAdd ( name ) { this . writeStartGroup ( "add" , name ) ; } public writeStartGroup ( type , name ) { this . writeLine ( type + "(" + name + ")" ) ; this . writeStartBlock ( ) ; } public writeProperty ( name , value ) { this . writeLine ( name + " = " + value + ";" ) ; } public writeStartProperty ( name ) { this . writeLine ( name + " =" ) ; this . incIndent ( ) ; } public writePropertyValue ( value , lastValue ) { if ( lastValue ) { this . writeLine ( value + ";" ) ; this . decIndent ( ) ; } else this . writeLine ( value + "," ) ; } public addProperty ( name , value ) { this . propertiesCache . push ( new NameValue ( name , value ) ) ; } public writeProperties ( ) { if ( this . propertiesCache . length > 0 ) { this . propertiesCache . sort ( ( propA , propB ) => { return propA . name . localeCompare ( propB . name , undefined , { numeric : true , sensitivity : 'base' } ) ; } ) ; for ( let i = 0 ; i < this . propertiesCache . length ; i ++ ) this . writeProperty ( this . propertiesCache [ i ] . name , this . propertiesCache [ i ] . value ) ; this . propertiesCache = [ ] ; } } public writeReportColumn ( dataSetName , source , addDataItemName ) { let columnName = this . createName ( source ) ; if ( addDataItemName ) columnName = columnName + "_" + this . createName ( dataSetName ) ; this . writeNameSourceBlock ( "column" , columnName , this . encodeName ( source ) ) ; } public writeTableField ( fieldId , fieldName , fieldDataType , fieldLength , dataClassification ) { let dataType = fieldDataType . toLowerCase ( ) ; if ( ( fieldLength ) && ( ( dataType == 'text' ) || ( dataType == 'code' ) ) ) fieldDataType = fieldDataType + '[' + fieldLength + ']' ; if ( ( dataType . startsWith ( "enum " ) ) && ( dataType . length > 5 ) ) { let enumType = fieldDataType . substr ( 5 ) . trim ( ) ; if ( ! enumType . startsWith ( '"' ) ) enumType = ALSyntaxHelper . toNameText ( enumType ) ; fieldDataType = "Enum " + enumType ; } this . writeLine ( "field(" + fieldId + "; " + ALSyntaxHelper . toNameText ( fieldName ) + "; " + fieldDataType + ")" ) ; this . writeStartBlock ( ) ; this . writeProperty ( 'Caption' , ALSyntaxHelper . toStringText ( fieldName ) ) ; if ( dataClassification ) this . writeProperty ( "DataClassification" , dataClassification ) ; else this . writeProperty ( "DataClassification" , "ToBeClassified" ) ; this . writeEndBlock ( ) ; } public writePageField ( fieldName , fieldCaption , fieldCaptionComment , fieldDescription , createToolTip , existingToolTips ) { this . writeStartNameSourceBlock ( "field" , this . encodeName ( fieldName ) , 'Rec.' + this . encodeName ( fieldName ) ) ; if ( createToolTip ) this . writeTooltip ( this . fieldToolTip , this . fieldToolTipComment , fieldCaption , fieldCaptionComment , fieldDescription , existingToolTips ) ; this . writeApplicationArea ( ) ; this . writeEndBlock ( ) ; } public writeApiPageField ( fieldName , fieldCaption , fieldCaptionComment , useTableFieldCaption ) { let name = this . createApiName ( fieldName ) ; this . writeStartNameSourceBlock ( "field" , this . encodeName ( name ) , 'Rec.' + this . encodeName ( fieldName ) ) ; if ( useTableFieldCaption ) { if ( ( ! fieldCaption ) || ( fieldCaption === '' ) ) fieldCaption = fieldName ; if ( ( fieldCaptionComment ) && ( fieldCaptionComment !== '' ) ) this . addProperty ( "Caption" , this . encodeString ( fieldCaption ) + ', Comment = ' + this . encodeString ( fieldCaptionComment ) ) ; else this . addProperty ( "Caption" , this . encodeString ( fieldCaption ) ) ; } else this . addProperty ( "Caption" , this . encodeString ( name ) + ', Locked = true' ) ; this . writeProperties ( ) ; this . writeEndBlock ( ) ; } public writeApplicationArea ( ) { if ( ( this . applicationArea ) && ( this . applicationArea !== "" ) ) this . writeProperty ( "ApplicationArea" , this . applicationArea ) ; } public writeTooltip ( captionTemplate , commentTemplate , value , comment , fieldDescription , existingToolTips ) { let textValue = undefined ; if ( ( this . useTableFieldDescriptionAsToolTip ) && ( fieldDescription ) && ( fieldDescription != "" ) ) textValue = this . encodeString ( fieldDescription ) ; else if ( ( existingToolTips ) && ( existingToolTips . length > 0 ) && ( existingToolTips [ 0 ] ) && ( existingToolTips [ 0 ] != "" ) ) textValue = this . encodeString ( existingToolTips [ 0 ] ) ; else if ( ( captionTemplate ) && ( captionTemplate != "" ) && ( value ) && ( value != "" ) ) { textValue = this . applyCaptionTemplate ( captionTemplate , value , comment ) ; let commentValue = this . applyCaptionTemplate ( commentTemplate , value , comment ) ; textValue = this . encodeString ( textValue ) ; if ( ( commentValue ) && ( commentValue != "" ) ) textValue = textValue + ", Comment = " + this . encodeString ( commentValue ) ; } if ( ( textValue ) && ( textValue != "" ) ) this . writeProperty ( "ToolTip" , textValue ) ; } protected applyCaptionTemplate ( template , value , comment ) { if ( ( template ) && ( template != "" ) ) { if ( ! value ) value = "" ; if ( ! comment ) comment = "" ; template = template . replace ( new RegExp ( "%1" , "g" ) , value ) ; template = template . replace ( new RegExp ( "%Caption%" , "g" ) , value ) ; template = template . replace ( new RegExp ( "%Caption.Comment%" , "g" ) , comment ) ; } return template ; } public addApplicationAreaProperty ( ) { if ( ( this . applicationArea ) && ( this . applicationArea !== "" ) ) this . addProperty ( "ApplicationArea" , this . applicationArea ) ; } public encodeString ( text ) { return ALSyntaxHelper . toStringText ( text ) ; } public encodeName ( name ) { return ALSyntaxHelper . toNameText ( name ) ; } public createName ( source ) { return source . replace ( /\W/g , '' ) ; } public createApiName ( source ) { let text = '' ; let toLower = true ; let toUpper = false ; source = source . trim ( ) ; for ( let i = 0 ; i < source . length ; i ++ ) { let character = source [ i ] ; let isLowerCaseLetterChar = ( ( character >= 'a' ) && ( character <= 'z' ) ) ; let isUpperCaseLetterChar = ( ( character >= 'A' ) && ( character <= 'Z' ) ) ; let isDigitChar = ( ( character >= '0' ) && ( character <= '9' ) ) ; let validCharacter = ( ( isLowerCaseLetterChar ) || ( isUpperCaseLetterChar ) || ( ( isDigitChar ) && ( text !== '' ) ) ) ; if ( ( text !== '' ) || ( validCharacter ) ) { if ( isUpperCaseLetterChar ) { toUpper = false ; if ( ( text !== '' ) && ( toLower ) && ( i < ( source . length - 1 ) ) ) { let nextCharacter = source [ i + 1 ] ; if ( ( ( nextCharacter >= 'a' ) && ( nextCharacter <= 'z' ) ) ) toLower = false ; } if ( toLower ) character = character . toLowerCase ( ) ; } else { toLower = false ; if ( ( isLowerCaseLetterChar ) && ( toUpper ) ) { character = character . toUpperCase ( ) ; toUpper = false ; } if ( ! isLowerCaseLetterChar ) toUpper = true ; } if ( validCharacter ) text = text + character ; } } return text ; } }