@jsreport/jsreport-core 3.1.1 → 3.3.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 +166 -166
- package/README.md +298 -298
- package/index.js +29 -29
- package/lib/main/blobStorage/blobStorage.js +52 -52
- package/lib/main/blobStorage/inMemoryProvider.js +27 -27
- package/lib/main/blobStorage/mainActions.js +24 -24
- package/lib/main/createDefaultLoggerFormat.js +17 -17
- package/lib/main/defaults.js +14 -14
- package/lib/main/extensions/discover.js +20 -20
- package/lib/main/extensions/extensionsManager.js +264 -264
- package/lib/main/extensions/fileUtils.js +56 -56
- package/lib/main/extensions/findVersion.js +49 -49
- package/lib/main/extensions/locationCache.js +103 -103
- package/lib/main/extensions/sorter.js +10 -10
- package/lib/main/extensions/validateMinimalVersion.js +50 -50
- package/lib/main/folders/cascadeFolderRemove.js +25 -25
- package/lib/main/folders/getEntitiesInFolder.js +53 -53
- package/lib/main/folders/index.js +42 -42
- package/lib/main/folders/moveBetweenFolders.js +354 -354
- package/lib/main/folders/validateDuplicatedName.js +107 -107
- package/lib/main/folders/validateReservedName.js +53 -53
- package/lib/main/logger.js +254 -244
- package/lib/main/migration/resourcesToAssets.js +230 -230
- package/lib/main/migration/xlsxTemplatesToAssets.js +128 -128
- package/lib/main/monitoring.js +92 -91
- package/lib/main/optionsLoad.js +237 -237
- package/lib/main/optionsSchema.js +237 -237
- package/lib/main/profiler.js +13 -1
- package/lib/main/reporter.js +593 -579
- package/lib/main/schemaValidator.js +252 -252
- package/lib/main/settings.js +154 -154
- package/lib/main/store/checkDuplicatedId.js +27 -27
- package/lib/main/store/collection.js +329 -329
- package/lib/main/store/documentStore.js +469 -469
- package/lib/main/store/mainActions.js +28 -28
- package/lib/main/store/memoryStoreProvider.js +99 -99
- package/lib/main/store/queue.js +48 -48
- package/lib/main/store/referenceUtils.js +251 -251
- package/lib/main/store/setupValidateId.js +43 -43
- package/lib/main/store/setupValidateShortid.js +71 -71
- package/lib/main/store/transaction.js +69 -69
- package/lib/main/store/typeUtils.js +180 -180
- package/lib/main/templates.js +34 -34
- package/lib/main/validateEntityName.js +62 -62
- package/lib/shared/createError.js +36 -36
- package/lib/shared/encryption.js +114 -114
- package/lib/shared/folders/index.js +11 -11
- package/lib/shared/folders/normalizeEntityPath.js +15 -15
- package/lib/shared/folders/resolveEntityFromPath.js +88 -88
- package/lib/shared/folders/resolveEntityPath.js +46 -46
- package/lib/shared/folders/resolveFolderFromPath.js +38 -38
- package/lib/shared/generateRequestId.js +4 -4
- package/lib/shared/listenerCollection.js +169 -169
- package/lib/shared/normalizeMetaFromLogs.js +30 -30
- package/lib/shared/reporter.js +128 -123
- package/lib/shared/request.js +64 -64
- package/lib/shared/tempFilesHandler.js +81 -81
- package/lib/shared/templates.js +82 -82
- package/lib/static/helpers.js +33 -33
- package/lib/worker/blobStorage.js +34 -34
- package/lib/worker/defaultProxyExtend.js +46 -46
- package/lib/worker/documentStore.js +49 -49
- package/lib/worker/extensionsManager.js +17 -17
- package/lib/worker/logger.js +48 -48
- package/lib/worker/render/diff.js +138 -138
- package/lib/worker/render/executeEngine.js +232 -207
- package/lib/worker/render/htmlRecipe.js +10 -10
- package/lib/worker/render/moduleHelper.js +45 -43
- package/lib/worker/render/noneEngine.js +12 -12
- package/lib/worker/render/profiler.js +162 -158
- package/lib/worker/render/render.js +202 -201
- package/lib/worker/render/resolveReferences.js +60 -60
- package/lib/worker/reporter.js +197 -191
- package/lib/worker/sandbox/runInSandbox.js +65 -13
- package/lib/worker/sandbox/safeSandbox.js +829 -828
- package/lib/worker/templates.js +80 -78
- package/lib/worker/workerHandler.js +54 -54
- package/package.json +91 -92
- package/test/blobStorage/common.js +21 -21
- package/test/store/common.js +1449 -1449
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
module.exports = (reporter) => (proxy, req) => {
|
|
3
|
-
proxy.req = req
|
|
4
|
-
|
|
5
|
-
proxy.render = async (renderRequest) => {
|
|
6
|
-
const res = await reporter.render({
|
|
7
|
-
...renderRequest,
|
|
8
|
-
// new fresh context (user data and cycle control counter is inherit from originalReq during rendering).
|
|
9
|
-
// this avoids that user can fake user identity by sending context
|
|
10
|
-
// with information of another user and allows the original request to collect logs
|
|
11
|
-
// from the render of proxy
|
|
12
|
-
context: {}
|
|
13
|
-
}, req)
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
content: res.content,
|
|
17
|
-
meta: res.meta
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
proxy.documentStore = {
|
|
22
|
-
collection: (name) => ({
|
|
23
|
-
find: async (q) => {
|
|
24
|
-
req.context.userFindCall = true
|
|
25
|
-
const res = await reporter.documentStore.collection(name).find(q, req)
|
|
26
|
-
return res
|
|
27
|
-
},
|
|
28
|
-
findOne: async (q) => {
|
|
29
|
-
req.context.userFindCall = true
|
|
30
|
-
|
|
31
|
-
const res = await reporter.documentStore.collection(name).findOne(q, req)
|
|
32
|
-
|
|
33
|
-
return res
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
proxy.folders = {
|
|
39
|
-
resolveEntityFromPath: (path, es, options) => {
|
|
40
|
-
return reporter.folders.resolveEntityFromPath(path, es, options || {}, req)
|
|
41
|
-
},
|
|
42
|
-
resolveEntityPath: (entity, es) => {
|
|
43
|
-
return reporter.folders.resolveEntityPath(entity, es, req)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
|
|
2
|
+
module.exports = (reporter) => (proxy, req) => {
|
|
3
|
+
proxy.req = req
|
|
4
|
+
|
|
5
|
+
proxy.render = async (renderRequest) => {
|
|
6
|
+
const res = await reporter.render({
|
|
7
|
+
...renderRequest,
|
|
8
|
+
// new fresh context (user data and cycle control counter is inherit from originalReq during rendering).
|
|
9
|
+
// this avoids that user can fake user identity by sending context
|
|
10
|
+
// with information of another user and allows the original request to collect logs
|
|
11
|
+
// from the render of proxy
|
|
12
|
+
context: {}
|
|
13
|
+
}, req)
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
content: res.content,
|
|
17
|
+
meta: res.meta
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
proxy.documentStore = {
|
|
22
|
+
collection: (name) => ({
|
|
23
|
+
find: async (q) => {
|
|
24
|
+
req.context.userFindCall = true
|
|
25
|
+
const res = await reporter.documentStore.collection(name).find(q, req)
|
|
26
|
+
return res
|
|
27
|
+
},
|
|
28
|
+
findOne: async (q) => {
|
|
29
|
+
req.context.userFindCall = true
|
|
30
|
+
|
|
31
|
+
const res = await reporter.documentStore.collection(name).findOne(q, req)
|
|
32
|
+
|
|
33
|
+
return res
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
proxy.folders = {
|
|
39
|
+
resolveEntityFromPath: (path, es, options) => {
|
|
40
|
+
return reporter.folders.resolveEntityFromPath(path, es, options || {}, req)
|
|
41
|
+
},
|
|
42
|
+
resolveEntityPath: (entity, es) => {
|
|
43
|
+
return reporter.folders.resolveEntityPath(entity, es, req)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
module.exports = ({ model, collections }, executeMainAction) => {
|
|
2
|
-
const store = {
|
|
3
|
-
model,
|
|
4
|
-
collection: (name) => ({
|
|
5
|
-
find: (q, req) => executeMainAction('documentStore.collection.find', {
|
|
6
|
-
query: q,
|
|
7
|
-
collection: name
|
|
8
|
-
}, req),
|
|
9
|
-
findOne: (q, req) => executeMainAction('documentStore.collection.findOne', {
|
|
10
|
-
query: q,
|
|
11
|
-
collection: name
|
|
12
|
-
}, req),
|
|
13
|
-
insert: async (doc, req) => {
|
|
14
|
-
const entity = await executeMainAction('documentStore.collection.insert', {
|
|
15
|
-
doc,
|
|
16
|
-
collection: name
|
|
17
|
-
}, req)
|
|
18
|
-
doc._id = entity._id
|
|
19
|
-
return entity
|
|
20
|
-
},
|
|
21
|
-
update: async (query, update, options, req) => {
|
|
22
|
-
if (req == null) {
|
|
23
|
-
req = options
|
|
24
|
-
options = {}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const r = await executeMainAction('documentStore.collection.update', {
|
|
28
|
-
query,
|
|
29
|
-
update,
|
|
30
|
-
options,
|
|
31
|
-
collection: name
|
|
32
|
-
}, req)
|
|
33
|
-
|
|
34
|
-
return r
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
store.collections = {}
|
|
40
|
-
|
|
41
|
-
for (const colName of collections) {
|
|
42
|
-
store.collections[colName] = {
|
|
43
|
-
name: colName,
|
|
44
|
-
...store.collection(colName)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return store
|
|
49
|
-
}
|
|
1
|
+
module.exports = ({ model, collections }, executeMainAction) => {
|
|
2
|
+
const store = {
|
|
3
|
+
model,
|
|
4
|
+
collection: (name) => ({
|
|
5
|
+
find: (q, req) => executeMainAction('documentStore.collection.find', {
|
|
6
|
+
query: q,
|
|
7
|
+
collection: name
|
|
8
|
+
}, req),
|
|
9
|
+
findOne: (q, req) => executeMainAction('documentStore.collection.findOne', {
|
|
10
|
+
query: q,
|
|
11
|
+
collection: name
|
|
12
|
+
}, req),
|
|
13
|
+
insert: async (doc, req) => {
|
|
14
|
+
const entity = await executeMainAction('documentStore.collection.insert', {
|
|
15
|
+
doc,
|
|
16
|
+
collection: name
|
|
17
|
+
}, req)
|
|
18
|
+
doc._id = entity._id
|
|
19
|
+
return entity
|
|
20
|
+
},
|
|
21
|
+
update: async (query, update, options, req) => {
|
|
22
|
+
if (req == null) {
|
|
23
|
+
req = options
|
|
24
|
+
options = {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const r = await executeMainAction('documentStore.collection.update', {
|
|
28
|
+
query,
|
|
29
|
+
update,
|
|
30
|
+
options,
|
|
31
|
+
collection: name
|
|
32
|
+
}, req)
|
|
33
|
+
|
|
34
|
+
return r
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
store.collections = {}
|
|
40
|
+
|
|
41
|
+
for (const colName of collections) {
|
|
42
|
+
store.collections[colName] = {
|
|
43
|
+
name: colName,
|
|
44
|
+
...store.collection(colName)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return store
|
|
49
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
|
-
module.exports = (reporter, extensionsDefs) => {
|
|
4
|
-
return {
|
|
5
|
-
recipes: [],
|
|
6
|
-
engines: [],
|
|
7
|
-
extensions: extensionsDefs,
|
|
8
|
-
|
|
9
|
-
async init () {
|
|
10
|
-
for (const extension of this.extensions) {
|
|
11
|
-
if (extension.options.enabled !== false) {
|
|
12
|
-
await require(path.join(extension.directory, extension.worker))(reporter, extension)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
module.exports = (reporter, extensionsDefs) => {
|
|
4
|
+
return {
|
|
5
|
+
recipes: [],
|
|
6
|
+
engines: [],
|
|
7
|
+
extensions: extensionsDefs,
|
|
8
|
+
|
|
9
|
+
async init () {
|
|
10
|
+
for (const extension of this.extensions) {
|
|
11
|
+
if (extension.options.enabled !== false) {
|
|
12
|
+
await require(path.join(extension.directory, extension.worker))(reporter, extension)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/lib/worker/logger.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
const util = require('util')
|
|
2
|
-
const normalizeMetaFromLogs = require('../shared/normalizeMetaFromLogs')
|
|
3
|
-
|
|
4
|
-
module.exports = function createLogger (profiler) {
|
|
5
|
-
return {
|
|
6
|
-
debug: (...args) => logFn('debug', profiler, ...args),
|
|
7
|
-
info: (...args) => logFn('info', profiler, ...args),
|
|
8
|
-
warn: (...args) => logFn('warn', profiler, ...args),
|
|
9
|
-
error: (...args) => logFn('error', profiler, ...args)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function logFn (level, profiler, ...args) {
|
|
14
|
-
const lastArg = args.slice(-1)[0]
|
|
15
|
-
let req
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
lastArg != null &&
|
|
19
|
-
typeof lastArg === 'object' &&
|
|
20
|
-
lastArg.context != null &&
|
|
21
|
-
lastArg.context.rootId != null
|
|
22
|
-
) {
|
|
23
|
-
req = lastArg
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (req == null) {
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const msgArgs = args.slice(0, -1)
|
|
31
|
-
|
|
32
|
-
const log = {
|
|
33
|
-
timestamp: new Date().getTime(),
|
|
34
|
-
level: level,
|
|
35
|
-
message: util.format.apply(util, msgArgs)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const meta = normalizeMetaFromLogs(level, log.message, lastArg)
|
|
39
|
-
|
|
40
|
-
if (meta != null) {
|
|
41
|
-
log.meta = meta
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return profiler.emit({
|
|
45
|
-
type: 'log',
|
|
46
|
-
...log
|
|
47
|
-
}, req)
|
|
48
|
-
}
|
|
1
|
+
const util = require('util')
|
|
2
|
+
const normalizeMetaFromLogs = require('../shared/normalizeMetaFromLogs')
|
|
3
|
+
|
|
4
|
+
module.exports = function createLogger (profiler) {
|
|
5
|
+
return {
|
|
6
|
+
debug: (...args) => logFn('debug', profiler, ...args),
|
|
7
|
+
info: (...args) => logFn('info', profiler, ...args),
|
|
8
|
+
warn: (...args) => logFn('warn', profiler, ...args),
|
|
9
|
+
error: (...args) => logFn('error', profiler, ...args)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function logFn (level, profiler, ...args) {
|
|
14
|
+
const lastArg = args.slice(-1)[0]
|
|
15
|
+
let req
|
|
16
|
+
|
|
17
|
+
if (
|
|
18
|
+
lastArg != null &&
|
|
19
|
+
typeof lastArg === 'object' &&
|
|
20
|
+
lastArg.context != null &&
|
|
21
|
+
lastArg.context.rootId != null
|
|
22
|
+
) {
|
|
23
|
+
req = lastArg
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (req == null) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const msgArgs = args.slice(0, -1)
|
|
31
|
+
|
|
32
|
+
const log = {
|
|
33
|
+
timestamp: new Date().getTime(),
|
|
34
|
+
level: level,
|
|
35
|
+
message: util.format.apply(util, msgArgs)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const meta = normalizeMetaFromLogs(level, log.message, lastArg)
|
|
39
|
+
|
|
40
|
+
if (meta != null) {
|
|
41
|
+
log.meta = meta
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return profiler.emit({
|
|
45
|
+
type: 'log',
|
|
46
|
+
...log
|
|
47
|
+
}, req)
|
|
48
|
+
}
|
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
const jsdiff = require('diff')
|
|
2
|
-
const gdiff = new (require('diff-match-patch'))()
|
|
3
|
-
|
|
4
|
-
function formatPatch (diff) {
|
|
5
|
-
const ret = []
|
|
6
|
-
if (diff.oldFileName === diff.newFileName) {
|
|
7
|
-
ret.push('Index: ' + diff.oldFileName)
|
|
8
|
-
}
|
|
9
|
-
ret.push('===================================================================')
|
|
10
|
-
ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader))
|
|
11
|
-
ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader))
|
|
12
|
-
|
|
13
|
-
for (let i = 0; i < diff.hunks.length; i++) {
|
|
14
|
-
const hunk = diff.hunks[i]
|
|
15
|
-
ret.push(
|
|
16
|
-
'@@ -' + hunk.oldStart + ',' + hunk.oldLines +
|
|
17
|
-
' +' + hunk.newStart + ',' + hunk.newLines +
|
|
18
|
-
' @@'
|
|
19
|
-
)
|
|
20
|
-
ret.push.apply(ret, hunk.lines)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const res = ret.join('\n') + '\n'
|
|
24
|
-
return res
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function createPatch (name, older, newer, context) {
|
|
28
|
-
const { chars1, chars2, lineArray } = gdiff.diff_linesToChars_(older, newer)
|
|
29
|
-
const cdiff = gdiff.diff_main(chars1, chars2, false)
|
|
30
|
-
gdiff.diff_charsToLines_(cdiff, lineArray)
|
|
31
|
-
|
|
32
|
-
const diff = cdiff.map(([op, data]) => {
|
|
33
|
-
const r = { value: data }
|
|
34
|
-
if (op === 1) {
|
|
35
|
-
r.added = true
|
|
36
|
-
}
|
|
37
|
-
if (op === -1) {
|
|
38
|
-
r.removed = true
|
|
39
|
-
}
|
|
40
|
-
return r
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
diff.push({ value: '', lines: [] }) // Append an empty value to make cleanup easier
|
|
44
|
-
|
|
45
|
-
function contextLines (lines) {
|
|
46
|
-
return lines.map(function (entry) { return ' ' + entry })
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const hunks = []
|
|
50
|
-
let oldRangeStart = 0
|
|
51
|
-
let newRangeStart = 0
|
|
52
|
-
let curRange = []
|
|
53
|
-
|
|
54
|
-
let oldLine = 1; let newLine = 1
|
|
55
|
-
for (let i = 0; i < diff.length; i++) {
|
|
56
|
-
const current = diff[i]
|
|
57
|
-
|
|
58
|
-
const lines = current.lines || current.value.replace(/\n$/, '').split('\n')
|
|
59
|
-
current.lines = lines
|
|
60
|
-
|
|
61
|
-
if (current.added || current.removed) {
|
|
62
|
-
// If we have previous context, start with that
|
|
63
|
-
if (!oldRangeStart) {
|
|
64
|
-
const prev = diff[i - 1]
|
|
65
|
-
oldRangeStart = oldLine
|
|
66
|
-
newRangeStart = newLine
|
|
67
|
-
|
|
68
|
-
if (prev) {
|
|
69
|
-
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : []
|
|
70
|
-
oldRangeStart -= curRange.length
|
|
71
|
-
newRangeStart -= curRange.length
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Output our changes
|
|
76
|
-
curRange.push(...lines.map(function (entry) {
|
|
77
|
-
return (current.added ? '+' : '-') + entry
|
|
78
|
-
}))
|
|
79
|
-
|
|
80
|
-
// Track the updated file position
|
|
81
|
-
if (current.added) {
|
|
82
|
-
newLine += lines.length
|
|
83
|
-
} else {
|
|
84
|
-
oldLine += lines.length
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
// Identical context lines. Track line changes
|
|
88
|
-
if (oldRangeStart) {
|
|
89
|
-
// Close out any changes that have been output (or join overlapping)
|
|
90
|
-
if (lines.length <= context * 2 && i < diff.length - 2) {
|
|
91
|
-
// Overlapping
|
|
92
|
-
curRange.push(...contextLines(lines))
|
|
93
|
-
} else {
|
|
94
|
-
// end the range and output
|
|
95
|
-
const contextSize = Math.min(lines.length, context)
|
|
96
|
-
curRange.push(...contextLines(lines.slice(0, contextSize)))
|
|
97
|
-
|
|
98
|
-
const hunk = {
|
|
99
|
-
oldStart: oldRangeStart,
|
|
100
|
-
oldLines: (oldLine - oldRangeStart + contextSize),
|
|
101
|
-
newStart: newRangeStart,
|
|
102
|
-
newLines: (newLine - newRangeStart + contextSize),
|
|
103
|
-
lines: curRange
|
|
104
|
-
}
|
|
105
|
-
if (i >= diff.length - 2 && lines.length <= context) {
|
|
106
|
-
// EOF is inside this hunk
|
|
107
|
-
const oldEOFNewline = (/\n$/.test(older))
|
|
108
|
-
const newEOFNewline = (/\n$/.test(newer))
|
|
109
|
-
const noNlBeforeAdds = lines.length === 0 && curRange.length > hunk.oldLines
|
|
110
|
-
if (!oldEOFNewline && noNlBeforeAdds) {
|
|
111
|
-
// special case: old has no eol and no trailing context; no-nl can end up before adds
|
|
112
|
-
curRange.splice(hunk.oldLines, 0, '\')
|
|
113
|
-
}
|
|
114
|
-
if ((!oldEOFNewline && !noNlBeforeAdds) || !newEOFNewline) {
|
|
115
|
-
curRange.push('\')
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
hunks.push(hunk)
|
|
119
|
-
|
|
120
|
-
oldRangeStart = 0
|
|
121
|
-
newRangeStart = 0
|
|
122
|
-
curRange = []
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
oldLine += lines.length
|
|
126
|
-
newLine += lines.length
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return formatPatch({
|
|
131
|
-
oldFileName: name,
|
|
132
|
-
newFileName: name,
|
|
133
|
-
hunks: hunks
|
|
134
|
-
})
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
module.exports.applyPatch = (prev, patch) => jsdiff.applyPatch(prev, patch)
|
|
138
|
-
module.exports.createPatch = createPatch
|
|
1
|
+
const jsdiff = require('diff')
|
|
2
|
+
const gdiff = new (require('diff-match-patch'))()
|
|
3
|
+
|
|
4
|
+
function formatPatch (diff) {
|
|
5
|
+
const ret = []
|
|
6
|
+
if (diff.oldFileName === diff.newFileName) {
|
|
7
|
+
ret.push('Index: ' + diff.oldFileName)
|
|
8
|
+
}
|
|
9
|
+
ret.push('===================================================================')
|
|
10
|
+
ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader))
|
|
11
|
+
ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader))
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < diff.hunks.length; i++) {
|
|
14
|
+
const hunk = diff.hunks[i]
|
|
15
|
+
ret.push(
|
|
16
|
+
'@@ -' + hunk.oldStart + ',' + hunk.oldLines +
|
|
17
|
+
' +' + hunk.newStart + ',' + hunk.newLines +
|
|
18
|
+
' @@'
|
|
19
|
+
)
|
|
20
|
+
ret.push.apply(ret, hunk.lines)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const res = ret.join('\n') + '\n'
|
|
24
|
+
return res
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createPatch (name, older, newer, context) {
|
|
28
|
+
const { chars1, chars2, lineArray } = gdiff.diff_linesToChars_(older, newer)
|
|
29
|
+
const cdiff = gdiff.diff_main(chars1, chars2, false)
|
|
30
|
+
gdiff.diff_charsToLines_(cdiff, lineArray)
|
|
31
|
+
|
|
32
|
+
const diff = cdiff.map(([op, data]) => {
|
|
33
|
+
const r = { value: data }
|
|
34
|
+
if (op === 1) {
|
|
35
|
+
r.added = true
|
|
36
|
+
}
|
|
37
|
+
if (op === -1) {
|
|
38
|
+
r.removed = true
|
|
39
|
+
}
|
|
40
|
+
return r
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
diff.push({ value: '', lines: [] }) // Append an empty value to make cleanup easier
|
|
44
|
+
|
|
45
|
+
function contextLines (lines) {
|
|
46
|
+
return lines.map(function (entry) { return ' ' + entry })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const hunks = []
|
|
50
|
+
let oldRangeStart = 0
|
|
51
|
+
let newRangeStart = 0
|
|
52
|
+
let curRange = []
|
|
53
|
+
|
|
54
|
+
let oldLine = 1; let newLine = 1
|
|
55
|
+
for (let i = 0; i < diff.length; i++) {
|
|
56
|
+
const current = diff[i]
|
|
57
|
+
|
|
58
|
+
const lines = current.lines || current.value.replace(/\n$/, '').split('\n')
|
|
59
|
+
current.lines = lines
|
|
60
|
+
|
|
61
|
+
if (current.added || current.removed) {
|
|
62
|
+
// If we have previous context, start with that
|
|
63
|
+
if (!oldRangeStart) {
|
|
64
|
+
const prev = diff[i - 1]
|
|
65
|
+
oldRangeStart = oldLine
|
|
66
|
+
newRangeStart = newLine
|
|
67
|
+
|
|
68
|
+
if (prev) {
|
|
69
|
+
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : []
|
|
70
|
+
oldRangeStart -= curRange.length
|
|
71
|
+
newRangeStart -= curRange.length
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Output our changes
|
|
76
|
+
curRange.push(...lines.map(function (entry) {
|
|
77
|
+
return (current.added ? '+' : '-') + entry
|
|
78
|
+
}))
|
|
79
|
+
|
|
80
|
+
// Track the updated file position
|
|
81
|
+
if (current.added) {
|
|
82
|
+
newLine += lines.length
|
|
83
|
+
} else {
|
|
84
|
+
oldLine += lines.length
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
// Identical context lines. Track line changes
|
|
88
|
+
if (oldRangeStart) {
|
|
89
|
+
// Close out any changes that have been output (or join overlapping)
|
|
90
|
+
if (lines.length <= context * 2 && i < diff.length - 2) {
|
|
91
|
+
// Overlapping
|
|
92
|
+
curRange.push(...contextLines(lines))
|
|
93
|
+
} else {
|
|
94
|
+
// end the range and output
|
|
95
|
+
const contextSize = Math.min(lines.length, context)
|
|
96
|
+
curRange.push(...contextLines(lines.slice(0, contextSize)))
|
|
97
|
+
|
|
98
|
+
const hunk = {
|
|
99
|
+
oldStart: oldRangeStart,
|
|
100
|
+
oldLines: (oldLine - oldRangeStart + contextSize),
|
|
101
|
+
newStart: newRangeStart,
|
|
102
|
+
newLines: (newLine - newRangeStart + contextSize),
|
|
103
|
+
lines: curRange
|
|
104
|
+
}
|
|
105
|
+
if (i >= diff.length - 2 && lines.length <= context) {
|
|
106
|
+
// EOF is inside this hunk
|
|
107
|
+
const oldEOFNewline = (/\n$/.test(older))
|
|
108
|
+
const newEOFNewline = (/\n$/.test(newer))
|
|
109
|
+
const noNlBeforeAdds = lines.length === 0 && curRange.length > hunk.oldLines
|
|
110
|
+
if (!oldEOFNewline && noNlBeforeAdds) {
|
|
111
|
+
// special case: old has no eol and no trailing context; no-nl can end up before adds
|
|
112
|
+
curRange.splice(hunk.oldLines, 0, '\')
|
|
113
|
+
}
|
|
114
|
+
if ((!oldEOFNewline && !noNlBeforeAdds) || !newEOFNewline) {
|
|
115
|
+
curRange.push('\')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
hunks.push(hunk)
|
|
119
|
+
|
|
120
|
+
oldRangeStart = 0
|
|
121
|
+
newRangeStart = 0
|
|
122
|
+
curRange = []
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
oldLine += lines.length
|
|
126
|
+
newLine += lines.length
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return formatPatch({
|
|
131
|
+
oldFileName: name,
|
|
132
|
+
newFileName: name,
|
|
133
|
+
hunks: hunks
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports.applyPatch = (prev, patch) => jsdiff.applyPatch(prev, patch)
|
|
138
|
+
module.exports.createPatch = createPatch
|