#javascript #git #object
#javascript #git #объект
Вопрос:
Я ищу способ создать объект из выходных данных git show, которые я использую git show -m --name-status --oneline <commit-hash>
. Выходные данные выглядят следующим образом :
5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts
Я просто хочу часть между описанием двух коммитов и получить объекты такого рода :
[
{ status: "M", path: "src/app/app.module.ts" },
{ status: "M", path: "src/app/components/accordion/accordion.component.scss" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.html" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.ts" },
{ status: "M", path: "src/app/models/MockGitService.ts" },
{ status: "M", path: "src/app/models/MockLeftPanelService.ts" },
{ status: "M", path: "src/assets/i18n/en.json" },
{ status: "M", path: "src/assets/i18n/fr.json" },
{ status: "M", path: "package.json" }
]
И
{
"src": {
"app": {
{ file: "app.module.ts", status: "M" },
"components": {
"accordion": {
{ file: "accordion.component.scss" status: "m" }
}
...
}
},
"assets": {
....
}
},
{ file: "package.json", status: "M" }
}
Я понятия не имею, как создать второй объект. Но я попробовал это для первого :
var first = test.split(/n/).map(x => {
return (x.split(/s{7}/g))
}).filter(o => o.length === 2);
console.log(first);
Проблема в том, что я получаю часть после описания второго коммита.
Как я могу приступить к созданию этих двух объектов?
ОТРЕДАКТИРОВАТЬ рабочее решение для первого объекта
var output = `5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts`;
var temp = output.split(/n/);
temp.shift();
var arr = temp.map(x => {
return (x.split(/s{7}/g))
})
var final = [];
for (s in arr) {
if (Array.isArray(arr[s]) amp;amp; arr[s].length === 2) {
final.push({ status: arr[s][0], path: arr[s][1]});
} else {
break;
}
}
console.log(final);
Комментарии:
1. Вы пытались это сделать? Если да, в чем была ваша проблема? Это выглядит как операция синтаксического анализа.
2. Я попытался создать первый объект, используя regex и slipt, но я не могу найти способ остановиться перед описанием второго коммита. А что касается второго объекта, я действительно понятия не имею…
3. Можете ли вы добавить код, который вы уже написали, к вопросу?
4. Я удалил свои попытки
5. Я отредактировал, используя пример кода
Ответ №1:
Ниже вы найдете рабочее решение с легкими модульными тестами.
Мне пришлось изменить структуру второго объекта и заполнить ее ожидаемыми данными для завершения тестов.
// this is the git output provided by the OP
const output = `
5b5f664 (from fd9fe89) Merge branch 'develop' into COMMIT-4
M src/app/app.module.ts
M src/app/components/accordion/accordion.component.scss
A src/app/components/file-diff-commit/file-diff-commit.component.html
A src/app/components/file-diff-commit/file-diff-commit.component.ts
M src/app/models/MockGitService.ts
M src/app/models/MockLeftPanelService.ts
M src/assets/i18n/en.json
M src/assets/i18n/fr.json
M package.json
5b5f664 (from a0ebd90) Merge branch 'develop' into COMMIT-4
M package.json
M src/app/components/copy-button/copy-button.component.scss
A src/app/models/CommitInformations.ts
M src/app/models/MockGitService.ts
M src/app/models/MockRightPanelService.ts
`
// this is the first shape of object required by the OP:
// it looks like the result of splitting each git output line into the file and its status
// the OP mentionned that he/she wanted only the first commit, the solution below generates a set of object per commit
const entries = [
{ status: "M", path: "src/app/app.module.ts" },
{ status: "M", path: "src/app/components/accordion/accordion.component.scss" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.html" },
{ status: "A", path: "src/app/components/file-diff-commit/file-diff-commit.component.ts" },
{ status: "M", path: "src/app/models/MockGitService.ts" },
{ status: "M", path: "src/app/models/MockLeftPanelService.ts" },
{ status: "M", path: "src/assets/i18n/en.json" },
{ status: "M", path: "src/assets/i18n/fr.json" },
{ status: "M", path: "package.json" }
];
// This is the second object shape required by the OP, slightly modified, it looks like a full folder tree structure built from the entries extracted before
const folderTree = {
folders: {
"src": {
folders: {
"app": {
folders: {
"components": {
folders: {
"accordion": {
files: {
"accordion.component.scss": { status: "m" }
}
},
"file-diff-commit": {
files: {
"file-diff-commit.component.html": { status: "a" },
"file-diff-commit.component.ts": { status: "a" }
}
}
}
},
"models": {
files: {
"MockGitService.ts": { status: "m" },
"MockLeftPanelService.ts": { status: "m" }
}
}
},
files: {
"app.module.ts": { status: "m" },
}
},
"assets": {
folders: {
"i18n": {
files: {
"en.json": { status: "m" },
"fr.json": { status: "m" }
}
}
}
}
}
}
},
files: {
"package.json": { status: "m" }
}
};
// this will serve as commit splitter
const commitReg = /[a-f0-9]{7} (from [a-f0-9]{7}) Merge branch '[wd-_] ' into [wd-_] n/g;
// converts the first object shape into the second one
function buildTreeFromEntries(entries) {
// Note and entry is { status: A|M|U, path: /w (/w )*.w }
const root = {};
entries.forEach((entry) => {
const pathSplit = entry.path.split('/');
if (pathSplit.length < 2) {
if (!root.files) {
root.files = {};
}
root.files[pathSplit[0]] = { status: entry.status.toLowerCase() };
return;
}
let current = root;
pathSplit.forEach((p, index, list) => {
if (index === list.length - 1) {
if (!current.files) {
current.files = {};
}
current.files[p] = { status: entry.status.toLowerCase() };
return;
}
if (!current.folders) {
current.folders = {};
}
if (!current.folders[p]) {
current.folders[p] = {};
}
current = current.folders[p];
});
});
return root;
}
// returns a set of results as requested by the OP by commit
function parseGitOutput(output) {
const commits = output.split(commitReg).filter(c => c.trim() !== '');
const result = [];
commits.forEach((commit) => {
const currentEntries = [];
const currentCommitResult = { entries: currentEntries };
result.push(currentCommitResult);
const files = commit.split('n').filter(c => c.trim() !== '');
files.forEach((file) => {
const statusFilePair = file.split(/s /);
const path = statusFilePair[1];
const status = statusFilePair[0];
currentEntries.push({ status, path });
});
});
result.forEach((commitResult) => {
commitResult.folderTree = buildTreeFromEntries(commitResult.entries);
});
return resu<
}
// for testing purpose only, the test is far from perfect but more or less proves the concept
function objectMatch(obj1, obj2) {
const keys = Object.keys(obj1);
for (let i = 0; i < keys.length; i ) {
const key = keys[i];
const v1 = obj1[key];
const v2 = obj2[key];
if (typeof v1 !== typeof v2) {
console.log(v1, ' is not the same type as ', v2);
return false;
}
if (typeof v1 === 'string') {
if (v1 !== v2) {
console.log(v1, ' !== ', v2);
return false;
}
continue;
}
if (!objectMatch(v1, v2)) {
return false;
}
}
return true;
}
// parsing
const parsedOutput = parseGitOutput(output)[0];
// console output of the results and tests
console.log(parsedOutput.entries);
console.log(
"entries match:",
parsedOutput.entries.every((entry, index) => objectMatch(entries[index], entry))
);
console.log("tree match:", parsedOutput.folderTree, folderTree);
console.log(parsedOutput.folderTree);
Комментарии:
1. большое спасибо! Я нашел решение для генерации первого объекта, и оно работает с использованием вашего решения в виде дерева. Я редактирую свой пост