@ind-rcg/plugins-printengine 246.1010.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +37 -0
- package/README.md +7 -0
- package/dist/dev/fonts/LICENSE.txt +202 -0
- package/dist/dev/fonts/Roboto-Italic.ttf +0 -0
- package/dist/dev/fonts/Roboto-Medium.ttf +0 -0
- package/dist/dev/fonts/Roboto-MediumItalic.ttf +0 -0
- package/dist/dev/fonts/Roboto-Regular.ttf +0 -0
- package/dist/dev/printEngine.js +589 -0
- package/dist/dev/src/contractToIntermediateJSONClass.js +1659 -0
- package/dist/dev/src/formatClass.js +156 -0
- package/dist/dev/src/index.js +110 -0
- package/dist/dev/src/localizationClass.js +89 -0
- package/dist/dev/src/logClass.js +38 -0
- package/dist/dev/src/macroHandlerClass.js +132 -0
- package/dist/dev/src/pdfConverterClass.js +1123 -0
- package/dist/dev/src/printEngineParams.js +124 -0
- package/dist/dev/src/tableCellIdentifier.js +116 -0
- package/dist/dev/src/togglesClass.js +61 -0
- package/dist/prod/printEngine.js +2 -0
- package/dist/prod/printEngine.js.LICENSE.txt +50 -0
- package/package.json +79 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
const dayjs = require('dayjs');
|
|
8
|
+
|
|
9
|
+
class Format {
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
this.INVALID_VALUE = "###";
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
formatDate(value, format){
|
|
17
|
+
if(!_.isString(value)) {
|
|
18
|
+
return this.INVALID_VALUE;
|
|
19
|
+
}
|
|
20
|
+
if(!_.isString(format)){
|
|
21
|
+
return this.INVALID_VALUE;
|
|
22
|
+
}
|
|
23
|
+
// restrict the library a bit more because it also parses fragments of a date
|
|
24
|
+
const allowedDateRegex = /^\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}:\d{2}(\.\d{3}Z)?)?$/;
|
|
25
|
+
if(! allowedDateRegex.test(value)) {
|
|
26
|
+
return this.INVALID_VALUE;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// restrict also format strings more as otherwise the library creates suprising results
|
|
30
|
+
const allowedFormatRegex = /^[:\-/.YMDdHhmsSZTAa ]+$/;
|
|
31
|
+
if(! allowedFormatRegex.test(format)) {
|
|
32
|
+
return this.INVALID_VALUE;
|
|
33
|
+
}
|
|
34
|
+
const parsedDate = dayjs(value);
|
|
35
|
+
if(parsedDate.isValid()){
|
|
36
|
+
const formatedValue = parsedDate.format(format);
|
|
37
|
+
return formatedValue;
|
|
38
|
+
|
|
39
|
+
} else {
|
|
40
|
+
return this.INVALID_VALUE;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Formats a string of raw decimal to the locale format with 1000 seperator
|
|
46
|
+
* This function is a direct copy from mobility framework and therefore the max lines rule was disabled.
|
|
47
|
+
* @param value : needs to be a number or a string representing a number and needs to match the regex description below
|
|
48
|
+
* @param format : needs to be a string and needs to match the regex description below
|
|
49
|
+
* @param decimalSeparator : optional should be overwritten by localization
|
|
50
|
+
* @param thousandSeparator : optional should be overwritten by localization
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
// eslint-disable-next-line max-lines-per-function
|
|
54
|
+
formatDecimalV2(value, format, decimalSeparator = ".", thousandSeparator = ",") {
|
|
55
|
+
let result;
|
|
56
|
+
let invalidValue = this.INVALID_VALUE;
|
|
57
|
+
|
|
58
|
+
if (!_.isNil(value)) {
|
|
59
|
+
if (_.isNil(format) || !_.isString(format) || (!_.isString(value) && isNaN(value))) {
|
|
60
|
+
return invalidValue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (_.isString(value)) {
|
|
64
|
+
let numericStringPatternRegex = /^-?\d+\.?\d*$|^\d*\.?\d+$/;
|
|
65
|
+
let numericStringPatternMatches = value.match(numericStringPatternRegex);
|
|
66
|
+
|
|
67
|
+
if (numericStringPatternMatches === null) {
|
|
68
|
+
return invalidValue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let decimalStringPatternRegex = /\d+\.\d+/;
|
|
73
|
+
let decimalStringPatternMatches = format.match(decimalStringPatternRegex);
|
|
74
|
+
|
|
75
|
+
if (decimalStringPatternMatches === null) {
|
|
76
|
+
return invalidValue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let stringNumber = value.toString();
|
|
80
|
+
let integerPart;
|
|
81
|
+
let decimalPart;
|
|
82
|
+
|
|
83
|
+
//Get integer and decimal part from input
|
|
84
|
+
if (stringNumber.indexOf(".") >= 0) {
|
|
85
|
+
integerPart = stringNumber.substring(0, stringNumber.indexOf("."));
|
|
86
|
+
decimalPart = stringNumber.substr(stringNumber.indexOf(".") + 1);
|
|
87
|
+
} else {
|
|
88
|
+
integerPart = stringNumber;
|
|
89
|
+
decimalPart = "0";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//Get integer and decimal part length from format
|
|
93
|
+
let integerLengthInFormat = parseInt(format.substr(0, format.indexOf(".")), 10);
|
|
94
|
+
let decimalLengthInFormat = parseInt(format.substr(format.indexOf(".") + 1), 10);
|
|
95
|
+
|
|
96
|
+
//Remove leading zero for integer part
|
|
97
|
+
integerPart = integerPart.replace(/^(-)?0+(?=\d)/,'$1');
|
|
98
|
+
let inputIntegerPartLength = integerPart.length;
|
|
99
|
+
if(integerPart.startsWith("-")){
|
|
100
|
+
//If its negative, then exlcude it in format length checking
|
|
101
|
+
inputIntegerPartLength = Math.max(0, inputIntegerPartLength - 1);
|
|
102
|
+
}
|
|
103
|
+
if (inputIntegerPartLength > integerLengthInFormat) {
|
|
104
|
+
result = invalidValue;
|
|
105
|
+
} else {
|
|
106
|
+
if (decimalPart.length > decimalLengthInFormat) {
|
|
107
|
+
//If decimal part length is greater than decimal length in format, round the value.
|
|
108
|
+
let roundedValue = parseFloat(integerPart + "." + decimalPart).toFixed(decimalLengthInFormat).split(".");
|
|
109
|
+
/**If after rounding the value, integer part length exceeds integerLengthInFormat
|
|
110
|
+
** example 99.999 with format 2.2 , after rounding it becomes 100.00 which violates 2.2 format
|
|
111
|
+
** Display 99.99 in this case*/
|
|
112
|
+
if(roundedValue[0].length > integerLengthInFormat)
|
|
113
|
+
{
|
|
114
|
+
decimalPart = decimalPart.substr(0,decimalLengthInFormat);
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
{
|
|
118
|
+
integerPart = roundedValue[0];
|
|
119
|
+
decimalPart = roundedValue[1];
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
decimalPart = decimalPart.padEnd(decimalLengthInFormat, "0");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let returnString = "";
|
|
126
|
+
let ts = thousandSeparator;
|
|
127
|
+
let endIndex = integerPart.length;
|
|
128
|
+
let startIndex = endIndex - 3;
|
|
129
|
+
while (startIndex >= 0) {
|
|
130
|
+
returnString = integerPart.substring(startIndex, endIndex) + ts + returnString;
|
|
131
|
+
endIndex -= 3;
|
|
132
|
+
startIndex -= 3;
|
|
133
|
+
}
|
|
134
|
+
if (endIndex > 0) {
|
|
135
|
+
returnString = integerPart.substring(0, endIndex) + ts + returnString;
|
|
136
|
+
if (returnString.indexOf("-" + ts) === 0) {
|
|
137
|
+
returnString = "-" + returnString.substr(2);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (decimalLengthInFormat > 0) {
|
|
141
|
+
// Replace decimal separator
|
|
142
|
+
result = returnString.substring(0, returnString.length - 1) + decimalSeparator + decimalPart;
|
|
143
|
+
} else {
|
|
144
|
+
result = returnString.substring(0, returnString.length - 1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else
|
|
149
|
+
{
|
|
150
|
+
result = invalidValue;
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = Format;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
const classPrintEngineParams = require("../src/printEngineParams");
|
|
7
|
+
const classLocalization = require('./localizationClass');
|
|
8
|
+
const classToggles = require('./togglesClass');
|
|
9
|
+
const classMacroHandler = require('./macroHandlerClass');
|
|
10
|
+
const PdfConverter = require('./pdfConverterClass');
|
|
11
|
+
const ContractToIntermediateJSON = require('./contractToIntermediateJSONClass');
|
|
12
|
+
const classLog = require('./logClass');
|
|
13
|
+
let __log = new classLog();
|
|
14
|
+
const contractParser= new ContractToIntermediateJSON(__log );
|
|
15
|
+
|
|
16
|
+
const stream = require('stream');
|
|
17
|
+
const _ = require('lodash');
|
|
18
|
+
|
|
19
|
+
let pdfConverter = new PdfConverter();
|
|
20
|
+
|
|
21
|
+
// This will always stay undefined, and will only be activated via Rewire for tests
|
|
22
|
+
let testReportName;
|
|
23
|
+
|
|
24
|
+
const PRINT_TYPE = {
|
|
25
|
+
"STREAM": "STREAM",
|
|
26
|
+
"DATA_URL": "DATA_URL",
|
|
27
|
+
"BLOB": "BLOB"
|
|
28
|
+
};
|
|
29
|
+
Object.freeze(PRINT_TYPE);
|
|
30
|
+
|
|
31
|
+
function __validateCommonParameters(contract, params, format){
|
|
32
|
+
if (typeof contract !== 'string') {
|
|
33
|
+
throw new TypeError("Not a valid contract object");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!(params instanceof classPrintEngineParams)){
|
|
37
|
+
throw new TypeError("Not a valid PrintEngineParams object");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ((typeof params.getBOs() !== 'object') || (_.isEmpty(params.getBOs()))) {
|
|
41
|
+
throw new TypeError("Not a valid business object dictionary");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let localization = params.getLocalization();
|
|
45
|
+
|
|
46
|
+
if ((typeof localization !== 'object') || (Object.keys(localization).length === 0)) {
|
|
47
|
+
throw new TypeError("Not a valid localization object");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if(!PdfConverter.isValidFormat(format)) {
|
|
51
|
+
throw new TypeError("Not a valid print format");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function __innerPrintLogic(printType, contract, params, _stream, format) {
|
|
56
|
+
let json = contractParser.toJson(contract, params);
|
|
57
|
+
let pdfDefinition = pdfConverter.toPdfDefinition(json, format, testReportName);
|
|
58
|
+
|
|
59
|
+
switch (printType) {
|
|
60
|
+
case PRINT_TYPE.STREAM:
|
|
61
|
+
pdfConverter.writeToStream(pdfDefinition, _stream);
|
|
62
|
+
break;
|
|
63
|
+
|
|
64
|
+
case PRINT_TYPE.BLOB:
|
|
65
|
+
return pdfConverter.toBlob(pdfDefinition);
|
|
66
|
+
|
|
67
|
+
case PRINT_TYPE.DATA_URL:
|
|
68
|
+
return pdfConverter.toDataUrl(pdfDefinition);
|
|
69
|
+
|
|
70
|
+
default:
|
|
71
|
+
__log.error('PRINT_TYPE ' + printType + ' not supported in innerPrintLogic');
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function printToStream(contract, params, _stream, format = "A4") {
|
|
77
|
+
// Validate parameters
|
|
78
|
+
if(!(_stream instanceof stream.Stream)) {
|
|
79
|
+
throw new TypeError("Not a valid stream.");
|
|
80
|
+
}
|
|
81
|
+
__validateCommonParameters(contract, params, format);
|
|
82
|
+
__innerPrintLogic(PRINT_TYPE.STREAM, contract, params, _stream, format);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function printToDataUrl(contract, params, format = "A4") {
|
|
86
|
+
// Validate parameters
|
|
87
|
+
__validateCommonParameters(contract, params, format);
|
|
88
|
+
return __innerPrintLogic(PRINT_TYPE.DATA_URL, contract, params, null, format);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function printToBlob(contract, params, format = "A4") {
|
|
92
|
+
// Validate parameters
|
|
93
|
+
__validateCommonParameters(contract, params, format);
|
|
94
|
+
return __innerPrintLogic(PRINT_TYPE.BLOB, contract, params, null, format);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
"printToStream": printToStream,
|
|
100
|
+
"printToDataUrl": printToDataUrl,
|
|
101
|
+
"printToBlob": printToBlob,
|
|
102
|
+
"PdfConverter": PdfConverter,
|
|
103
|
+
"ContractToIntermediateJSON": ContractToIntermediateJSON,
|
|
104
|
+
"Localization": classLocalization,
|
|
105
|
+
"Toggles": classToggles,
|
|
106
|
+
"PrintEngineParams": classPrintEngineParams,
|
|
107
|
+
"MacroHandler": classMacroHandler,
|
|
108
|
+
"Log": classLog,
|
|
109
|
+
"onMessage": __log.onMessage
|
|
110
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
|
|
8
|
+
class Localization {
|
|
9
|
+
constructor(localization, isSfBackend = true) {
|
|
10
|
+
if (typeof localization !== 'object') {
|
|
11
|
+
throw new TypeError("Not a valid localization object");
|
|
12
|
+
}
|
|
13
|
+
this.localization = localization;
|
|
14
|
+
this.intMinDateTimeAnsi = isSfBackend ? '1700-01-01 00:00:00' : '1800-01-01 00:00:00';
|
|
15
|
+
this.separatorDecimalDefault = ".";
|
|
16
|
+
this.separatorThousandDefault = ",";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
resolve(key, defaultValue) {
|
|
20
|
+
let result = this.localization[key];
|
|
21
|
+
if (_.isNil(result) && key && key.length > 0) {
|
|
22
|
+
// try with a global label, used for Context Menu
|
|
23
|
+
let globalLabelName = key.substring(key.lastIndexOf(".") + 1);
|
|
24
|
+
result = this.localization[globalLabelName];
|
|
25
|
+
}
|
|
26
|
+
return !_.isNil(result) ? result : (!_.isNil(defaultValue) ? defaultValue : key);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get separatorDecimal() {
|
|
30
|
+
if (!_.isNil(this.localization) && !_.isNil(this.localization.FORMATS) && !_.isNil(this.localization.FORMATS.NumberFormats)) {
|
|
31
|
+
return this.localization.FORMATS.NumberFormats.DecimalSeparator.value;
|
|
32
|
+
} else {
|
|
33
|
+
return this.separatorDecimalDefault;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get separatorThousand() {
|
|
38
|
+
if (!_.isNil(this.localization) && !_.isNil(this.localization.FORMATS) && !_.isNil(this.localization.FORMATS.NumberFormats)) {
|
|
39
|
+
return this.localization.FORMATS.NumberFormats.ThousandSeparator.value;
|
|
40
|
+
} else {
|
|
41
|
+
return this.separatorThousandDefault;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get minDateTimeAnsi() {
|
|
46
|
+
return this.intMinDateTimeAnsi;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get dateFormat() {
|
|
50
|
+
const fallback = "MM/DD/YYYY";
|
|
51
|
+
if(_.isNil(this.localization.FORMATS) || _.isNil(this.localization.FORMATS.DateFormats)
|
|
52
|
+
|| _.isNil(this.localization.FORMATS.DateFormats.Date)){
|
|
53
|
+
return fallback;
|
|
54
|
+
}
|
|
55
|
+
return this.localization.FORMATS.DateFormats.Date.value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get shortDateFormat() {
|
|
59
|
+
const fallback = "dd MM/DD";
|
|
60
|
+
if(_.isNil(this.localization.FORMATS) || _.isNil(this.localization.FORMATS.DateFormats)
|
|
61
|
+
|| _.isNil(this.localization.FORMATS.DateFormats.ShortDate)){
|
|
62
|
+
return fallback;
|
|
63
|
+
}
|
|
64
|
+
return this.localization.FORMATS.DateFormats.ShortDate.value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get dateTimeFormat() {
|
|
68
|
+
const fallback = "MM/DD/YYYY h:mm a";
|
|
69
|
+
if(_.isNil(this.localization.FORMATS) || _.isNil(this.localization.FORMATS.DateFormats)
|
|
70
|
+
|| _.isNil(this.localization.FORMATS.DateFormats.DateTime)){
|
|
71
|
+
return fallback;
|
|
72
|
+
}
|
|
73
|
+
return this.localization.FORMATS.DateFormats.DateTime.value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get timeFormat() {
|
|
77
|
+
const fallback = "h:mm a";
|
|
78
|
+
if(_.isNil(this.localization.FORMATS) || _.isNil(this.localization.FORMATS.DateFormats)
|
|
79
|
+
|| _.isNil(this.localization.FORMATS.DateFormats.Time)){
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return this.localization.FORMATS.DateFormats.Time.value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
module.exports = Localization;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
const __Logger = require('js-logger');
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
|
|
8
|
+
class Log {
|
|
9
|
+
/**********************************************************************************************************
|
|
10
|
+
* The purpose of this class is to wrap the external logger library. The goal is to make future migration
|
|
11
|
+
* to a different logger library easy.
|
|
12
|
+
**********************************************************************************************************/
|
|
13
|
+
constructor() {
|
|
14
|
+
__Logger.useDefaults();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
onMessage(handlerFunction){
|
|
19
|
+
if(!_.isFunction(handlerFunction)){
|
|
20
|
+
throw new Error("Not a valid function.");
|
|
21
|
+
}
|
|
22
|
+
const consoleHandler = __Logger.createDefaultHandler();
|
|
23
|
+
__Logger.setHandler(function __printEngineOnMessageHandler(messages, context){
|
|
24
|
+
consoleHandler(messages, context);
|
|
25
|
+
handlerFunction(messages, context);
|
|
26
|
+
} );
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
error(...args) {
|
|
30
|
+
__Logger.error.apply(this, args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
warn(...args){
|
|
34
|
+
__Logger.warn.apply(this, args);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = Log;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
const LogClass = require('./logClass');
|
|
7
|
+
const _ = require('lodash');
|
|
8
|
+
|
|
9
|
+
//MacroDefintion = "{", "{", MacroList, "}", "}" ;
|
|
10
|
+
//MacroList = KeyValuePair, { ";" KeyValuePair } ;
|
|
11
|
+
//KeyValuePair = Value | Key "=" Value ;
|
|
12
|
+
//Key = "path" | "format" | "toggleId" | "toggleField" ;
|
|
13
|
+
//Value = Path | Number | SimpleFloat;
|
|
14
|
+
//Path = ".", Identifier | Scope, Identifier, { ".", Identifier} ;
|
|
15
|
+
//Scope = Identifier, ":", ":"
|
|
16
|
+
//Identifier = Letter, { Letter | Digit } ;
|
|
17
|
+
//Number = Digit, { Digit } ;
|
|
18
|
+
//SimpleFloat = Digit, { Digit } ( ".", Digit, { Digit } ).
|
|
19
|
+
//Letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" |
|
|
20
|
+
// "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ;
|
|
21
|
+
//Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
|
|
22
|
+
|
|
23
|
+
class MacroHandler {
|
|
24
|
+
constructor(log) {
|
|
25
|
+
if(!(log instanceof LogClass)) {
|
|
26
|
+
throw new Error("Invalid constructor parameters");
|
|
27
|
+
}
|
|
28
|
+
this.__log = log;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
__parseValue(property, value, result) {
|
|
32
|
+
if (_.startsWith(value, ".")) {
|
|
33
|
+
result[property] = value.substr(1);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
let fullValueList = value.split("::");
|
|
37
|
+
if (fullValueList.length === 2) {
|
|
38
|
+
result.scope = fullValueList[0];
|
|
39
|
+
result[property] = fullValueList[1];
|
|
40
|
+
} else if (fullValueList.length === 1) {
|
|
41
|
+
result[property] = fullValueList[0];
|
|
42
|
+
} else {
|
|
43
|
+
let error = "Unexpected macro value: " + value;
|
|
44
|
+
this.__log.error(error);
|
|
45
|
+
throw new Error(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
__isWhitespaceKeptForThisProperty(key){
|
|
51
|
+
return key === "defaultLabel" || key === "dateTimeFormat";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
__parseKeyValuePair(keyValuePair, result) {
|
|
55
|
+
let keyValueList = keyValuePair.split("=");
|
|
56
|
+
let trimmedKey = _.trim(keyValueList[0]);
|
|
57
|
+
|
|
58
|
+
if(trimmedKey.length > 0) {
|
|
59
|
+
// ingore empty contents which is created by just placing ;
|
|
60
|
+
if (keyValueList.length === 1) {
|
|
61
|
+
// remove all whitespace
|
|
62
|
+
let strippedValue = keyValueList[0].replace(/\s/g,'');
|
|
63
|
+
this.__parseValue("path", strippedValue, result);
|
|
64
|
+
} else {
|
|
65
|
+
let strippedValue = keyValueList[1];
|
|
66
|
+
if(!this.__isWhitespaceKeptForThisProperty(trimmedKey)) {
|
|
67
|
+
strippedValue = keyValueList[1].replace(/\s/g,'');
|
|
68
|
+
}
|
|
69
|
+
this.__parseValue(trimmedKey, strippedValue, result);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// This is the regular expression which is used to find macros in the printV2 contract.
|
|
75
|
+
getMacroRegex() {
|
|
76
|
+
return /{\s*{[\s:.;=A-Za-z\-_0-9]*}\s*}/g;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
parseMacro( macroString ) {
|
|
81
|
+
// console.log(JSON.stringify(macroString));
|
|
82
|
+
|
|
83
|
+
if (_.isNil(macroString) || !_.isString(macroString)) {
|
|
84
|
+
throw new TypeError("Invalid macro string parameter");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let result = {};
|
|
88
|
+
|
|
89
|
+
let macroRegex = /^\s*{\s*{[\s:.;=A-Za-z\-_0-9]*}\s*}\s*$/g;
|
|
90
|
+
let macroMatches = macroString.match(macroRegex);
|
|
91
|
+
|
|
92
|
+
// console.log(macroString);
|
|
93
|
+
// console.log(JSON.stringify(macroMatches));
|
|
94
|
+
|
|
95
|
+
//Note that any invalid character between {{}} will be filtered out like "{{{}}}" will become "{{}}" which is shorter than the original.
|
|
96
|
+
if (_.isNil(macroMatches) || _.isNil(macroMatches[0]) ) {
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
macroString = macroMatches[0].replace(/[{}]/g,'');
|
|
101
|
+
|
|
102
|
+
if (macroString === "") {
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// console.log(macroString);
|
|
107
|
+
|
|
108
|
+
let macroList = macroString.split(";");
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
for (let i = 0; i < macroList.length; i++) {
|
|
112
|
+
this.__parseKeyValuePair(macroList[i], result);
|
|
113
|
+
}
|
|
114
|
+
} catch (err){
|
|
115
|
+
// some invalid value encountered during parse
|
|
116
|
+
result = {};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// avoid results where path contains ":" inside. Because this will generate a lot of complexity for calling components
|
|
120
|
+
// to handle this
|
|
121
|
+
if(!_.isNil(result.path)){
|
|
122
|
+
if(result.path.indexOf(":") > 0) {
|
|
123
|
+
result = {};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// console.log(JSON.stringify(result));
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = MacroHandler;
|