diff --git a/package-lock.json b/package-lock.json index 04544ef..96e2997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5442,6 +5442,16 @@ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, + "files-diff": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/files-diff/-/files-diff-0.0.2.tgz", + "integrity": "sha512-5uD9B8Ga0o4X5FqG1O8aSoyBKLIW1qKB/385F5JvT3HzDO6x+ykWhtpCgbWrDNN8QPaWWqSy8lk1bY/bNgfP5A==", + "requires": { + "diff": "^4.0.2", + "escape-html": "^1.0.3", + "string-similarity": "^4.0.1" + } + }, "filesize": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", diff --git a/package.json b/package.json index 58678f9..d7f39b1 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "do-bulma": "git+https://github.com/do-community/do-bulma.git", "do-vue": "git+https://github.com/do-community/do-vue.git", "escape-html": "^1.0.3", + "files-diff": "0.0.2", "memory-tar-create": "0.0.2", "pretty-checkbox-vue": "^1.1.9", "prismjs": "^1.20.0", diff --git a/src/nginxconfig/templates/app.vue b/src/nginxconfig/templates/app.vue index 1504301..ebe6a46 100644 --- a/src/nginxconfig/templates/app.vue +++ b/src/nginxconfig/templates/app.vue @@ -100,7 +100,7 @@ THE SOFTWARE. import sha2_256 from 'simple-js-sha2-256'; import escape from 'escape-html'; import Header from 'do-vue/src/templates/header'; - import diff from '../util/diff'; + import diff from 'files-diff'; import isChanged from '../util/is_changed'; import importData from '../util/import_data'; import isObject from '../util/is_object'; @@ -213,12 +213,18 @@ THE SOFTWARE. }, updateDiff(newConf, oldConf) { // Calculate the diff & highlight after render - this.$data.confFilesOutput = Object.values(diff(newConf, oldConf)).map(conf => { - const name = `${escape(this.$data.global.nginx.nginxConfigDirectory.computed)}/${conf[0]}`; + const diffConf = diff(newConf, oldConf, { + highlightFunction: value => `${value}`, + }); + this.$data.confFilesOutput = Object.values(diffConf).map(({ name, content }) => { + const diffName = name.filter(x => !x.removed).map(x => x.value).join(''); + const confName = `${escape(this.$data.global.nginx.nginxConfigDirectory.computed)}/${diffName}`; + const diffContent = content.filter(x => !x.removed).map(x => x.value).join(''); + return [ - name, - conf[1], - `${sha2_256(name)}-${sha2_256(conf[1])}`, + confName, + diffContent, + `${sha2_256(confName)}-${sha2_256(diffContent)}`, ]; }); this.$nextTick(() => this.$data.confWatcherWaiting = false); diff --git a/src/nginxconfig/util/diff/conf_lines.js b/src/nginxconfig/util/diff/conf_lines.js deleted file mode 100644 index ff04f77..0000000 --- a/src/nginxconfig/util/diff/conf_lines.js +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2020 DigitalOcean - -This code is licensed under the MIT License. -You may obtain a copy of the License at -https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -import { diffLines } from 'diff'; -import escape from 'escape-html'; - -export default (newConfFile, oldConfFile) => { - // Get the diff - const diff = diffLines(oldConfFile, newConfFile); - - // Wrap additions in , drop removals - return diff.map((change, index, array) => { - if (change.removed) return ''; - - const escaped = escape(change.value); - - // Don't mark as diff if nothing changed - if (!change.added) return escaped; - - // Don't mark as diff if only whitespace changed - if (index > 0 && array[index - 1].removed) { - if (array[index - 1].value.replace(/\s/g, '') === change.value.replace(/\s/g, '')) { - return escaped; - } - } - if (index < array.length - 1 && array[index + 1].removed) { - if (array[index + 1].value.replace(/\s/g, '') === change.value.replace(/\s/g, '')) { - return escaped; - } - } - - // Mark the diff, without highlighting whitespace - return escaped - .split('\n') - .map(part => part.replace(/^(\s*)(.*)(\s*)$/, '$1$2$3')) - .join('\n'); - }).join(''); -}; diff --git a/src/nginxconfig/util/diff/index.js b/src/nginxconfig/util/diff/index.js deleted file mode 100644 index 348fbfc..0000000 --- a/src/nginxconfig/util/diff/index.js +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2020 DigitalOcean - -This code is licensed under the MIT License. -You may obtain a copy of the License at -https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -import escape from 'escape-html'; -import renames from './renames'; -import confLines from './conf_lines'; -import names from './names'; - -export default (newConf, oldConf) => { - // Consider renames - const renameMap = renames(newConf, oldConf); - - // Store the diff config files - const newFiles = {}; - - // Work through each file in the new config - for (const name in newConf) { - if (!Object.prototype.hasOwnProperty.call(newConf, name)) continue; - - let newFileName = escape(name); - let newFileConf = escape(newConf[name]); - - // If this file was in the old config (same name or renamed & similar) - // Calculate the diff of the configs - const old = oldConf && oldConf[renameMap[name]]; - if (old && old !== newConf[name]) { - console.info(`Diffing ${name}...`); - newFileConf = confLines(newConf[name], old); - } - - // If the file was renamed we should diff that too - if (name in renameMap && renameMap[name] !== name) { - newFileName = names(name, renameMap[name]); - } - - // Store! - newFiles[name] = [ - newFileName, - newFileConf, - ]; - } - - // Done - return newFiles; -}; diff --git a/src/nginxconfig/util/diff/names.js b/src/nginxconfig/util/diff/names.js deleted file mode 100644 index ee1165c..0000000 --- a/src/nginxconfig/util/diff/names.js +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2020 DigitalOcean - -This code is licensed under the MIT License. -You may obtain a copy of the License at -https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -import { diffChars } from 'diff'; -import escape from 'escape-html'; - -export default (newConfName, oldConfName) => { - // Get the diff - const diff = diffChars(oldConfName, newConfName); - - // Wrap additions in , drop removals - return diff.map(change => { - if (change.removed) return ''; - - const escaped = escape(change.value); - - // Don't mark as diff if nothing changed - if (!change.added) return escaped; - - // Mark the diff, without highlighting whitespace - return escaped.replace(/^(\s*)(.*)(\s*)$/, '$1$2$3'); - }).join(''); -}; diff --git a/src/nginxconfig/util/diff/renames.js b/src/nginxconfig/util/diff/renames.js deleted file mode 100644 index d5303be..0000000 --- a/src/nginxconfig/util/diff/renames.js +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2020 DigitalOcean - -This code is licensed under the MIT License. -You may obtain a copy of the License at -https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -import { compareTwoStrings } from 'string-similarity'; - -export default (newConf, oldConf) => { - const newNames = Object.keys(newConf); - const oldNames = Object.keys(oldConf); - const removed = oldNames.filter(name => !newNames.includes(name)); - const added = newNames.filter(name => !oldNames.includes(name)); - - // For each newly added file, compare it to all the old files - const addedSimilarity = {}; - for (const newName of added) { - addedSimilarity[newName] = { old: '', similarity: 0 }; - - for (const oldName of removed) { - const similarity = compareTwoStrings(newConf[newName], oldConf[oldName]); - - // Only care about > 50% similarity - if (similarity <= .5) continue; - - // Store the most similar - if (similarity > addedSimilarity[newName].similarity) - addedSimilarity[newName] = { old: oldName, similarity }; - } - } - - // Create a rename map - return newNames.reduce((prev, current) => { - if (current in addedSimilarity && addedSimilarity[current].similarity) - prev[current] = addedSimilarity[current].old; - else - prev[current] = current; - return prev; - }, {}); -};