@cap-js/change-tracking 1.1.2 → 1.1.4
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/CHANGELOG.md +13 -1
- package/cds-plugin.js +229 -223
- package/lib/change-log.js +469 -506
- package/lib/entity-helper.js +187 -186
- package/lib/format-options.js +62 -62
- package/lib/localization.js +103 -95
- package/lib/template-processor.js +86 -82
- package/package.json +47 -39
package/lib/entity-helper.js
CHANGED
|
@@ -1,216 +1,217 @@
|
|
|
1
|
-
const cds = require(
|
|
2
|
-
const LOG = cds.log(
|
|
3
|
-
|
|
1
|
+
const cds = require('@sap/cds');
|
|
2
|
+
const LOG = cds.log('change-log');
|
|
4
3
|
|
|
5
4
|
const getNameFromPathVal = function (pathVal) {
|
|
6
|
-
|
|
7
|
-
}
|
|
5
|
+
return /^(.+?)\(/.exec(pathVal)?.[1] || '';
|
|
6
|
+
};
|
|
8
7
|
|
|
9
8
|
const getUUIDFromPathVal = function (pathVal) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
9
|
+
const regRes = /\((.+?)\)/.exec(pathVal);
|
|
10
|
+
return regRes ? regRes[1] : '';
|
|
11
|
+
};
|
|
13
12
|
|
|
14
13
|
const getEntityByContextPath = function (aPath, hasComp = false) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
14
|
+
if (hasComp) return cds.model.definitions[aPath[aPath.length - 1]];
|
|
15
|
+
let entity = cds.model.definitions[aPath[0]];
|
|
16
|
+
for (let each of aPath.slice(1)) {
|
|
17
|
+
entity = entity.elements[each]?._target;
|
|
18
|
+
}
|
|
19
|
+
return entity;
|
|
20
|
+
};
|
|
22
21
|
|
|
23
22
|
const getObjIdElementNamesInArray = function (elements) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
if (Array.isArray(elements))
|
|
24
|
+
return elements.map((e) => {
|
|
25
|
+
const splitted = (e['='] || e).split('.');
|
|
26
|
+
splitted.shift();
|
|
27
|
+
return splitted.join('.');
|
|
28
|
+
});
|
|
29
|
+
else return [];
|
|
30
|
+
};
|
|
31
31
|
|
|
32
32
|
const getCurObjFromDbQuery = async function (entityName, whereXpr) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
33
|
+
if (!Object.keys(whereXpr)) return {};
|
|
34
|
+
// REVISIT: This always reads all elements -> should read required ones only!
|
|
35
|
+
const obj = await SELECT.one.from(entityName).where(whereXpr);
|
|
36
|
+
return obj || {};
|
|
37
|
+
};
|
|
38
38
|
|
|
39
39
|
const getCurObjFromReqData = function (reqData, nodePathVal, pathVal) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
40
|
+
const pathVals = splitPath(pathVal);
|
|
41
|
+
const rootNodePathVal = pathVals[0];
|
|
42
|
+
let curReqObj = reqData || {};
|
|
43
|
+
|
|
44
|
+
if (nodePathVal === rootNodePathVal) return curReqObj;
|
|
45
|
+
else pathVals.shift();
|
|
46
|
+
|
|
47
|
+
let parentSrvObjName = getNameFromPathVal(rootNodePathVal);
|
|
48
|
+
|
|
49
|
+
for (const subNodePathVal of pathVals) {
|
|
50
|
+
const srvObjName = getNameFromPathVal(subNodePathVal);
|
|
51
|
+
const curSrvObjUUID = getUUIDFromPathVal(subNodePathVal);
|
|
52
|
+
const associationName = _getAssociationName(parentSrvObjName, srvObjName);
|
|
53
|
+
if (curReqObj) {
|
|
54
|
+
let associationData = curReqObj[associationName];
|
|
55
|
+
if (!Array.isArray(associationData)) associationData = [associationData];
|
|
56
|
+
curReqObj = associationData?.find((x) => x?.ID === curSrvObjUUID) || {};
|
|
57
|
+
}
|
|
58
|
+
if (subNodePathVal === nodePathVal) return curReqObj || {};
|
|
59
|
+
parentSrvObjName = srvObjName;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return curReqObj;
|
|
63
|
+
|
|
64
|
+
function _getAssociationName(entity, target) {
|
|
65
|
+
const source = cds.model.definitions[entity];
|
|
66
|
+
const assocs = source.associations;
|
|
67
|
+
for (const each in assocs) {
|
|
68
|
+
if (assocs[each].target === target) return each;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
73
72
|
|
|
74
|
-
async function getObjectId
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
73
|
+
async function getObjectId(reqData, entityName, fields, curObj) {
|
|
74
|
+
let all = [],
|
|
75
|
+
{ curObjFromReqData: req_data = {}, curObjFromDbQuery: db_data = {} } = curObj;
|
|
76
|
+
let entity = cds.model.definitions[entityName];
|
|
77
|
+
if (!fields?.length) fields = entity['@changelog']?.map?.((k) => k['='] || k) || [];
|
|
78
|
+
for (let field of fields) {
|
|
79
|
+
let path = field.split('.');
|
|
80
|
+
if (path.length > 1) {
|
|
81
|
+
let current = entity,
|
|
82
|
+
_db_data = db_data;
|
|
83
|
+
while (path.length > 1) {
|
|
84
|
+
let assoc = current.elements[path[0]];
|
|
85
|
+
if (!assoc?.isAssociation) break;
|
|
86
|
+
let foreignKey = assoc.keys?.[0]?.$generatedFieldName;
|
|
87
|
+
let IDval = req_data[foreignKey] && current.name === entityName ? req_data[foreignKey] : _db_data[foreignKey];
|
|
88
|
+
if (!IDval) {
|
|
89
|
+
_db_data = {};
|
|
90
|
+
} else
|
|
91
|
+
try {
|
|
92
|
+
// REVISIT: This always reads all elements -> should read required ones only!
|
|
93
|
+
let ID = assoc.keys?.[0]?.ref[0] || 'ID';
|
|
94
|
+
const isComposition = hasComposition(assoc._target, current);
|
|
95
|
+
// Peer association and composition are distinguished by the value of isComposition.
|
|
96
|
+
if (isComposition) {
|
|
97
|
+
// This function can recursively retrieve the desired information from reqData without having to read it from db.
|
|
98
|
+
_db_data = _getCompositionObjFromReq(reqData, IDval);
|
|
99
|
+
// When multiple layers of child nodes are deleted at the same time, the deep layer of child nodes will lose the information of the upper nodes, so data needs to be extracted from the db.
|
|
100
|
+
const entityKeys = reqData ? Object.keys(reqData).filter((item) => !Object.keys(assoc._target.keys).some((ele) => item === ele)) : [];
|
|
101
|
+
if (!_db_data || JSON.stringify(_db_data) === '{}' || entityKeys.length === 0) {
|
|
102
|
+
_db_data = IDval ? await getCurObjFromDbQuery(assoc._target, { [ID]: IDval }) : {};
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
_db_data = IDval ? await getCurObjFromDbQuery(assoc._target, { [ID]: IDval }) : {};
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
LOG.error('Failed to generate object Id for an association entity.', e);
|
|
109
|
+
throw new Error('Failed to generate object Id for an association entity.', e);
|
|
110
|
+
}
|
|
111
|
+
current = assoc._target;
|
|
112
|
+
path.shift();
|
|
113
|
+
}
|
|
114
|
+
field = path.join('_');
|
|
115
|
+
let obj = current.name === entityName && req_data[field] ? req_data[field] : _db_data[field];
|
|
116
|
+
if (obj) all.push(obj);
|
|
117
|
+
} else {
|
|
118
|
+
let e = entity.elements[field];
|
|
119
|
+
if (e?.isAssociation) field = e.keys?.[0]?.$generatedFieldName;
|
|
120
|
+
let obj = req_data[field] || db_data[field];
|
|
121
|
+
if (obj) all.push(obj);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return all.join(', ');
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
127
|
const getDBEntity = (entity) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
128
|
+
if (typeof entity === 'string') entity = cds.model.definitions[entity];
|
|
129
|
+
let proto = Reflect.getPrototypeOf(entity);
|
|
130
|
+
if (proto instanceof cds.entity) return proto;
|
|
131
|
+
};
|
|
134
132
|
|
|
135
133
|
const getValueEntityType = function (entityName, fields) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
134
|
+
const types = [],
|
|
135
|
+
entity = cds.model.definitions[entityName];
|
|
136
|
+
for (let field of fields) {
|
|
137
|
+
let current = entity,
|
|
138
|
+
path = field.split('.');
|
|
139
|
+
if (path.length > 1) {
|
|
140
|
+
for (;;) {
|
|
141
|
+
let target = current.elements[path[0]]?._target;
|
|
142
|
+
if (target) current = target;
|
|
143
|
+
else break;
|
|
144
|
+
path.shift();
|
|
145
|
+
}
|
|
146
|
+
field = path.join('_');
|
|
147
|
+
}
|
|
148
|
+
let e = current.elements[field];
|
|
149
|
+
if (e) types.push(e.type);
|
|
150
|
+
}
|
|
151
|
+
return types.join(', ');
|
|
152
|
+
};
|
|
152
153
|
|
|
153
154
|
const hasComposition = function (parentEntity, subEntity) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
if (!parentEntity.compositions) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
const compositions = Object.values(parentEntity.compositions);
|
|
159
160
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
for (const composition of compositions) {
|
|
162
|
+
if (composition.target === subEntity.name) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
}
|
|
167
|
+
return false;
|
|
168
|
+
};
|
|
168
169
|
|
|
169
170
|
const _getCompositionObjFromReq = function (obj, targetID) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
171
|
+
if (obj?.ID === targetID) {
|
|
172
|
+
return obj;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (const key in obj) {
|
|
176
|
+
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
177
|
+
const result = _getCompositionObjFromReq(obj[key], targetID);
|
|
178
|
+
if (result) {
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return null;
|
|
184
185
|
};
|
|
185
186
|
|
|
186
|
-
function splitPath
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
187
|
+
function splitPath(path) {
|
|
188
|
+
let result = [];
|
|
189
|
+
let buf = '';
|
|
190
|
+
let paren = 0;
|
|
191
|
+
for (let i = 0; i < path.length; i++) {
|
|
192
|
+
const c = path[i];
|
|
193
|
+
if (c === '(') paren++;
|
|
194
|
+
if (c === ')') paren--;
|
|
195
|
+
if (c === '/' && paren === 0) {
|
|
196
|
+
result.push(buf);
|
|
197
|
+
buf = '';
|
|
198
|
+
} else {
|
|
199
|
+
buf += c;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (buf) result.push(buf);
|
|
203
|
+
return result;
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
module.exports = {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
207
|
+
getCurObjFromReqData,
|
|
208
|
+
getCurObjFromDbQuery,
|
|
209
|
+
getObjectId,
|
|
210
|
+
getNameFromPathVal,
|
|
211
|
+
getUUIDFromPathVal,
|
|
212
|
+
getDBEntity,
|
|
213
|
+
getEntityByContextPath,
|
|
214
|
+
getObjIdElementNamesInArray,
|
|
215
|
+
getValueEntityType,
|
|
216
|
+
splitPath
|
|
217
|
+
};
|
package/lib/format-options.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
1
|
const formatOptions = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
2
|
+
'cds.Date': {
|
|
3
|
+
de: { day: '2-digit', month: '2-digit', year: 'numeric' },
|
|
4
|
+
en: { day: 'numeric', month: 'short', year: 'numeric' },
|
|
5
|
+
es: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
6
|
+
fi: { year: 'numeric', month: '2-digit', day: '2-digit' },
|
|
7
|
+
fr: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
8
|
+
it: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
9
|
+
ja: { year: 'numeric', month: '2-digit', day: '2-digit' },
|
|
10
|
+
pl: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
11
|
+
pt: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
12
|
+
ru: { day: '2-digit', month: 'short', year: 'numeric' },
|
|
13
|
+
'zh-CN': { year: 'numeric', month: 'long', day: 'numeric' }
|
|
14
|
+
},
|
|
15
|
+
'cds.DateTime': {
|
|
16
|
+
de: { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
17
|
+
el: { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
18
|
+
en: { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
19
|
+
es: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
20
|
+
es_MX: { day: '2-digit', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true },
|
|
21
|
+
fi: { year: 'numeric', month: '2-digit', day: '2-digit', hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
22
|
+
fr: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
23
|
+
it: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
24
|
+
ja: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
25
|
+
pl: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
26
|
+
pt: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
27
|
+
ru: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
28
|
+
'zh-CN': { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }
|
|
29
|
+
},
|
|
30
|
+
'cds.Timestamp': {
|
|
31
|
+
cs: { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
32
|
+
de: { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
33
|
+
el: { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
34
|
+
en: { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
35
|
+
es: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
36
|
+
es_MX: { day: '2-digit', month: 'short', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true },
|
|
37
|
+
fi: { year: 'numeric', month: '2-digit', day: '2-digit', hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
38
|
+
fr: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
39
|
+
it: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
40
|
+
ja: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
41
|
+
pl: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
42
|
+
pt: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
43
|
+
ru: { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
44
|
+
'zh-CN': { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }
|
|
45
|
+
},
|
|
46
|
+
'cds.Time': {
|
|
47
|
+
cs: { hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
48
|
+
fi: { hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
49
|
+
de: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
50
|
+
el: { hour: 'numeric', minute: '2-digit', second: '2-digit' },
|
|
51
|
+
en: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
52
|
+
es: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
53
|
+
es_MX: { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true },
|
|
54
|
+
fr: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
55
|
+
it: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
56
|
+
ja: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
57
|
+
pl: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
58
|
+
pt: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
59
|
+
ru: { hour: '2-digit', minute: '2-digit', second: '2-digit' },
|
|
60
|
+
'zh-CN': { hour: '2-digit', minute: '2-digit', second: '2-digit' }
|
|
61
|
+
}
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
module.exports = {
|
|
65
|
-
|
|
66
|
-
};
|
|
65
|
+
formatOptions
|
|
66
|
+
};
|