@atlaspack/build-cache 2.13.3-canary.48 → 2.13.3-canary.481
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 +57 -0
- package/dist/LargeMap.js +59 -0
- package/dist/buildCache.js +15 -0
- package/dist/index.js +19 -0
- package/dist/serializer.js +222 -0
- package/dist/serializerCore.js +9 -0
- package/lib/LargeMap.js +63 -0
- package/lib/serializer.js +16 -2
- package/lib/types/LargeMap.d.ts +19 -0
- package/lib/types/buildCache.d.ts +2 -0
- package/{src/index.js → lib/types/index.d.ts} +0 -2
- package/lib/types/serializer.d.ts +11 -0
- package/lib/types/serializerCore.d.ts +2 -0
- package/package.json +12 -5
- package/src/LargeMap.ts +67 -0
- package/src/{buildCache.js → buildCache.ts} +0 -2
- package/src/index.ts +3 -0
- package/src/{serializer.js → serializer.ts} +27 -9
- package/src/serializerCore.ts +4 -0
- package/test/LargeMap.test.ts +151 -0
- package/test/{serializer.test.js → serializer.test.ts} +6 -8
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/serializerCore.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# @atlaspack/build-cache
|
|
2
2
|
|
|
3
|
+
## 2.13.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`1815c2c`](https://github.com/atlassian-labs/atlaspack/commit/1815c2ce48e32f4df97ccdd668fd650fc79d1051)]:
|
|
8
|
+
- @atlaspack/feature-flags@2.29.1
|
|
9
|
+
|
|
10
|
+
## 2.13.10
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [[`349b19c`](https://github.com/atlassian-labs/atlaspack/commit/349b19c3aca2ccb1ffb5cdcdc74890f4b62228be)]:
|
|
15
|
+
- @atlaspack/feature-flags@2.29.0
|
|
16
|
+
|
|
17
|
+
## 2.13.9
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [[`8826fd0`](https://github.com/atlassian-labs/atlaspack/commit/8826fd02c29c9c67cf0c80da41f424257fbdef93)]:
|
|
22
|
+
- @atlaspack/feature-flags@2.28.0
|
|
23
|
+
|
|
24
|
+
## 2.13.8
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [[`f33f9c4`](https://github.com/atlassian-labs/atlaspack/commit/f33f9c48dd24b319df352d197e4a83cbb1b053bc), [`e15fb6c`](https://github.com/atlassian-labs/atlaspack/commit/e15fb6c885c6354c6c02283de35ce18abc8c9e18)]:
|
|
29
|
+
- @atlaspack/feature-flags@2.27.7
|
|
30
|
+
|
|
31
|
+
## 2.13.7
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- [#960](https://github.com/atlassian-labs/atlaspack/pull/960) [`565bab3`](https://github.com/atlassian-labs/atlaspack/commit/565bab3771cc334659d873cabff4cdfac0860cc7) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Add LargeMap to work around Node 24's Map size limit in build cache serializer.
|
|
36
|
+
|
|
37
|
+
This change is behind the `useLargeMapInBuildCache` feature flag.
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [[`c31090c`](https://github.com/atlassian-labs/atlaspack/commit/c31090c9025f35d3fa8561b42dca170853a32e6f), [`565bab3`](https://github.com/atlassian-labs/atlaspack/commit/565bab3771cc334659d873cabff4cdfac0860cc7)]:
|
|
40
|
+
- @atlaspack/feature-flags@2.27.6
|
|
41
|
+
|
|
42
|
+
## 2.13.6
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- [#785](https://github.com/atlassian-labs/atlaspack/pull/785) [`0e7dd5e`](https://github.com/atlassian-labs/atlaspack/commit/0e7dd5ec6fbe05aa9e0bb5775a9d0975f206a922) Thanks [@matt-koko](https://github.com/matt-koko)! - We need to re-publish every package in Atlaspack with the corrected types field.
|
|
47
|
+
|
|
48
|
+
## 2.13.5
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- [#742](https://github.com/atlassian-labs/atlaspack/pull/742) [`ee040bb`](https://github.com/atlassian-labs/atlaspack/commit/ee040bb6428f29b57d892ddd8107e29077d08ffd) Thanks [@yamadapc](https://github.com/yamadapc)! - Internal changes and bug fixes to environmentDeduplication flag
|
|
53
|
+
|
|
54
|
+
## 2.13.4
|
|
55
|
+
|
|
56
|
+
### Patch Changes
|
|
57
|
+
|
|
58
|
+
- [#720](https://github.com/atlassian-labs/atlaspack/pull/720) [`d2fd849`](https://github.com/atlassian-labs/atlaspack/commit/d2fd849770fe6305e9c694bd97b1bd905abd9d94) Thanks [@alshdavid](https://github.com/alshdavid)! - Migrate to TypeScript
|
|
59
|
+
|
|
3
60
|
## 2.13.3
|
|
4
61
|
|
|
5
62
|
### Patch Changes
|
package/dist/LargeMap.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LargeMap = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A Map implementation that can exceed Node 24's Map size limit.
|
|
6
|
+
*
|
|
7
|
+
* LargeMap works around the Maximum maps size limit by using multiple internal Maps,
|
|
8
|
+
* creating a new one when the current Map reaches the size limit.
|
|
9
|
+
*
|
|
10
|
+
* This is a minimal implementation supporting only has/get/set - intended as a
|
|
11
|
+
* temporary solution until we no longer need large JS serialization
|
|
12
|
+
*/
|
|
13
|
+
class LargeMap {
|
|
14
|
+
constructor(maxSize = Math.pow(2, 23)) {
|
|
15
|
+
this.lastMap = new Map();
|
|
16
|
+
this.maps = [this.lastMap];
|
|
17
|
+
this.singleMap = true;
|
|
18
|
+
this.maxSize = maxSize;
|
|
19
|
+
}
|
|
20
|
+
set(key, value) {
|
|
21
|
+
// Update existing key if found
|
|
22
|
+
if (!this.singleMap) {
|
|
23
|
+
for (let map of this.maps) {
|
|
24
|
+
if (map.has(key)) {
|
|
25
|
+
map.set(key, value);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Otherwise, add to last map
|
|
31
|
+
if (this.lastMap.size >= this.maxSize) {
|
|
32
|
+
this.lastMap = new Map();
|
|
33
|
+
this.maps.push(this.lastMap);
|
|
34
|
+
this.singleMap = false;
|
|
35
|
+
}
|
|
36
|
+
this.lastMap.set(key, value);
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
get(key) {
|
|
40
|
+
if (this.singleMap) {
|
|
41
|
+
return this.lastMap.get(key);
|
|
42
|
+
}
|
|
43
|
+
for (let map of this.maps) {
|
|
44
|
+
if (map.has(key)) {
|
|
45
|
+
return map.get(key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
has(key) {
|
|
51
|
+
for (let map of this.maps) {
|
|
52
|
+
if (map.has(key)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.LargeMap = LargeMap;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBuildCache = createBuildCache;
|
|
4
|
+
exports.clearBuildCaches = clearBuildCaches;
|
|
5
|
+
const buildCaches = [];
|
|
6
|
+
function createBuildCache() {
|
|
7
|
+
let cache = new Map();
|
|
8
|
+
buildCaches.push(cache);
|
|
9
|
+
return cache;
|
|
10
|
+
}
|
|
11
|
+
function clearBuildCaches() {
|
|
12
|
+
for (let cache of buildCaches) {
|
|
13
|
+
cache.clear();
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./buildCache"), exports);
|
|
18
|
+
__exportStar(require("./serializer"), exports);
|
|
19
|
+
__exportStar(require("./serializerCore"), exports);
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deserializeRaw = exports.serializeRaw = void 0;
|
|
4
|
+
exports.registerSerializableClass = registerSerializableClass;
|
|
5
|
+
exports.unregisterSerializableClass = unregisterSerializableClass;
|
|
6
|
+
exports.prepareForSerialization = prepareForSerialization;
|
|
7
|
+
exports.restoreDeserializedObject = restoreDeserializedObject;
|
|
8
|
+
exports.serialize = serialize;
|
|
9
|
+
exports.deserialize = deserialize;
|
|
10
|
+
exports.cacheSerializedObject = cacheSerializedObject;
|
|
11
|
+
exports.deserializeToCache = deserializeToCache;
|
|
12
|
+
exports.removeSerializedObjectFromCache = removeSerializedObjectFromCache;
|
|
13
|
+
const feature_flags_1 = require("@atlaspack/feature-flags");
|
|
14
|
+
const buildCache_1 = require("./buildCache");
|
|
15
|
+
const LargeMap_1 = require("./LargeMap");
|
|
16
|
+
const serializerCore_1 = require("./serializerCore");
|
|
17
|
+
var serializerCore_2 = require("./serializerCore");
|
|
18
|
+
Object.defineProperty(exports, "serializeRaw", { enumerable: true, get: function () { return serializerCore_2.serializeRaw; } });
|
|
19
|
+
Object.defineProperty(exports, "deserializeRaw", { enumerable: true, get: function () { return serializerCore_2.deserializeRaw; } });
|
|
20
|
+
// /flow-to-ts helpers
|
|
21
|
+
const nameToCtor = new Map();
|
|
22
|
+
const ctorToName = new Map();
|
|
23
|
+
function registerSerializableClass(name, ctor) {
|
|
24
|
+
if (ctorToName.has(ctor)) {
|
|
25
|
+
throw new Error('Class already registered with serializer');
|
|
26
|
+
}
|
|
27
|
+
nameToCtor.set(name, ctor);
|
|
28
|
+
ctorToName.set(ctor, name);
|
|
29
|
+
}
|
|
30
|
+
function unregisterSerializableClass(name, ctor) {
|
|
31
|
+
if (nameToCtor.get(name) === ctor) {
|
|
32
|
+
nameToCtor.delete(name);
|
|
33
|
+
}
|
|
34
|
+
if (ctorToName.get(ctor) === name) {
|
|
35
|
+
ctorToName.delete(ctor);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function shallowCopy(object) {
|
|
39
|
+
if (object && typeof object === 'object') {
|
|
40
|
+
if (Array.isArray(object)) {
|
|
41
|
+
return [...object];
|
|
42
|
+
}
|
|
43
|
+
if (object instanceof Map) {
|
|
44
|
+
return new Map(object);
|
|
45
|
+
}
|
|
46
|
+
if (object instanceof Set) {
|
|
47
|
+
return new Set(object);
|
|
48
|
+
}
|
|
49
|
+
return Object.create(Object.getPrototypeOf(object), Object.getOwnPropertyDescriptors(object));
|
|
50
|
+
}
|
|
51
|
+
return object;
|
|
52
|
+
}
|
|
53
|
+
function isBuffer(object) {
|
|
54
|
+
return (object.buffer instanceof ArrayBuffer ||
|
|
55
|
+
(typeof SharedArrayBuffer !== 'undefined' &&
|
|
56
|
+
object.buffer instanceof SharedArrayBuffer));
|
|
57
|
+
}
|
|
58
|
+
function shouldContinueMapping(value) {
|
|
59
|
+
return value && typeof value === 'object' && value.$$raw !== true;
|
|
60
|
+
}
|
|
61
|
+
function mapObject(object, fn, preOrder = false) {
|
|
62
|
+
// Use LargeMap to work around Node 24's Map size limit
|
|
63
|
+
// when the feature flag is enabled
|
|
64
|
+
let cache = (0, feature_flags_1.getFeatureFlag)('useLargeMapInBuildCache')
|
|
65
|
+
? new LargeMap_1.LargeMap()
|
|
66
|
+
: new Map();
|
|
67
|
+
let memo = (0, feature_flags_1.getFeatureFlag)('useLargeMapInBuildCache')
|
|
68
|
+
? new LargeMap_1.LargeMap()
|
|
69
|
+
: new Map();
|
|
70
|
+
// Memoize the passed function to ensure it always returns the exact same
|
|
71
|
+
// output by reference for the same input. This is important to maintain
|
|
72
|
+
// reference integrity when deserializing rather than cloning.
|
|
73
|
+
let memoizedFn = (val) => {
|
|
74
|
+
let res = memo.get(val);
|
|
75
|
+
if (res == null) {
|
|
76
|
+
res = fn(val);
|
|
77
|
+
memo.set(val, res);
|
|
78
|
+
}
|
|
79
|
+
return res;
|
|
80
|
+
};
|
|
81
|
+
let walk = (object, shouldCopy = false) => {
|
|
82
|
+
// Check the cache first, both for performance and cycle detection.
|
|
83
|
+
if (cache.has(object)) {
|
|
84
|
+
return cache.get(object);
|
|
85
|
+
}
|
|
86
|
+
let result = object;
|
|
87
|
+
cache.set(object, result);
|
|
88
|
+
let processKey = (key, value) => {
|
|
89
|
+
let newValue = value;
|
|
90
|
+
if (preOrder && value && typeof value === 'object') {
|
|
91
|
+
newValue = memoizedFn(value);
|
|
92
|
+
}
|
|
93
|
+
// Recursively walk the children
|
|
94
|
+
if (preOrder
|
|
95
|
+
? shouldContinueMapping(newValue)
|
|
96
|
+
: newValue &&
|
|
97
|
+
typeof newValue === 'object' &&
|
|
98
|
+
shouldContinueMapping(object)) {
|
|
99
|
+
newValue = walk(newValue, newValue === value);
|
|
100
|
+
}
|
|
101
|
+
if (!preOrder && newValue && typeof newValue === 'object') {
|
|
102
|
+
newValue = memoizedFn(newValue);
|
|
103
|
+
}
|
|
104
|
+
if (newValue !== value) {
|
|
105
|
+
// Copy on write. We only need to do this when serializing, not deserializing.
|
|
106
|
+
if (object === result && preOrder && shouldCopy) {
|
|
107
|
+
result = shallowCopy(object);
|
|
108
|
+
cache.set(object, result);
|
|
109
|
+
}
|
|
110
|
+
// Replace the key with the new value
|
|
111
|
+
if (result instanceof Map) {
|
|
112
|
+
result.set(key, newValue);
|
|
113
|
+
}
|
|
114
|
+
else if (result instanceof Set) {
|
|
115
|
+
let _result = result; // For Flow
|
|
116
|
+
// TODO: do we care about iteration order??
|
|
117
|
+
_result.delete(value);
|
|
118
|
+
_result.add(newValue);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
result[key] = newValue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
// Iterate in various ways depending on type.
|
|
126
|
+
if (Array.isArray(object)) {
|
|
127
|
+
for (let i = 0; i < object.length; i++) {
|
|
128
|
+
processKey(i, object[i]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (object instanceof Map || object instanceof Set) {
|
|
132
|
+
for (let [key, val] of object.entries()) {
|
|
133
|
+
processKey(key, val);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (!isBuffer(object)) {
|
|
137
|
+
for (let key in object) {
|
|
138
|
+
processKey(key, object[key]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
let mapped = memoizedFn(object);
|
|
144
|
+
if (preOrder
|
|
145
|
+
? shouldContinueMapping(mapped)
|
|
146
|
+
: mapped && typeof mapped === 'object' && shouldContinueMapping(object)) {
|
|
147
|
+
return walk(mapped, mapped === object);
|
|
148
|
+
}
|
|
149
|
+
return mapped;
|
|
150
|
+
}
|
|
151
|
+
function prepareForSerialization(object) {
|
|
152
|
+
if (object?.$$raw) {
|
|
153
|
+
return object;
|
|
154
|
+
}
|
|
155
|
+
return mapObject(object, (value) => {
|
|
156
|
+
// Add a $$type property with the name of this class, if any is registered.
|
|
157
|
+
if (value &&
|
|
158
|
+
typeof value === 'object' &&
|
|
159
|
+
typeof value.constructor === 'function') {
|
|
160
|
+
let type = ctorToName.get(value.constructor);
|
|
161
|
+
if (type != null) {
|
|
162
|
+
let serialized = value;
|
|
163
|
+
let raw = false;
|
|
164
|
+
if (value && typeof value.serialize === 'function') {
|
|
165
|
+
// If the object has a serialize method, call it
|
|
166
|
+
serialized = value.serialize();
|
|
167
|
+
raw = (serialized && serialized.$$raw) ?? true;
|
|
168
|
+
if (serialized) {
|
|
169
|
+
delete serialized.$$raw;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
$$type: type,
|
|
174
|
+
$$raw: raw,
|
|
175
|
+
value: { ...serialized },
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return value;
|
|
180
|
+
}, true);
|
|
181
|
+
}
|
|
182
|
+
function restoreDeserializedObject(object) {
|
|
183
|
+
return mapObject(object, (value) => {
|
|
184
|
+
// If the value has a $$type property, use it to restore the object type
|
|
185
|
+
if (value && value.$$type) {
|
|
186
|
+
let ctor = nameToCtor.get(value.$$type);
|
|
187
|
+
if (ctor == null) {
|
|
188
|
+
throw new Error(`Expected constructor ${value.$$type} to be registered with serializer to deserialize`);
|
|
189
|
+
}
|
|
190
|
+
if (typeof ctor.deserialize === 'function') {
|
|
191
|
+
return ctor.deserialize(value.value);
|
|
192
|
+
}
|
|
193
|
+
value = value.value;
|
|
194
|
+
Object.setPrototypeOf(value, ctor.prototype);
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const serializeCache = (0, buildCache_1.createBuildCache)();
|
|
200
|
+
function serialize(object) {
|
|
201
|
+
let cached = serializeCache.get(object);
|
|
202
|
+
if (cached) {
|
|
203
|
+
return cached;
|
|
204
|
+
}
|
|
205
|
+
let mapped = prepareForSerialization(object);
|
|
206
|
+
return (0, serializerCore_1.serializeRaw)(mapped);
|
|
207
|
+
}
|
|
208
|
+
function deserialize(buffer) {
|
|
209
|
+
let obj = (0, serializerCore_1.deserializeRaw)(buffer);
|
|
210
|
+
return restoreDeserializedObject(obj);
|
|
211
|
+
}
|
|
212
|
+
function cacheSerializedObject(object, buffer) {
|
|
213
|
+
serializeCache.set(object, buffer || serialize(object));
|
|
214
|
+
}
|
|
215
|
+
function deserializeToCache(buffer) {
|
|
216
|
+
let deserialized = deserialize(buffer);
|
|
217
|
+
serializeCache.set(deserialized, buffer);
|
|
218
|
+
return deserialized;
|
|
219
|
+
}
|
|
220
|
+
function removeSerializedObjectFromCache(object) {
|
|
221
|
+
serializeCache.delete(object);
|
|
222
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.deserializeRaw = exports.serializeRaw = void 0;
|
|
7
|
+
const v8_1 = __importDefault(require("v8"));
|
|
8
|
+
exports.serializeRaw = v8_1.default.serialize;
|
|
9
|
+
exports.deserializeRaw = v8_1.default.deserialize;
|
package/lib/LargeMap.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.LargeMap = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* A Map implementation that can exceed Node 24's Map size limit.
|
|
9
|
+
*
|
|
10
|
+
* LargeMap works around the Maximum maps size limit by using multiple internal Maps,
|
|
11
|
+
* creating a new one when the current Map reaches the size limit.
|
|
12
|
+
*
|
|
13
|
+
* This is a minimal implementation supporting only has/get/set - intended as a
|
|
14
|
+
* temporary solution until we no longer need large JS serialization
|
|
15
|
+
*/
|
|
16
|
+
class LargeMap {
|
|
17
|
+
constructor(maxSize = Math.pow(2, 23)) {
|
|
18
|
+
this.lastMap = new Map();
|
|
19
|
+
this.maps = [this.lastMap];
|
|
20
|
+
this.singleMap = true;
|
|
21
|
+
this.maxSize = maxSize;
|
|
22
|
+
}
|
|
23
|
+
set(key, value) {
|
|
24
|
+
// Update existing key if found
|
|
25
|
+
if (!this.singleMap) {
|
|
26
|
+
for (let map of this.maps) {
|
|
27
|
+
if (map.has(key)) {
|
|
28
|
+
map.set(key, value);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Otherwise, add to last map
|
|
35
|
+
if (this.lastMap.size >= this.maxSize) {
|
|
36
|
+
this.lastMap = new Map();
|
|
37
|
+
this.maps.push(this.lastMap);
|
|
38
|
+
this.singleMap = false;
|
|
39
|
+
}
|
|
40
|
+
this.lastMap.set(key, value);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
get(key) {
|
|
44
|
+
if (this.singleMap) {
|
|
45
|
+
return this.lastMap.get(key);
|
|
46
|
+
}
|
|
47
|
+
for (let map of this.maps) {
|
|
48
|
+
if (map.has(key)) {
|
|
49
|
+
return map.get(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
has(key) {
|
|
55
|
+
for (let map of this.maps) {
|
|
56
|
+
if (map.has(key)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.LargeMap = LargeMap;
|
package/lib/serializer.js
CHANGED
|
@@ -24,8 +24,20 @@ Object.defineProperty(exports, "serializeRaw", {
|
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
exports.unregisterSerializableClass = unregisterSerializableClass;
|
|
27
|
+
function _featureFlags() {
|
|
28
|
+
const data = require("@atlaspack/feature-flags");
|
|
29
|
+
_featureFlags = function () {
|
|
30
|
+
return data;
|
|
31
|
+
};
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
27
34
|
var _buildCache = require("./buildCache");
|
|
35
|
+
var _LargeMap = require("./LargeMap");
|
|
28
36
|
var _serializerCore = require("./serializerCore");
|
|
37
|
+
// flow-to-ts helpers
|
|
38
|
+
|
|
39
|
+
// /flow-to-ts helpers
|
|
40
|
+
|
|
29
41
|
const nameToCtor = new Map();
|
|
30
42
|
const ctorToName = new Map();
|
|
31
43
|
function registerSerializableClass(name, ctor) {
|
|
@@ -65,8 +77,10 @@ function shouldContinueMapping(value) {
|
|
|
65
77
|
return value && typeof value === 'object' && value.$$raw !== true;
|
|
66
78
|
}
|
|
67
79
|
function mapObject(object, fn, preOrder = false) {
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
// Use LargeMap to work around Node 24's Map size limit
|
|
81
|
+
// when the feature flag is enabled
|
|
82
|
+
let cache = (0, _featureFlags().getFeatureFlag)('useLargeMapInBuildCache') ? new _LargeMap.LargeMap() : new Map();
|
|
83
|
+
let memo = (0, _featureFlags().getFeatureFlag)('useLargeMapInBuildCache') ? new _LargeMap.LargeMap() : new Map();
|
|
70
84
|
|
|
71
85
|
// Memoize the passed function to ensure it always returns the exact same
|
|
72
86
|
// output by reference for the same input. This is important to maintain
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Map implementation that can exceed Node 24's Map size limit.
|
|
3
|
+
*
|
|
4
|
+
* LargeMap works around the Maximum maps size limit by using multiple internal Maps,
|
|
5
|
+
* creating a new one when the current Map reaches the size limit.
|
|
6
|
+
*
|
|
7
|
+
* This is a minimal implementation supporting only has/get/set - intended as a
|
|
8
|
+
* temporary solution until we no longer need large JS serialization
|
|
9
|
+
*/
|
|
10
|
+
export declare class LargeMap<K, V> {
|
|
11
|
+
maps: Map<K, V>[];
|
|
12
|
+
maxSize: number;
|
|
13
|
+
singleMap: boolean;
|
|
14
|
+
lastMap: Map<K, V>;
|
|
15
|
+
constructor(maxSize?: number);
|
|
16
|
+
set(key: K, value: V): this;
|
|
17
|
+
get(key: K): V | undefined;
|
|
18
|
+
has(key: K): boolean;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { serializeRaw, deserializeRaw } from './serializerCore';
|
|
2
|
+
export type Class<T> = new (...args: any[]) => T;
|
|
3
|
+
export declare function registerSerializableClass(name: string, ctor: Class<any>): void;
|
|
4
|
+
export declare function unregisterSerializableClass(name: string, ctor: Class<any>): void;
|
|
5
|
+
export declare function prepareForSerialization(object: any): any;
|
|
6
|
+
export declare function restoreDeserializedObject(object: any): any;
|
|
7
|
+
export declare function serialize(object: any): Buffer;
|
|
8
|
+
export declare function deserialize(buffer: Buffer): any;
|
|
9
|
+
export declare function cacheSerializedObject(object: any, buffer?: Buffer): void;
|
|
10
|
+
export declare function deserializeToCache(buffer: Buffer): any;
|
|
11
|
+
export declare function removeSerializedObjectFromCache(object: any): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/build-cache",
|
|
3
3
|
"description": "Serialize and deserialize data structures to a build cache",
|
|
4
|
-
"version": "2.13.3-canary.
|
|
4
|
+
"version": "2.13.3-canary.481+221f28644",
|
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"publishConfig": {
|
|
@@ -11,10 +11,17 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/atlassian-labs/atlaspack.git"
|
|
13
13
|
},
|
|
14
|
-
"main": "lib/index.js",
|
|
15
|
-
"source": "src/index.
|
|
14
|
+
"main": "./lib/index.js",
|
|
15
|
+
"source": "./src/index.ts",
|
|
16
|
+
"types": "./lib/types/index.d.ts",
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": ">= 16.0.0"
|
|
18
19
|
},
|
|
19
|
-
"
|
|
20
|
-
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build:lib": "gulp build --gulpfile ../../../gulpfile.js --cwd ."
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@atlaspack/feature-flags": "2.14.1-canary.481+221f28644"
|
|
25
|
+
},
|
|
26
|
+
"gitHead": "221f28644f5b2314645595facac076b49503345d"
|
|
27
|
+
}
|
package/src/LargeMap.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Map implementation that can exceed Node 24's Map size limit.
|
|
3
|
+
*
|
|
4
|
+
* LargeMap works around the Maximum maps size limit by using multiple internal Maps,
|
|
5
|
+
* creating a new one when the current Map reaches the size limit.
|
|
6
|
+
*
|
|
7
|
+
* This is a minimal implementation supporting only has/get/set - intended as a
|
|
8
|
+
* temporary solution until we no longer need large JS serialization
|
|
9
|
+
*/
|
|
10
|
+
export class LargeMap<K, V> {
|
|
11
|
+
maps: Map<K, V>[];
|
|
12
|
+
maxSize: number;
|
|
13
|
+
singleMap: boolean;
|
|
14
|
+
lastMap: Map<K, V>;
|
|
15
|
+
|
|
16
|
+
constructor(maxSize: number = Math.pow(2, 23)) {
|
|
17
|
+
this.lastMap = new Map();
|
|
18
|
+
this.maps = [this.lastMap];
|
|
19
|
+
this.singleMap = true;
|
|
20
|
+
this.maxSize = maxSize;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
set(key: K, value: V): this {
|
|
24
|
+
// Update existing key if found
|
|
25
|
+
if (!this.singleMap) {
|
|
26
|
+
for (let map of this.maps) {
|
|
27
|
+
if (map.has(key)) {
|
|
28
|
+
map.set(key, value);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Otherwise, add to last map
|
|
35
|
+
if (this.lastMap.size >= this.maxSize) {
|
|
36
|
+
this.lastMap = new Map();
|
|
37
|
+
this.maps.push(this.lastMap);
|
|
38
|
+
this.singleMap = false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.lastMap.set(key, value);
|
|
42
|
+
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get(key: K): V | undefined {
|
|
47
|
+
if (this.singleMap) {
|
|
48
|
+
return this.lastMap.get(key);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (let map of this.maps) {
|
|
52
|
+
if (map.has(key)) {
|
|
53
|
+
return map.get(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
has(key: K): boolean {
|
|
60
|
+
for (let map of this.maps) {
|
|
61
|
+
if (map.has(key)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/index.ts
ADDED