decap-cms-lib-util 2.16.0-beta.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/CHANGELOG.md +601 -0
- package/LICENSE +22 -0
- package/README.md +22 -0
- package/dist/decap-cms-lib-util.js +3 -0
- package/dist/decap-cms-lib-util.js.LICENSE.txt +15 -0
- package/dist/decap-cms-lib-util.js.map +1 -0
- package/dist/esm/API.js +177 -0
- package/dist/esm/APIError.js +47 -0
- package/dist/esm/APIUtils.js +48 -0
- package/dist/esm/AccessTokenError.js +41 -0
- package/dist/esm/Cursor.js +135 -0
- package/dist/esm/EditorialWorkflowError.js +43 -0
- package/dist/esm/asyncLock.js +45 -0
- package/dist/esm/backendUtil.js +98 -0
- package/dist/esm/getBlobSHA.js +19 -0
- package/dist/esm/git-lfs.js +123 -0
- package/dist/esm/implementation.js +304 -0
- package/dist/esm/index.js +403 -0
- package/dist/esm/loadScript.js +27 -0
- package/dist/esm/localForage.js +25 -0
- package/dist/esm/path.js +93 -0
- package/dist/esm/promise.js +23 -0
- package/dist/esm/types/semaphore.d.js +1 -0
- package/dist/esm/unsentRequest.js +123 -0
- package/package.json +29 -0
- package/src/API.ts +220 -0
- package/src/APIError.ts +17 -0
- package/src/APIUtils.ts +38 -0
- package/src/AccessTokenError.ts +11 -0
- package/src/Cursor.ts +178 -0
- package/src/EditorialWorkflowError.ts +12 -0
- package/src/__tests__/api.spec.js +12 -0
- package/src/__tests__/apiUtils.spec.js +74 -0
- package/src/__tests__/asyncLock.spec.js +85 -0
- package/src/__tests__/backendUtil.spec.js +97 -0
- package/src/__tests__/implementation.spec.js +58 -0
- package/src/__tests__/path.spec.js +53 -0
- package/src/__tests__/unsentRequest.spec.js +19 -0
- package/src/asyncLock.ts +43 -0
- package/src/backendUtil.ts +120 -0
- package/src/getBlobSHA.ts +12 -0
- package/src/git-lfs.ts +133 -0
- package/src/implementation.ts +573 -0
- package/src/index.ts +210 -0
- package/src/loadScript.js +24 -0
- package/src/localForage.ts +21 -0
- package/src/path.ts +86 -0
- package/src/promise.ts +21 -0
- package/src/types/semaphore.d.ts +5 -0
- package/src/unsentRequest.js +133 -0
- package/webpack.config.js +3 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createPointerFile = createPointerFile;
|
|
7
|
+
exports.getLargeMediaFilteredMediaFiles = getLargeMediaFilteredMediaFiles;
|
|
8
|
+
exports.getLargeMediaPatternsFromGitAttributesFile = void 0;
|
|
9
|
+
exports.getPointerFileForMediaFileObj = getPointerFileForMediaFileObj;
|
|
10
|
+
exports.parsePointerFile = void 0;
|
|
11
|
+
var _map2 = _interopRequireDefault(require("lodash/fp/map"));
|
|
12
|
+
var _fromPairs2 = _interopRequireDefault(require("lodash/fp/fromPairs"));
|
|
13
|
+
var _flow2 = _interopRequireDefault(require("lodash/fp/flow"));
|
|
14
|
+
var _filter2 = _interopRequireDefault(require("lodash/fp/filter"));
|
|
15
|
+
var _getBlobSHA = _interopRequireDefault(require("./getBlobSHA"));
|
|
16
|
+
const _excluded = ["size", "oid"]; //
|
|
17
|
+
// Pointer file parsing
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
20
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
21
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
22
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
23
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
24
|
+
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
25
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
26
|
+
function splitIntoLines(str) {
|
|
27
|
+
return str.split('\n');
|
|
28
|
+
}
|
|
29
|
+
function splitIntoWords(str) {
|
|
30
|
+
return str.split(/\s+/g);
|
|
31
|
+
}
|
|
32
|
+
function isNonEmptyString(str) {
|
|
33
|
+
return str !== '';
|
|
34
|
+
}
|
|
35
|
+
const withoutEmptyLines = (0, _flow2.default)([(0, _map2.default)(str => str.trim()), (0, _filter2.default)(isNonEmptyString)]);
|
|
36
|
+
const parsePointerFile = (0, _flow2.default)([splitIntoLines, withoutEmptyLines, (0, _map2.default)(splitIntoWords), _fromPairs2.default, _ref => {
|
|
37
|
+
let {
|
|
38
|
+
size,
|
|
39
|
+
oid
|
|
40
|
+
} = _ref,
|
|
41
|
+
rest = _objectWithoutProperties(_ref, _excluded);
|
|
42
|
+
return _objectSpread({
|
|
43
|
+
size: parseInt(size),
|
|
44
|
+
sha: oid === null || oid === void 0 ? void 0 : oid.split(':')[1]
|
|
45
|
+
}, rest);
|
|
46
|
+
}]);
|
|
47
|
+
|
|
48
|
+
//
|
|
49
|
+
// .gitattributes file parsing
|
|
50
|
+
exports.parsePointerFile = parsePointerFile;
|
|
51
|
+
function removeGitAttributesCommentsFromLine(line) {
|
|
52
|
+
return line.split('#')[0];
|
|
53
|
+
}
|
|
54
|
+
function parseGitPatternAttribute(attributeString) {
|
|
55
|
+
// There are three kinds of attribute settings:
|
|
56
|
+
// - a key=val pair sets an attribute to a specific value
|
|
57
|
+
// - a key without a value and a leading hyphen sets an attribute to false
|
|
58
|
+
// - a key without a value and no leading hyphen sets an attribute
|
|
59
|
+
// to true
|
|
60
|
+
if (attributeString.includes('=')) {
|
|
61
|
+
return attributeString.split('=');
|
|
62
|
+
}
|
|
63
|
+
if (attributeString.startsWith('-')) {
|
|
64
|
+
return [attributeString.slice(1), false];
|
|
65
|
+
}
|
|
66
|
+
return [attributeString, true];
|
|
67
|
+
}
|
|
68
|
+
const parseGitPatternAttributes = (0, _flow2.default)([(0, _map2.default)(parseGitPatternAttribute), _fromPairs2.default]);
|
|
69
|
+
const parseGitAttributesPatternLine = (0, _flow2.default)([splitIntoWords, ([pattern, ...attributes]) => [pattern, parseGitPatternAttributes(attributes)]]);
|
|
70
|
+
const parseGitAttributesFileToPatternAttributePairs = (0, _flow2.default)([splitIntoLines, (0, _map2.default)(removeGitAttributesCommentsFromLine), withoutEmptyLines, (0, _map2.default)(parseGitAttributesPatternLine)]);
|
|
71
|
+
const getLargeMediaPatternsFromGitAttributesFile = (0, _flow2.default)([parseGitAttributesFileToPatternAttributePairs, (0, _filter2.default)(([, attributes]) => attributes.filter === 'lfs' && attributes.diff === 'lfs' && attributes.merge === 'lfs'), (0, _map2.default)(([pattern]) => pattern)]);
|
|
72
|
+
exports.getLargeMediaPatternsFromGitAttributesFile = getLargeMediaPatternsFromGitAttributesFile;
|
|
73
|
+
function createPointerFile({
|
|
74
|
+
size,
|
|
75
|
+
sha
|
|
76
|
+
}) {
|
|
77
|
+
return `\
|
|
78
|
+
version https://git-lfs.github.com/spec/v1
|
|
79
|
+
oid sha256:${sha}
|
|
80
|
+
size ${size}
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
async function getPointerFileForMediaFileObj(client, fileObj, path) {
|
|
84
|
+
const {
|
|
85
|
+
name,
|
|
86
|
+
size
|
|
87
|
+
} = fileObj;
|
|
88
|
+
const sha = await (0, _getBlobSHA.default)(fileObj);
|
|
89
|
+
await client.uploadResource({
|
|
90
|
+
sha,
|
|
91
|
+
size
|
|
92
|
+
}, fileObj);
|
|
93
|
+
const pointerFileString = createPointerFile({
|
|
94
|
+
sha,
|
|
95
|
+
size
|
|
96
|
+
});
|
|
97
|
+
const pointerFileBlob = new Blob([pointerFileString]);
|
|
98
|
+
const pointerFile = new File([pointerFileBlob], name, {
|
|
99
|
+
type: 'text/plain'
|
|
100
|
+
});
|
|
101
|
+
const pointerFileSHA = await (0, _getBlobSHA.default)(pointerFile);
|
|
102
|
+
return {
|
|
103
|
+
fileObj: pointerFile,
|
|
104
|
+
size: pointerFileBlob.size,
|
|
105
|
+
sha: pointerFileSHA,
|
|
106
|
+
raw: pointerFileString,
|
|
107
|
+
path
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async function getLargeMediaFilteredMediaFiles(client, mediaFiles) {
|
|
111
|
+
return await Promise.all(mediaFiles.map(async mediaFile => {
|
|
112
|
+
const {
|
|
113
|
+
fileObj,
|
|
114
|
+
path
|
|
115
|
+
} = mediaFile;
|
|
116
|
+
const fixedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
117
|
+
if (!client.matchPath(fixedPath)) {
|
|
118
|
+
return mediaFile;
|
|
119
|
+
}
|
|
120
|
+
const pointerFileDetails = await getPointerFileForMediaFileObj(client, fileObj, path);
|
|
121
|
+
return _objectSpread(_objectSpread({}, mediaFile), pointerFileDetails);
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.allEntriesByFolder = allEntriesByFolder;
|
|
7
|
+
exports.blobToFileObj = blobToFileObj;
|
|
8
|
+
exports.entriesByFiles = entriesByFiles;
|
|
9
|
+
exports.entriesByFolder = entriesByFolder;
|
|
10
|
+
exports.getLocalTree = getLocalTree;
|
|
11
|
+
exports.getMediaAsBlob = getMediaAsBlob;
|
|
12
|
+
exports.getMediaDisplayURL = getMediaDisplayURL;
|
|
13
|
+
exports.persistLocalTree = persistLocalTree;
|
|
14
|
+
exports.runWithLock = runWithLock;
|
|
15
|
+
exports.unpublishedEntries = unpublishedEntries;
|
|
16
|
+
var _sortBy2 = _interopRequireDefault(require("lodash/sortBy"));
|
|
17
|
+
var _unionBy2 = _interopRequireDefault(require("lodash/unionBy"));
|
|
18
|
+
var _semaphore = _interopRequireDefault(require("semaphore"));
|
|
19
|
+
var _path = require("./path");
|
|
20
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
22
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
23
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
24
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
25
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
26
|
+
const MAX_CONCURRENT_DOWNLOADS = 10;
|
|
27
|
+
async function fetchFiles(files, readFile, readFileMetadata, apiName) {
|
|
28
|
+
const sem = (0, _semaphore.default)(MAX_CONCURRENT_DOWNLOADS);
|
|
29
|
+
const promises = [];
|
|
30
|
+
files.forEach(file => {
|
|
31
|
+
promises.push(new Promise(resolve => sem.take(async () => {
|
|
32
|
+
try {
|
|
33
|
+
const [data, fileMetadata] = await Promise.all([readFile(file.path, file.id, {
|
|
34
|
+
parseText: true
|
|
35
|
+
}), readFileMetadata(file.path, file.id)]);
|
|
36
|
+
resolve({
|
|
37
|
+
file: _objectSpread(_objectSpread({}, file), fileMetadata),
|
|
38
|
+
data: data
|
|
39
|
+
});
|
|
40
|
+
sem.leave();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
sem.leave();
|
|
43
|
+
console.error(`failed to load file from ${apiName}: ${file.path}`);
|
|
44
|
+
resolve({
|
|
45
|
+
error: true
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
})));
|
|
49
|
+
});
|
|
50
|
+
return Promise.all(promises).then(loadedEntries => loadedEntries.filter(loadedEntry => !loadedEntry.error));
|
|
51
|
+
}
|
|
52
|
+
async function entriesByFolder(listFiles, readFile, readFileMetadata, apiName) {
|
|
53
|
+
const files = await listFiles();
|
|
54
|
+
return fetchFiles(files, readFile, readFileMetadata, apiName);
|
|
55
|
+
}
|
|
56
|
+
async function entriesByFiles(files, readFile, readFileMetadata, apiName) {
|
|
57
|
+
return fetchFiles(files, readFile, readFileMetadata, apiName);
|
|
58
|
+
}
|
|
59
|
+
async function unpublishedEntries(listEntriesKeys) {
|
|
60
|
+
try {
|
|
61
|
+
const keys = await listEntriesKeys();
|
|
62
|
+
return keys;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error.message === 'Not Found') {
|
|
65
|
+
return Promise.resolve([]);
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function blobToFileObj(name, blob) {
|
|
71
|
+
const options = name.match(/.svg$/) ? {
|
|
72
|
+
type: 'image/svg+xml'
|
|
73
|
+
} : {};
|
|
74
|
+
return new File([blob], name, options);
|
|
75
|
+
}
|
|
76
|
+
async function getMediaAsBlob(path, id, readFile) {
|
|
77
|
+
let blob;
|
|
78
|
+
if (path.match(/.svg$/)) {
|
|
79
|
+
const text = await readFile(path, id, {
|
|
80
|
+
parseText: true
|
|
81
|
+
});
|
|
82
|
+
blob = new Blob([text], {
|
|
83
|
+
type: 'image/svg+xml'
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
blob = await readFile(path, id, {
|
|
87
|
+
parseText: false
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return blob;
|
|
91
|
+
}
|
|
92
|
+
async function getMediaDisplayURL(displayURL, readFile, semaphore) {
|
|
93
|
+
const {
|
|
94
|
+
path,
|
|
95
|
+
id
|
|
96
|
+
} = displayURL;
|
|
97
|
+
return new Promise((resolve, reject) => semaphore.take(() => getMediaAsBlob(path, id, readFile).then(blob => URL.createObjectURL(blob)).then(resolve, reject).finally(() => semaphore.leave())));
|
|
98
|
+
}
|
|
99
|
+
async function runWithLock(lock, func, message) {
|
|
100
|
+
try {
|
|
101
|
+
const acquired = await lock.acquire();
|
|
102
|
+
if (!acquired) {
|
|
103
|
+
console.warn(message);
|
|
104
|
+
}
|
|
105
|
+
const result = await func();
|
|
106
|
+
return result;
|
|
107
|
+
} finally {
|
|
108
|
+
lock.release();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const LOCAL_KEY = 'git.local';
|
|
112
|
+
function getLocalKey({
|
|
113
|
+
branch,
|
|
114
|
+
folder,
|
|
115
|
+
extension,
|
|
116
|
+
depth
|
|
117
|
+
}) {
|
|
118
|
+
return `${LOCAL_KEY}.${branch}.${folder}.${extension}.${depth}`;
|
|
119
|
+
}
|
|
120
|
+
async function persistLocalTree({
|
|
121
|
+
localForage,
|
|
122
|
+
localTree,
|
|
123
|
+
branch,
|
|
124
|
+
folder,
|
|
125
|
+
extension,
|
|
126
|
+
depth
|
|
127
|
+
}) {
|
|
128
|
+
await localForage.setItem(getLocalKey({
|
|
129
|
+
branch,
|
|
130
|
+
folder,
|
|
131
|
+
extension,
|
|
132
|
+
depth
|
|
133
|
+
}), localTree);
|
|
134
|
+
}
|
|
135
|
+
async function getLocalTree({
|
|
136
|
+
localForage,
|
|
137
|
+
branch,
|
|
138
|
+
folder,
|
|
139
|
+
extension,
|
|
140
|
+
depth
|
|
141
|
+
}) {
|
|
142
|
+
const localTree = await localForage.getItem(getLocalKey({
|
|
143
|
+
branch,
|
|
144
|
+
folder,
|
|
145
|
+
extension,
|
|
146
|
+
depth
|
|
147
|
+
}));
|
|
148
|
+
return localTree;
|
|
149
|
+
}
|
|
150
|
+
async function getDiffFromLocalTree({
|
|
151
|
+
branch,
|
|
152
|
+
localTree,
|
|
153
|
+
folder,
|
|
154
|
+
getDifferences,
|
|
155
|
+
filterFile,
|
|
156
|
+
getFileId
|
|
157
|
+
}) {
|
|
158
|
+
const diff = await getDifferences(branch.sha, localTree.head);
|
|
159
|
+
const diffFiles = diff.filter(d => {
|
|
160
|
+
var _d$oldPath, _d$newPath;
|
|
161
|
+
return ((_d$oldPath = d.oldPath) === null || _d$oldPath === void 0 ? void 0 : _d$oldPath.startsWith(folder)) || ((_d$newPath = d.newPath) === null || _d$newPath === void 0 ? void 0 : _d$newPath.startsWith(folder));
|
|
162
|
+
}).reduce((acc, d) => {
|
|
163
|
+
if (d.status === 'renamed') {
|
|
164
|
+
acc.push({
|
|
165
|
+
path: d.oldPath,
|
|
166
|
+
name: (0, _path.basename)(d.oldPath),
|
|
167
|
+
deleted: true
|
|
168
|
+
});
|
|
169
|
+
acc.push({
|
|
170
|
+
path: d.newPath,
|
|
171
|
+
name: (0, _path.basename)(d.newPath),
|
|
172
|
+
deleted: false
|
|
173
|
+
});
|
|
174
|
+
} else if (d.status === 'deleted') {
|
|
175
|
+
acc.push({
|
|
176
|
+
path: d.oldPath,
|
|
177
|
+
name: (0, _path.basename)(d.oldPath),
|
|
178
|
+
deleted: true
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
acc.push({
|
|
182
|
+
path: d.newPath || d.oldPath,
|
|
183
|
+
name: (0, _path.basename)(d.newPath || d.oldPath),
|
|
184
|
+
deleted: false
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return acc;
|
|
188
|
+
}, []).filter(filterFile);
|
|
189
|
+
const diffFilesWithIds = await Promise.all(diffFiles.map(async file => {
|
|
190
|
+
if (!file.deleted) {
|
|
191
|
+
const id = await getFileId(file.path);
|
|
192
|
+
return _objectSpread(_objectSpread({}, file), {}, {
|
|
193
|
+
id
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
return _objectSpread(_objectSpread({}, file), {}, {
|
|
197
|
+
id: ''
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
return diffFilesWithIds;
|
|
202
|
+
}
|
|
203
|
+
async function allEntriesByFolder({
|
|
204
|
+
listAllFiles,
|
|
205
|
+
readFile,
|
|
206
|
+
readFileMetadata,
|
|
207
|
+
apiName,
|
|
208
|
+
branch,
|
|
209
|
+
localForage,
|
|
210
|
+
folder,
|
|
211
|
+
extension,
|
|
212
|
+
depth,
|
|
213
|
+
getDefaultBranch,
|
|
214
|
+
isShaExistsInBranch,
|
|
215
|
+
getDifferences,
|
|
216
|
+
getFileId,
|
|
217
|
+
filterFile,
|
|
218
|
+
customFetch
|
|
219
|
+
}) {
|
|
220
|
+
async function listAllFilesAndPersist() {
|
|
221
|
+
const files = await listAllFiles(folder, extension, depth);
|
|
222
|
+
const branch = await getDefaultBranch();
|
|
223
|
+
await persistLocalTree({
|
|
224
|
+
localForage,
|
|
225
|
+
localTree: {
|
|
226
|
+
head: branch.sha,
|
|
227
|
+
files: files.map(f => ({
|
|
228
|
+
id: f.id,
|
|
229
|
+
path: f.path,
|
|
230
|
+
name: (0, _path.basename)(f.path)
|
|
231
|
+
}))
|
|
232
|
+
},
|
|
233
|
+
branch: branch.name,
|
|
234
|
+
depth,
|
|
235
|
+
extension,
|
|
236
|
+
folder
|
|
237
|
+
});
|
|
238
|
+
return files;
|
|
239
|
+
}
|
|
240
|
+
async function listFiles() {
|
|
241
|
+
const localTree = await getLocalTree({
|
|
242
|
+
localForage,
|
|
243
|
+
branch,
|
|
244
|
+
folder,
|
|
245
|
+
extension,
|
|
246
|
+
depth
|
|
247
|
+
});
|
|
248
|
+
if (localTree) {
|
|
249
|
+
const branch = await getDefaultBranch();
|
|
250
|
+
// if the branch was forced pushed the local tree sha can be removed from the remote tree
|
|
251
|
+
const localTreeInBranch = await isShaExistsInBranch(branch.name, localTree.head);
|
|
252
|
+
if (!localTreeInBranch) {
|
|
253
|
+
console.log(`Can't find local tree head '${localTree.head}' in branch '${branch.name}', rebuilding local tree`);
|
|
254
|
+
return listAllFilesAndPersist();
|
|
255
|
+
}
|
|
256
|
+
const diff = await getDiffFromLocalTree({
|
|
257
|
+
branch,
|
|
258
|
+
localTree,
|
|
259
|
+
folder,
|
|
260
|
+
extension,
|
|
261
|
+
depth,
|
|
262
|
+
getDifferences,
|
|
263
|
+
getFileId,
|
|
264
|
+
filterFile
|
|
265
|
+
}).catch(e => {
|
|
266
|
+
console.log('Failed getting diff from local tree:', e);
|
|
267
|
+
return null;
|
|
268
|
+
});
|
|
269
|
+
if (!diff) {
|
|
270
|
+
console.log(`Diff is null, rebuilding local tree`);
|
|
271
|
+
return listAllFilesAndPersist();
|
|
272
|
+
}
|
|
273
|
+
if (diff.length === 0) {
|
|
274
|
+
// return local copy
|
|
275
|
+
return localTree.files;
|
|
276
|
+
} else {
|
|
277
|
+
const deleted = diff.reduce((acc, d) => {
|
|
278
|
+
acc[d.path] = d.deleted;
|
|
279
|
+
return acc;
|
|
280
|
+
}, {});
|
|
281
|
+
const newCopy = (0, _sortBy2.default)((0, _unionBy2.default)(diff.filter(d => !deleted[d.path]), localTree.files.filter(f => !deleted[f.path]), file => file.path), file => file.path);
|
|
282
|
+
await persistLocalTree({
|
|
283
|
+
localForage,
|
|
284
|
+
localTree: {
|
|
285
|
+
head: branch.sha,
|
|
286
|
+
files: newCopy
|
|
287
|
+
},
|
|
288
|
+
branch: branch.name,
|
|
289
|
+
depth,
|
|
290
|
+
extension,
|
|
291
|
+
folder
|
|
292
|
+
});
|
|
293
|
+
return newCopy;
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
return listAllFilesAndPersist();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const files = await listFiles();
|
|
300
|
+
if (customFetch) {
|
|
301
|
+
return await customFetch(files);
|
|
302
|
+
}
|
|
303
|
+
return await fetchFiles(files, readFile, readFileMetadata, apiName);
|
|
304
|
+
}
|