@ocfl/ocfl 0.4.0 → 1.0.0-beta.1

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.
Files changed (138) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +24 -9
  3. package/dist/constants.d.ts +15 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +14 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/digest.d.ts +58 -0
  8. package/dist/digest.d.ts.map +1 -0
  9. package/dist/digest.js +204 -0
  10. package/dist/digest.js.map +1 -0
  11. package/dist/error.d.ts +5 -0
  12. package/dist/error.d.ts.map +1 -0
  13. package/dist/error.js +9 -0
  14. package/dist/error.js.map +1 -0
  15. package/dist/extension.d.ts +83 -0
  16. package/dist/extension.d.ts.map +1 -0
  17. package/dist/extension.js +170 -0
  18. package/dist/extension.js.map +1 -0
  19. package/dist/extensions/0002-flat-direct-storage-layout.d.ts +12 -0
  20. package/dist/extensions/0002-flat-direct-storage-layout.d.ts.map +1 -0
  21. package/dist/extensions/0002-flat-direct-storage-layout.js +34 -0
  22. package/dist/extensions/0002-flat-direct-storage-layout.js.map +1 -0
  23. package/dist/extensions/0003-hash-and-id-n-tuple-storage-layout.d.ts +15 -0
  24. package/dist/extensions/0003-hash-and-id-n-tuple-storage-layout.d.ts.map +1 -0
  25. package/dist/extensions/0003-hash-and-id-n-tuple-storage-layout.js +49 -0
  26. package/dist/extensions/0003-hash-and-id-n-tuple-storage-layout.js.map +1 -0
  27. package/dist/extensions/0004-hashed-n-tuple-storage-layout.d.ts +17 -0
  28. package/dist/extensions/0004-hashed-n-tuple-storage-layout.d.ts.map +1 -0
  29. package/dist/extensions/0004-hashed-n-tuple-storage-layout.js +54 -0
  30. package/dist/extensions/0004-hashed-n-tuple-storage-layout.js.map +1 -0
  31. package/dist/extensions/0006-flat-omit-prefix-storage-layout.d.ts +6 -0
  32. package/dist/extensions/0006-flat-omit-prefix-storage-layout.d.ts.map +1 -0
  33. package/dist/extensions/0006-flat-omit-prefix-storage-layout.js +8 -0
  34. package/dist/extensions/0006-flat-omit-prefix-storage-layout.js.map +1 -0
  35. package/dist/extensions/0007-n-tuple-omit-prefix-storage-layout.d.ts +6 -0
  36. package/dist/extensions/0007-n-tuple-omit-prefix-storage-layout.d.ts.map +1 -0
  37. package/dist/extensions/0007-n-tuple-omit-prefix-storage-layout.js +8 -0
  38. package/dist/extensions/0007-n-tuple-omit-prefix-storage-layout.js.map +1 -0
  39. package/dist/extensions/0009-digest-algorithms.d.ts +9 -0
  40. package/dist/extensions/0009-digest-algorithms.d.ts.map +1 -0
  41. package/dist/extensions/0009-digest-algorithms.js +11 -0
  42. package/dist/extensions/0009-digest-algorithms.js.map +1 -0
  43. package/dist/extensions/000N-path-direct-storage-layout.d.ts +16 -0
  44. package/dist/extensions/000N-path-direct-storage-layout.d.ts.map +1 -0
  45. package/dist/extensions/000N-path-direct-storage-layout.js +46 -0
  46. package/dist/extensions/000N-path-direct-storage-layout.js.map +1 -0
  47. package/dist/extensions/index.d.ts +23 -0
  48. package/dist/extensions/index.d.ts.map +1 -0
  49. package/dist/extensions/index.js +8 -0
  50. package/dist/extensions/index.js.map +1 -0
  51. package/dist/file.d.ts +87 -0
  52. package/dist/file.d.ts.map +1 -0
  53. package/dist/file.js +118 -0
  54. package/dist/file.js.map +1 -0
  55. package/dist/index.d.ts +61 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +73 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/inventory.d.ts +155 -0
  60. package/dist/inventory.d.ts.map +1 -0
  61. package/dist/inventory.js +591 -0
  62. package/dist/inventory.js.map +1 -0
  63. package/dist/object.d.ts +188 -0
  64. package/dist/object.d.ts.map +1 -0
  65. package/dist/object.js +425 -0
  66. package/dist/object.js.map +1 -0
  67. package/dist/storage.d.ts +94 -0
  68. package/dist/storage.d.ts.map +1 -0
  69. package/dist/storage.js +302 -0
  70. package/dist/storage.js.map +1 -0
  71. package/dist/store.d.ts +100 -0
  72. package/dist/store.d.ts.map +1 -0
  73. package/dist/store.js +157 -0
  74. package/dist/store.js.map +1 -0
  75. package/dist/transaction.d.ts +155 -0
  76. package/dist/transaction.d.ts.map +1 -0
  77. package/dist/transaction.js +395 -0
  78. package/dist/transaction.js.map +1 -0
  79. package/dist/types.d.ts +107 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/utils.d.ts +24 -0
  84. package/dist/utils.d.ts.map +1 -0
  85. package/dist/utils.js +85 -0
  86. package/dist/utils.js.map +1 -0
  87. package/dist/validation.d.ts +32 -0
  88. package/dist/validation.d.ts.map +1 -0
  89. package/dist/validation.js +31 -0
  90. package/dist/validation.js.map +1 -0
  91. package/package.json +31 -51
  92. package/src/constants.ts +16 -0
  93. package/src/digest.ts +258 -0
  94. package/src/error.ts +9 -0
  95. package/src/extension.ts +206 -0
  96. package/{lib/extensions/0002-flat-direct-storage-layout.js → src/extensions/0002-flat-direct-storage-layout.ts} +15 -22
  97. package/src/extensions/0003-hash-and-id-n-tuple-storage-layout.ts +56 -0
  98. package/src/extensions/0004-hashed-n-tuple-storage-layout.ts +59 -0
  99. package/src/extensions/0006-flat-omit-prefix-storage-layout.ts +9 -0
  100. package/src/extensions/0007-n-tuple-omit-prefix-storage-layout.ts +9 -0
  101. package/src/extensions/0009-digest-algorithms.ts +12 -0
  102. package/src/extensions/000N-path-direct-storage-layout.ts +51 -0
  103. package/src/extensions/index.ts +24 -0
  104. package/src/file.ts +161 -0
  105. package/src/index.ts +92 -0
  106. package/src/inventory.ts +634 -0
  107. package/src/object.ts +473 -0
  108. package/src/storage.ts +342 -0
  109. package/src/store.ts +199 -0
  110. package/src/transaction.ts +456 -0
  111. package/{lib/types.d.ts → src/types.ts} +28 -74
  112. package/src/utils.ts +94 -0
  113. package/src/validation.ts +46 -0
  114. package/index.js +0 -129
  115. package/index.mjs +0 -18
  116. package/lib/constants.js +0 -24
  117. package/lib/digest.js +0 -307
  118. package/lib/enum.js +0 -90
  119. package/lib/error.js +0 -19
  120. package/lib/extension.js +0 -194
  121. package/lib/extensions/0003-hash-and-id-n-tuple-storage-layout.js +0 -60
  122. package/lib/extensions/0004-hashed-n-tuple-storage-layout.js +0 -63
  123. package/lib/extensions/0005-mutable-head.js +0 -0
  124. package/lib/extensions/0006-flat-omit-prefix-storage-layout.js +0 -7
  125. package/lib/extensions/0007-n-tuple-omit-prefix-storage-layout.js +0 -7
  126. package/lib/extensions/0008-schema-registry.js +0 -0
  127. package/lib/extensions/0009-digest-algorithms.js +0 -18
  128. package/lib/extensions/000N-path-direct-storage-layout.js +0 -61
  129. package/lib/extensions/index.js +0 -13
  130. package/lib/file.js +0 -147
  131. package/lib/index.js +0 -13
  132. package/lib/inventory.js +0 -564
  133. package/lib/object.js +0 -499
  134. package/lib/storage.js +0 -338
  135. package/lib/store.js +0 -191
  136. package/lib/transaction.js +0 -448
  137. package/lib/utils.js +0 -122
  138. package/lib/validation.js +0 -174
package/lib/index.js DELETED
@@ -1,13 +0,0 @@
1
- // this is an internal index.js to avoid circular dependencies problem
2
- module.exports = {
3
- ...require('./constants.js'),
4
- ...require('./digest.js'),
5
- ...require('./transaction.js'),
6
- ...require('./extension.js'),
7
- ...require('./store.js'),
8
- ...require('./object.js'),
9
- ...require('./storage.js'),
10
- extensions: {
11
- ...require('./extensions/index.js')
12
- }
13
- };
package/lib/inventory.js DELETED
@@ -1,564 +0,0 @@
1
- 'use strict';
2
-
3
- //@ts-check
4
- /** @typedef {import('./types').Inventory} Inventory */
5
- /** @typedef {import('./types').InventoryDigests} InventoryDigests */
6
-
7
- class VersionNumber {
8
- value;
9
- zeroPaddingLength;
10
- /**
11
- *
12
- * @param {number} num
13
- * @param {number} [zeroPaddingLength]
14
- */
15
- constructor(num, zeroPaddingLength) {
16
- this.value = num;
17
- this.zeroPaddingLength = zeroPaddingLength;
18
- }
19
- valueOf() {
20
- return this.value;
21
- }
22
- toString() {
23
- return 'v' + (this.zeroPaddingLength ? (this.value + '').padStart(this.zeroPaddingLength, '0') : this.value);
24
- }
25
- next() {
26
- return new VersionNumber(this.value + 1, this.zeroPaddingLength);
27
- }
28
- previous() {
29
- const n = this.value - 1;
30
- if (n > 0) return new VersionNumber(n, this.zeroPaddingLength);
31
- }
32
- /**
33
- *
34
- * @param {number} num
35
- * @param {number} zeroPaddingLength
36
- */
37
- static fromInt(num, zeroPaddingLength) {
38
- return new VersionNumber(num, zeroPaddingLength);
39
- }
40
- /**
41
- *
42
- * @param {string} versionLabel
43
- */
44
- static fromString(versionLabel) {
45
- const label = versionLabel.replace('v', '');
46
- let zeroPaddingLength;
47
- if (label.startsWith('0')) zeroPaddingLength = label.length;
48
- return new VersionNumber(parseInt(label), zeroPaddingLength);
49
- }
50
-
51
- static next(versionLabel) {
52
- return VersionNumber.fromString(versionLabel).next();
53
- }
54
-
55
- static previous(versionLabel) {
56
- return VersionNumber.fromString(versionLabel).previous();
57
- }
58
- }
59
-
60
- /**
61
- * @typedef {{logicalPath?: string; digest?: string; contentPath?: string;}} FileRef
62
- */
63
-
64
- function findKey(file, obj) {
65
- for (let digest in obj) {
66
- const arr = obj[digest];
67
- if (arr.includes(file)) return digest;
68
- }
69
- }
70
-
71
- /**
72
- * Wrapper class for inventory data
73
- */
74
- class OcflObjectInventory {
75
- /** @type {Inventory} */
76
- #data;
77
- /** @type {{[key: string]: {[key:string]: {[key:string]: string}}}} */
78
- #fileIndex = {};
79
-
80
- metadata;
81
-
82
- /**
83
- * Helper function to find the digest by logical file path and cached it by indexing
84
- * @param {string} logicalPath
85
- * @param {string} version
86
- * @param {boolean} [onlyUsecache]
87
- */
88
- _indexGet(logicalPath, version, onlyUsecache) {
89
- let digests = this.#fileIndex[version]?.[logicalPath];
90
- if (!digests && !onlyUsecache) {
91
- // search and then index
92
- const fixity = this.fixity;
93
- const algo = this.digestAlgorithm;
94
- const digestArr = [];
95
- const mainDigest = findKey(logicalPath, this.versionState(version));
96
- if (mainDigest) {
97
- digestArr.push([algo, mainDigest]);
98
- if (fixity) {
99
- const cp = this.getContentPath(mainDigest);
100
- for (const fixityDigest in fixity) {
101
- const digest = findKey(cp, fixity[fixityDigest]);
102
- if (digest) digestArr.push([fixityDigest, digest]);
103
- }
104
- }
105
- }
106
- if (digestArr.length > 0) {
107
- const verIndex = this.#fileIndex[version] = this.#fileIndex[version] || {};
108
- digests = verIndex[logicalPath] = Object.fromEntries(digestArr);
109
- }
110
- }
111
- return digests;
112
- }
113
-
114
- _indexAdd(logicalPath, version, digests) {
115
- this.#fileIndex[version][logicalPath] = digests;
116
- }
117
-
118
- _indexRemove(logicalPath, version = this.head) {
119
- const val = this.#fileIndex[version][logicalPath];
120
- delete this.#fileIndex[version][logicalPath];
121
- return val;
122
- }
123
-
124
- _indexBuild() {
125
- // index fixity contentPaths
126
- const fixity = this.fixity;
127
- const fixityIndex = {};
128
- if (fixity) {
129
- for (const fixityAlgo in fixity) {
130
- const digestBlock = fixity[fixityAlgo];
131
- const fixityIndexDigest = fixityIndex[fixityAlgo] = {};
132
- for (const digest in digestBlock) {
133
- const cps = digestBlock[digest];
134
- for (const cp of cps) {
135
- fixityIndexDigest[cp] = digest;
136
- }
137
- }
138
- }
139
- }
140
- // index logicalPaths
141
- // { v1: { 'dir/file.txt': { sha512: 'abcdef' } } }
142
- const index = this.#fileIndex = {};
143
- const algo = this.digestAlgorithm;
144
- for (const verName in this.versions) {
145
- const ver = this.versions[verName];
146
- const indexVer = index[verName] = {};
147
- for (const digest in ver.state) {
148
- for (const lp of ver.state[digest]) {
149
- const file = indexVer[lp] = { [algo]: digest };
150
- if (fixity) {
151
- for (const fixityAlgo in fixityIndex) {
152
- const fixityIndexDigest = fixityIndex[fixityAlgo];
153
- const cps = this.manifest[digest] || [];
154
- for (const cp of cps) {
155
- if (fixityIndexDigest[cp]) file[fixityAlgo] = fixityIndexDigest[cp];
156
- }
157
- }
158
- }
159
- }
160
- }
161
- }
162
- }
163
-
164
- _indexFindPaths(prefix, version = this.head) {
165
- const res = [];
166
- const index = this.#fileIndex[version];
167
- const prefixWithSlash = prefix.endsWith('/') ? prefix : prefix + '/';
168
- for (const lp in index) {
169
- if (index[lp] && (lp === prefix || lp.startsWith(prefixWithSlash))) res.push(lp);
170
- }
171
- return res;
172
- }
173
-
174
-
175
- /**
176
- * Create a new mutable OcflObjectInventory from the object config or clone an existing inventory,
177
- * and increase the inventory version number. If data.head is undefined, starts from v1.
178
- * @param {Partial<Inventory> | OcflObjectInventory} data
179
- * @param {boolean} [cleanState]
180
- */
181
- static newVersion(data, cleanState) {
182
- if (data instanceof OcflObjectInventory) {
183
- data = data.toJSON();
184
- }
185
- if (!data.id || !data.digestAlgorithm || !data.type) throw new Error('Inventory must have an id, digestAlgorithm and type.');
186
- data.manifest = data.manifest || {};
187
- data.versions = data.versions || {};
188
- let prevVer;
189
- if (data.head) {
190
- prevVer = data.versions[data.head];
191
- data.head = VersionNumber.next(data.head).toString();
192
- } else {
193
- data.head = 'v1';
194
- cleanState = true;
195
- }
196
- data.versions[data.head] = {
197
- created: (new Date()).toISOString(),
198
- state: cleanState ? {} : JSON.parse(JSON.stringify(prevVer.state))
199
- };
200
- return new OcflObjectInventoryMut(data);
201
- }
202
-
203
- /**
204
- * Create a new inventory model
205
- * @param {Inventory} data - Initial data of the inventory
206
- * @param {string} [version] - Set the version, default to data.head
207
- */
208
- constructor(data, version) {
209
- this.#data = data;
210
- this._indexBuild();
211
- }
212
-
213
- get id() { return this.#data.id }
214
- get type() { return this.#data.type }
215
- get digestAlgorithm() { return this.#data.digestAlgorithm }
216
- get head() { return this.#data.head }
217
- /** The version number of the current head */
218
- get versionNumber() { return VersionNumber.fromString(this.head); }
219
- get contentDirectory() { return this.#data.contentDirectory || 'content' }
220
- get manifest() { return this.#data.manifest }
221
- get versions() { return this.#data.versions }
222
- get version() { return this.versions[this.head] }
223
- get fixity() { return this.#data.fixity }
224
- set fixity(val) { this.#data.fixity = val; }
225
- /** The state of the current version */
226
- get state() { return this.version.state }
227
- get created() { return this.version.created }
228
- get message() { return this.version.message }
229
- get user() { return this.version.user }
230
- //get nextVersion() { return this.versionNumber.next().toString(); }
231
- //get prevVersion() { return this.versionNumber.previous()?.toString(); }
232
-
233
- /** Return true if there has been actual change to the state of current version compared to the previous version */
234
- get isChanged() {
235
- const prev = this.versionNumber.previous()?.toString();
236
- if (!prev) return true;
237
- let diff = this.diffState(this.head, prev);
238
- return Object.keys(diff[0]).length > 0 || Object.keys(diff[1]).length > 0;
239
- }
240
- set created(val) { this.version.created = val; }
241
- set message(val) { this.version.message = val; }
242
- set user(val) { this.version.user = val; }
243
-
244
- /**
245
- * Return the state of the specified version
246
- * @param {string} [version ] - The inventory version, default to the latest
247
- */
248
- versionState(version) {
249
- if (!version || version === 'latest') version = this.head;
250
- return this.versions[version]?.state;
251
- }
252
-
253
- toString() {
254
- return JSON.stringify(this.#data, null, 2);
255
- }
256
-
257
- /**
258
- * @return {Inventory}
259
- */
260
- toJSON() {
261
- return JSON.parse(this.toString());
262
- }
263
-
264
- /**
265
- *
266
- * @param {string} [version] - The version name
267
- */
268
- *files(version) {
269
- let state;
270
- if (!version || version === 'latest') {
271
- state = this.state;
272
- version = this.head;
273
- } else {
274
- state = this.versions[version]?.state;
275
- }
276
- for (let digest in state) {
277
- let files = state[digest];
278
- let contentPath = this.getContentPath(digest);
279
- for (let logicalPath of files) {
280
- yield {
281
- logicalPath,
282
- version,
283
- digest,
284
- contentPath,
285
- fixity: this.getFixity(logicalPath, version),
286
- ...this.metadata?.[contentPath]
287
- };
288
- }
289
- }
290
- }
291
-
292
- *find(fn, version) {
293
- for (let f of this.files(version)) {
294
- if (fn(f)) yield f;
295
- }
296
- }
297
-
298
- clone() {
299
- return new OcflObjectInventory(this.toJSON());
300
- }
301
-
302
- /**
303
- * Get the first content path found with the given digest from the manifest.
304
- * Also can be used to check the existance of an entry with the specified digest in the manifest.
305
- * @param {string} digest
306
- * @return {string} - The first content path found in the array
307
- */
308
- getContentPath(digest) {
309
- let cp = this.manifest[digest];
310
- if (cp && cp.length > 0) return cp[0];
311
- }
312
-
313
- /**
314
- * Get the digest of a content represented by the logicalPath of the specified version
315
- * @param {string} logicalPath
316
- * @param {string} [versionName]
317
- */
318
- getDigest(logicalPath, versionName = this.head) {
319
- return this._indexGet(logicalPath, versionName, true)?.[this.digestAlgorithm];
320
- }
321
-
322
- /**
323
- * Get the file information by the logicalPath of the specified version
324
- * @param {string} logicalPath
325
- * @param {string} [versionName]
326
- */
327
- getFile(logicalPath, versionName = this.head) {
328
- const digest = this.getDigest(logicalPath, versionName);
329
- const contentPath = this.getContentPath(digest);
330
- const version = versionName;
331
- if (digest) {
332
- return {
333
- logicalPath,
334
- version,
335
- digest,
336
- contentPath,
337
- fixity: this.getFixity(logicalPath, version),
338
- ...this.metadata?.[contentPath]
339
- }
340
- }
341
- }
342
-
343
- getFileByDigest(digest, versionName) {
344
- if (versionName) return this.getFile(this.versions[versionName].state[digest]?.[0], versionName);
345
- for (const version in this.versions) {
346
- const logicalPath = this.versions[version].state[digest]?.[0];
347
- if (logicalPath) return this.getFile(logicalPath, version);
348
- }
349
- }
350
-
351
- getFileByContentPath(contentPath, versionName) {
352
- for (const digest in this.manifest) {
353
- if (this.manifest[digest].includes(contentPath)) return this.getFileByDigest(digest, versionName);
354
- }
355
- }
356
-
357
- /**
358
- * Get the fixity of a content represented by the logicalPath of the specified version
359
- * @param {string} logicalPath
360
- * @param {string} [versionName]
361
- */
362
- getFixity(logicalPath, versionName = this.head) {
363
- const { [this.digestAlgorithm]: digest, ...fixity } = this._indexGet(logicalPath, versionName, true) || {};
364
- return fixity;
365
- }
366
-
367
- /**
368
- * Compare the differences between the state of two versions
369
- * @param {string} version0
370
- * @param {string} version1
371
- * @return {[InventoryDigests, InventoryDigests]} - A tuple of [A, B] where A contains files
372
- * that are in `version0` but not in `version1` and B contains files
373
- * that are in `version1` but not in `version0`
374
- */
375
- diffState(version0, version1) {
376
- var state1 = this.versionState(version0) ?? {};
377
- var state2 = this.versionState(version1) ?? {};
378
-
379
- var result = [[state1, state2], [state2, state1]].map(([s1, s2]) => {
380
- /** @type {Map<string, string[]>} */
381
- let r = new Map();
382
- for (let d in s1) {
383
- let d1 = s1[d];
384
- let d2 = s2[d];
385
- let diff;
386
- if (d2 && d2.length) {
387
- diff = d1.filter(f => !d2.includes(f));
388
- } else {
389
- diff = d1.slice();
390
- }
391
- if (diff.length > 0) r.set(d, diff);
392
- }
393
- return Object.fromEntries(r);
394
- });
395
-
396
- return /** @type {[InventoryDigests, InventoryDigests]} */(result);
397
- }
398
- }
399
-
400
-
401
- /**
402
- * Wrapper class with mutable methods for inventory data
403
- */
404
- class OcflObjectInventoryMut extends OcflObjectInventory {
405
-
406
- constructor(data) {
407
- super(data);
408
- }
409
-
410
- /**
411
- * Add a new file to the inventory or update the digest of an existing file
412
- * @param {string} digest
413
- * @param {string} logicalPath
414
- * @param {{[x: string]: string}} [fixity]
415
- * @return {boolean} - true if the state is changed
416
- */
417
- add(logicalPath, digest, fixity) {
418
- const state = this.state;
419
- const contentPath = this.head + '/' + this.contentDirectory + '/' + logicalPath;
420
- // add fixity info
421
- if (fixity) {
422
- for (const digestName in fixity) {
423
- this.addFixity(contentPath, digestName, fixity[digestName]);
424
- }
425
- }
426
- if (state[digest]) {
427
- // this is a file with identical content but different name
428
- if (state[digest].indexOf(logicalPath) < 0) state[digest].push(logicalPath);
429
- else return false; // else, same digest and path, ignore
430
- } else {
431
- let mf = this.manifest[digest];
432
- if (mf && mf.length > 0) {
433
- // this is a reinstatement
434
- } else {
435
- // normal addition of a new file
436
- this.manifest[digest] = [contentPath];
437
- }
438
- if (this.getDigest(logicalPath)) {
439
- // this is an update, remove old digest
440
- this.delete(logicalPath);
441
- }
442
- state[digest] = [logicalPath];
443
- }
444
- this._indexAdd(logicalPath, this.head, { [this.digestAlgorithm]: digest, ...fixity });
445
- return true;
446
- }
447
-
448
- /**
449
- * Low-level method to add a set of digest entries associated to file into the fixity block
450
- * @param {string} contentPath
451
- * @param {string} digestName
452
- * @param {string} digestValue
453
- */
454
- addFixity(contentPath, digestName, digestValue) {
455
- if (!digestValue || !digestName) return;
456
- const fixityBlock = this.fixity = this.fixity || {};
457
- const digestBlock = fixityBlock[digestName] = fixityBlock[digestName] || {};
458
- if (digestBlock[digestValue]) {
459
- if (!digestBlock[digestValue].includes(contentPath)) {
460
- digestBlock[digestValue].push(contentPath);
461
- }
462
- } else {
463
- digestBlock[digestValue] = [contentPath];
464
- }
465
- }
466
-
467
- /**
468
- * Rename a logical path. This will overwrite dest if exists
469
- * @param {string} srcLogicalPath
470
- * @param {string} destLogicalPath
471
- */
472
- rename(srcLogicalPath, destLogicalPath) {
473
- let srcPrefix = srcLogicalPath.endsWith('/') ? srcLogicalPath : srcLogicalPath + '/';
474
- let destPrefix = destLogicalPath.endsWith('/') ? destLogicalPath : destLogicalPath + '/';
475
- let srcList = this._indexFindPaths(srcPrefix);
476
- let pairs = srcList.map(src => [src, destPrefix + src.slice(srcPrefix.length)]);
477
- if (pairs.length === 0) pairs.push([srcLogicalPath, destLogicalPath]);
478
- for (let [src, dest] of pairs) {
479
- let digest = this.getDigest(src);
480
- let files = this.state[digest];
481
- let index = files?.indexOf(src);
482
- if (index >= 0) {
483
- this.delete(dest); //overwrite
484
- files[index] = dest;
485
- this._indexAdd(dest, this.head, this._indexRemove(src, this.head));
486
- } else {
487
- /** @todo decide: throw error or silently ignore non-existant file? */
488
- }
489
- }
490
- }
491
-
492
- /**
493
- * Create an alias or reference of a logical path
494
- * @param {string} srcLogicalPath
495
- * @param {string} destLogicalPath
496
- */
497
- copy(srcLogicalPath, destLogicalPath) {
498
- let srcPrefix = srcLogicalPath.endsWith('/') ? srcLogicalPath : srcLogicalPath + '/';
499
- let destPrefix = destLogicalPath.endsWith('/') ? destLogicalPath : destLogicalPath + '/';
500
- let srcList = this._indexFindPaths(srcPrefix);
501
- let pairs = srcList.map(src => [src, destPrefix + src.slice(srcPrefix.length)]);
502
- if (pairs.length === 0) pairs.push([srcLogicalPath, destLogicalPath]);
503
- for (let [src, dest] of pairs) {
504
- if (!dest) throw new Error(`Target logical path cannot be empty`);
505
- let digest = this._indexGet(src, this.head, true);
506
- if (!digest) throw new Error(`Source logical path "${src}" does not exist in object [${this.id}]`);
507
- //console.log(this.state);
508
- let files = this.state[digest[this.digestAlgorithm]];
509
- let index = files?.indexOf(dest);
510
- if (index >= 0) {
511
- /** @todo decide: throw error or silently ignore existing dest file? */
512
- } else {
513
- files.push(dest);
514
- this._indexAdd(dest, this.head, digest);
515
- }
516
- }
517
- }
518
-
519
- /**
520
- * Delete a file
521
- * @param {string} logicalPath
522
- * @param {string} [version]
523
- */
524
- delete(logicalPath, version = this.head) {
525
- const names = this._indexFindPaths(logicalPath, version);
526
- let count = 0;
527
- const state = this.versionState(version);
528
- for (let lp of names) {
529
- const digest = this.getDigest(lp, version);
530
- const files = state[digest];
531
- const index = files?.indexOf(lp);
532
- if (index >= 0) {
533
- if (files.length === 1) {
534
- delete state[digest];
535
- } else {
536
- files.splice(index, 1);
537
- }
538
- this._indexRemove(lp, version);
539
- count++;
540
- }
541
- }
542
- return count;
543
- }
544
-
545
- reinstate(logicalPath, versionName) {
546
- let names = this._indexFindPaths(logicalPath, versionName);
547
- //let digest = this.getDigest(logicalPath, versionName);
548
- let state = this.state;
549
- let count = 0;
550
- for (let lp of names) {
551
- const digests = this._indexGet(lp, versionName);
552
- if (digests) {
553
- let c = this.delete(lp);
554
- }
555
- state[digests[this.digestAlgorithm]] = [lp];
556
- this._indexAdd(lp, this.head, digests);
557
- count++;
558
- }
559
- return count;
560
- }
561
-
562
- }
563
-
564
- module.exports = { OcflObjectInventory, OcflObjectInventoryMut, VersionNumber };