@fluidframework/core-utils 2.20.0 → 2.21.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 +4 -0
- package/dist/assert.d.ts +68 -2
- package/dist/assert.d.ts.map +1 -1
- package/dist/assert.js +121 -3
- package/dist/assert.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/shallowClone.d.ts +13 -0
- package/dist/shallowClone.d.ts.map +1 -0
- package/dist/shallowClone.js +22 -0
- package/dist/shallowClone.js.map +1 -0
- package/lib/assert.d.ts +68 -2
- package/lib/assert.d.ts.map +1 -1
- package/lib/assert.js +117 -2
- package/lib/assert.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/shallowClone.d.ts +13 -0
- package/lib/shallowClone.d.ts.map +1 -0
- package/lib/shallowClone.js +18 -0
- package/lib/shallowClone.js.map +1 -0
- package/package.json +5 -5
- package/src/assert.ts +126 -2
- package/src/index.ts +7 -1
- package/src/shallowClone.ts +18 -0
package/CHANGELOG.md
CHANGED
package/dist/assert.d.ts
CHANGED
|
@@ -3,16 +3,82 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Asserts the specified condition.
|
|
7
|
+
*
|
|
8
8
|
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
|
9
9
|
* Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.
|
|
10
10
|
* @param message - The message to include in the error when the condition does not hold.
|
|
11
11
|
* A number should not be specified manually: use a string.
|
|
12
12
|
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
|
13
13
|
* use numbered error codes instead.
|
|
14
|
+
* @remarks
|
|
15
|
+
* Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.
|
|
16
|
+
*
|
|
17
|
+
* Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.
|
|
18
|
+
* Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.
|
|
19
|
+
* It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.
|
|
20
|
+
*
|
|
21
|
+
* In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead
|
|
22
|
+
* to optimize bundle size.
|
|
23
|
+
*
|
|
24
|
+
* This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.
|
|
25
|
+
* @privateRemarks
|
|
26
|
+
* This should be deprecated (as a non internal API) then moved to purely internal.
|
|
27
|
+
* When done the `debugAssert` reference above should be turned into a link.
|
|
14
28
|
* @legacy
|
|
15
29
|
* @alpha
|
|
16
30
|
*/
|
|
17
31
|
export declare function assert(condition: boolean, message: string | number): asserts condition;
|
|
32
|
+
/**
|
|
33
|
+
* Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.
|
|
34
|
+
*
|
|
35
|
+
* Disabled by default.
|
|
36
|
+
*
|
|
37
|
+
* If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.
|
|
38
|
+
*
|
|
39
|
+
* @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.
|
|
40
|
+
* This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.
|
|
41
|
+
* @remarks
|
|
42
|
+
* Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.
|
|
43
|
+
*
|
|
44
|
+
* Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.
|
|
45
|
+
* The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.
|
|
46
|
+
*
|
|
47
|
+
* These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.
|
|
48
|
+
* Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.
|
|
49
|
+
* These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.
|
|
50
|
+
*
|
|
51
|
+
* @privateRemarks
|
|
52
|
+
* This design was chosen to accomplish two main goals:
|
|
53
|
+
*
|
|
54
|
+
* 1. Make it easy to compile debug asserts fully out of production builds.
|
|
55
|
+
* For webpack this happens by default, avoiding the need for customers to do special configuration.
|
|
56
|
+
* This is important for both performance and bundle size.
|
|
57
|
+
*
|
|
58
|
+
* 2. Make it easy to test (both manually and automated) with and without the predicates running.
|
|
59
|
+
* This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.
|
|
60
|
+
*
|
|
61
|
+
* The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export declare function debugAssert(predicate: () => true | {
|
|
65
|
+
toString(): string;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* Enables {@link debugAssert} validation.
|
|
69
|
+
* @remarks
|
|
70
|
+
* Throws if debugAsserts have been optimized out.
|
|
71
|
+
* @returns The previous state of debugAsserts.
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export declare function configureDebugAsserts(enabled: boolean): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if non-production conditional code like {@link debugAssert} is included in this build.
|
|
77
|
+
* @remarks
|
|
78
|
+
* Such code can be optimized out by bundlers: this checks if that has occurred.
|
|
79
|
+
* @privateRemarks
|
|
80
|
+
* See {@link skipInProduction}.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
export declare function nonProductionConditionalsIncluded(): boolean;
|
|
18
84
|
//# sourceMappingURL=assert.d.ts.map
|
package/dist/assert.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,CAMtF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,IAAI,GAAG;IAAE,QAAQ,IAAI,MAAM,CAAA;CAAE,GAAG,IAAI,CAahF;AAID;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ/D;AAED;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,IAAI,OAAO,CAM3D"}
|
package/dist/assert.js
CHANGED
|
@@ -4,16 +4,30 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.assert = void 0;
|
|
7
|
+
exports.nonProductionConditionalsIncluded = exports.configureDebugAsserts = exports.debugAssert = exports.assert = void 0;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Asserts the specified condition.
|
|
10
|
+
*
|
|
11
11
|
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
|
12
12
|
* Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.
|
|
13
13
|
* @param message - The message to include in the error when the condition does not hold.
|
|
14
14
|
* A number should not be specified manually: use a string.
|
|
15
15
|
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
|
16
16
|
* use numbered error codes instead.
|
|
17
|
+
* @remarks
|
|
18
|
+
* Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.
|
|
19
|
+
*
|
|
20
|
+
* Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.
|
|
21
|
+
* Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.
|
|
22
|
+
* It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.
|
|
23
|
+
*
|
|
24
|
+
* In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead
|
|
25
|
+
* to optimize bundle size.
|
|
26
|
+
*
|
|
27
|
+
* This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.
|
|
28
|
+
* @privateRemarks
|
|
29
|
+
* This should be deprecated (as a non internal API) then moved to purely internal.
|
|
30
|
+
* When done the `debugAssert` reference above should be turned into a link.
|
|
17
31
|
* @legacy
|
|
18
32
|
* @alpha
|
|
19
33
|
*/
|
|
@@ -23,4 +37,108 @@ function assert(condition, message) {
|
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
39
|
exports.assert = assert;
|
|
40
|
+
/**
|
|
41
|
+
* Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.
|
|
42
|
+
*
|
|
43
|
+
* Disabled by default.
|
|
44
|
+
*
|
|
45
|
+
* If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.
|
|
46
|
+
*
|
|
47
|
+
* @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.
|
|
48
|
+
* This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.
|
|
49
|
+
* @remarks
|
|
50
|
+
* Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.
|
|
51
|
+
*
|
|
52
|
+
* Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.
|
|
53
|
+
* The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.
|
|
54
|
+
*
|
|
55
|
+
* These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.
|
|
56
|
+
* Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.
|
|
57
|
+
* These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.
|
|
58
|
+
*
|
|
59
|
+
* @privateRemarks
|
|
60
|
+
* This design was chosen to accomplish two main goals:
|
|
61
|
+
*
|
|
62
|
+
* 1. Make it easy to compile debug asserts fully out of production builds.
|
|
63
|
+
* For webpack this happens by default, avoiding the need for customers to do special configuration.
|
|
64
|
+
* This is important for both performance and bundle size.
|
|
65
|
+
*
|
|
66
|
+
* 2. Make it easy to test (both manually and automated) with and without the predicates running.
|
|
67
|
+
* This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.
|
|
68
|
+
*
|
|
69
|
+
* The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
function debugAssert(predicate) {
|
|
73
|
+
// This is valid since the contract for this function is that "predicate" should be side effect free and never return non true in production scenarios:
|
|
74
|
+
// it returning non-true indicates a bug is present, and that the validation it does to detect the bug is only desired in specific test/debug situations.
|
|
75
|
+
// Production scenarios, where pure code is removed, should never hit a failing predicate, and thus this code should be side effect free.
|
|
76
|
+
skipInProduction(() => {
|
|
77
|
+
if (debugAssertsEnabled) {
|
|
78
|
+
const result = predicate();
|
|
79
|
+
if (result !== true) {
|
|
80
|
+
debugger;
|
|
81
|
+
throw new Error(`Debug assert failed: ${result.toString()}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
exports.debugAssert = debugAssert;
|
|
87
|
+
let debugAssertsEnabled = false;
|
|
88
|
+
/**
|
|
89
|
+
* Enables {@link debugAssert} validation.
|
|
90
|
+
* @remarks
|
|
91
|
+
* Throws if debugAsserts have been optimized out.
|
|
92
|
+
* @returns The previous state of debugAsserts.
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
function configureDebugAsserts(enabled) {
|
|
96
|
+
assert(nonProductionConditionalsIncluded(), 0xab1 /* Debug asserts cannot be configured since they have been optimized out. */);
|
|
97
|
+
const old = debugAssertsEnabled;
|
|
98
|
+
debugAssertsEnabled = enabled;
|
|
99
|
+
return old;
|
|
100
|
+
}
|
|
101
|
+
exports.configureDebugAsserts = configureDebugAsserts;
|
|
102
|
+
/**
|
|
103
|
+
* Checks if non-production conditional code like {@link debugAssert} is included in this build.
|
|
104
|
+
* @remarks
|
|
105
|
+
* Such code can be optimized out by bundlers: this checks if that has occurred.
|
|
106
|
+
* @privateRemarks
|
|
107
|
+
* See {@link skipInProduction}.
|
|
108
|
+
* @internal
|
|
109
|
+
*/
|
|
110
|
+
function nonProductionConditionalsIncluded() {
|
|
111
|
+
let included = false;
|
|
112
|
+
skipInProduction(() => {
|
|
113
|
+
included = true;
|
|
114
|
+
});
|
|
115
|
+
return included;
|
|
116
|
+
}
|
|
117
|
+
exports.nonProductionConditionalsIncluded = nonProductionConditionalsIncluded;
|
|
118
|
+
/**
|
|
119
|
+
* Run `conditional` only in debug/development (non optimized/minified) builds, but optimize it out of production builds.
|
|
120
|
+
*
|
|
121
|
+
* @param conditional - This function will only be run in some configurations so it should be pure (at least in production scenarios).
|
|
122
|
+
* It can be used to interact with debug only functionality that is also removed in production builds, or to do validation/testing/debugging that can be assumed to be sideeffect free in production where it might be removed.
|
|
123
|
+
* @remarks
|
|
124
|
+
* Great care must be taken when using this to ensure that bugs are not introduced which only occur when `conditional` is not run.
|
|
125
|
+
* One way to do this is to provide an alternative way to disable the effects of `conditional` in development builds so both configurations can be tested:
|
|
126
|
+
* {@link debugAssert} uses this pattern.
|
|
127
|
+
*
|
|
128
|
+
* @privateRemarks
|
|
129
|
+
* Since this function has no built in option for toggling it in development for testing, it is not exported and is only used as a building block for other testable options.
|
|
130
|
+
* There are some additional details about syntax and bundler support in https://github.com/javascript-compiler-hints/compiler-notations-spec/tree/main .
|
|
131
|
+
* This code uses both NO_SIDE_EFFECTS and PURE to maximize compatibility: for any bundler supporting both they are redundant.
|
|
132
|
+
*/
|
|
133
|
+
// Using the exact syntax from https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md to maximize compatibility with tree-shaking tools.
|
|
134
|
+
// eslint-disable-next-line spaced-comment
|
|
135
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
136
|
+
function skipInProduction(conditional) {
|
|
137
|
+
// Here __PURE__ annotation is used to indicate that is is safe to optimize out this call.
|
|
138
|
+
// This is valid since the contract for this function is that "conditional" should be side effect free if it were run in production scenarios
|
|
139
|
+
// See https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free for documentation on this annotation.
|
|
140
|
+
// Using the exact syntax from https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free to maximize compatibility with tree-shaking tools.
|
|
141
|
+
// eslint-disable-next-line spaced-comment
|
|
142
|
+
/*#__PURE__*/ conditional();
|
|
143
|
+
}
|
|
26
144
|
//# sourceMappingURL=assert.js.map
|
package/dist/assert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,SAAgB,MAAM,CAAC,SAAkB,EAAE,OAAwB;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CACpF,CAAC;IACH,CAAC;AACF,CAAC;AAND,wBAMC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,SAAgB,WAAW,CAAC,SAA8C;IACzE,uJAAuJ;IACvJ,yJAAyJ;IACzJ,yIAAyI;IACzI,gBAAgB,CAAC,GAAG,EAAE;QACrB,IAAI,mBAAmB,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACrB,QAAQ,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC9D,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAbD,kCAaC;AAED,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC;;;;;;GAMG;AACH,SAAgB,qBAAqB,CAAC,OAAgB;IACrD,MAAM,CACL,iCAAiC,EAAE,EACnC,KAAK,CAAC,4EAA4E,CAClF,CAAC;IACF,MAAM,GAAG,GAAG,mBAAmB,CAAC;IAChC,mBAAmB,GAAG,OAAO,CAAC;IAC9B,OAAO,GAAG,CAAC;AACZ,CAAC;AARD,sDAQC;AAED;;;;;;;GAOG;AACH,SAAgB,iCAAiC;IAChD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,gBAAgB,CAAC,GAAG,EAAE;QACrB,QAAQ,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AACjB,CAAC;AAND,8EAMC;AAED;;;;;;;;;;;;;;GAcG;AACH,iMAAiM;AACjM,0CAA0C;AAC1C,wBAAwB;AACxB,SAAS,gBAAgB,CAAC,WAAuB;IAChD,0FAA0F;IAC1F,6IAA6I;IAC7I,iIAAiI;IAEjI,sKAAsK;IACtK,0CAA0C;IAC1C,aAAa,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Asserts the specified condition.\n *\n * @param condition - The condition that should be true, if the condition is false an error will be thrown.\n * Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.\n * @param message - The message to include in the error when the condition does not hold.\n * A number should not be specified manually: use a string.\n * Before a release, policy-check should be run, which will convert any asserts still using strings to\n * use numbered error codes instead.\n * @remarks\n * Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.\n *\n * Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.\n * Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.\n * It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.\n *\n * In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead\n * to optimize bundle size.\n *\n * This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.\n * @privateRemarks\n * This should be deprecated (as a non internal API) then moved to purely internal.\n * When done the `debugAssert` reference above should be turned into a link.\n * @legacy\n * @alpha\n */\nexport function assert(condition: boolean, message: string | number): asserts condition {\n\tif (!condition) {\n\t\tthrow new Error(\n\t\t\ttypeof message === \"number\" ? `0x${message.toString(16).padStart(3, \"0\")}` : message,\n\t\t);\n\t}\n}\n\n/**\n * Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.\n *\n * Disabled by default.\n *\n * If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.\n *\n * @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.\n * This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.\n * @remarks\n * Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.\n *\n * Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.\n * The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.\n *\n * These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.\n * Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.\n * These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.\n *\n * @privateRemarks\n * This design was chosen to accomplish two main goals:\n *\n * 1. Make it easy to compile debug asserts fully out of production builds.\n * For webpack this happens by default, avoiding the need for customers to do special configuration.\n * This is important for both performance and bundle size.\n *\n * 2. Make it easy to test (both manually and automated) with and without the predicates running.\n * This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.\n *\n * The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.\n * @internal\n */\nexport function debugAssert(predicate: () => true | { toString(): string }): void {\n\t// This is valid since the contract for this function is that \"predicate\" should be side effect free and never return non true in production scenarios:\n\t// it returning non-true indicates a bug is present, and that the validation it does to detect the bug is only desired in specific test/debug situations.\n\t// Production scenarios, where pure code is removed, should never hit a failing predicate, and thus this code should be side effect free.\n\tskipInProduction(() => {\n\t\tif (debugAssertsEnabled) {\n\t\t\tconst result = predicate();\n\t\t\tif (result !== true) {\n\t\t\t\tdebugger;\n\t\t\t\tthrow new Error(`Debug assert failed: ${result.toString()}`);\n\t\t\t}\n\t\t}\n\t});\n}\n\nlet debugAssertsEnabled = false;\n\n/**\n * Enables {@link debugAssert} validation.\n * @remarks\n * Throws if debugAsserts have been optimized out.\n * @returns The previous state of debugAsserts.\n * @internal\n */\nexport function configureDebugAsserts(enabled: boolean): boolean {\n\tassert(\n\t\tnonProductionConditionalsIncluded(),\n\t\t0xab1 /* Debug asserts cannot be configured since they have been optimized out. */,\n\t);\n\tconst old = debugAssertsEnabled;\n\tdebugAssertsEnabled = enabled;\n\treturn old;\n}\n\n/**\n * Checks if non-production conditional code like {@link debugAssert} is included in this build.\n * @remarks\n * Such code can be optimized out by bundlers: this checks if that has occurred.\n * @privateRemarks\n * See {@link skipInProduction}.\n * @internal\n */\nexport function nonProductionConditionalsIncluded(): boolean {\n\tlet included = false;\n\tskipInProduction(() => {\n\t\tincluded = true;\n\t});\n\treturn included;\n}\n\n/**\n * Run `conditional` only in debug/development (non optimized/minified) builds, but optimize it out of production builds.\n *\n * @param conditional - This function will only be run in some configurations so it should be pure (at least in production scenarios).\n * It can be used to interact with debug only functionality that is also removed in production builds, or to do validation/testing/debugging that can be assumed to be sideeffect free in production where it might be removed.\n * @remarks\n * Great care must be taken when using this to ensure that bugs are not introduced which only occur when `conditional` is not run.\n * One way to do this is to provide an alternative way to disable the effects of `conditional` in development builds so both configurations can be tested:\n * {@link debugAssert} uses this pattern.\n *\n * @privateRemarks\n * Since this function has no built in option for toggling it in development for testing, it is not exported and is only used as a building block for other testable options.\n * There are some additional details about syntax and bundler support in https://github.com/javascript-compiler-hints/compiler-notations-spec/tree/main .\n * This code uses both NO_SIDE_EFFECTS and PURE to maximize compatibility: for any bundler supporting both they are redundant.\n */\n// Using the exact syntax from https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md to maximize compatibility with tree-shaking tools.\n// eslint-disable-next-line spaced-comment\n/*#__NO_SIDE_EFFECTS__*/\nfunction skipInProduction(conditional: () => void): void {\n\t// Here __PURE__ annotation is used to indicate that is is safe to optimize out this call.\n\t// This is valid since the contract for this function is that \"conditional\" should be side effect free if it were run in production scenarios\n\t// See https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free for documentation on this annotation.\n\n\t// Using the exact syntax from https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free to maximize compatibility with tree-shaking tools.\n\t// eslint-disable-next-line spaced-comment\n\t/*#__PURE__*/ conditional();\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
export { assert } from "./assert.js";
|
|
5
|
+
export { assert, debugAssert, configureDebugAsserts, nonProductionConditionalsIncluded, } from "./assert.js";
|
|
6
6
|
export { compareArrays } from "./compare.js";
|
|
7
7
|
export { delay } from "./delay.js";
|
|
8
8
|
export type { IComparer, IHeapNode } from "./heap.js";
|
|
@@ -11,6 +11,7 @@ export { Lazy, LazyPromise } from "./lazy.js";
|
|
|
11
11
|
export type { PromiseCacheExpiry, PromiseCacheOptions } from "./promiseCache.js";
|
|
12
12
|
export { PromiseCache } from "./promiseCache.js";
|
|
13
13
|
export { Deferred } from "./promises.js";
|
|
14
|
+
export { shallowCloneObject } from "./shallowClone.js";
|
|
14
15
|
export type { IPromiseTimer, IPromiseTimerResult, ITimer } from "./timer.js";
|
|
15
16
|
export { PromiseTimer, setLongTimeout, Timer } from "./timer.js";
|
|
16
17
|
export { unreachableCase } from "./unreachable.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,MAAM,EACN,WAAW,EACX,qBAAqB,EACrB,iCAAiC,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.oob = exports.isPromiseLike = exports.isObject = exports.unreachableCase = exports.Timer = exports.setLongTimeout = exports.PromiseTimer = exports.Deferred = exports.PromiseCache = exports.LazyPromise = exports.Lazy = exports.NumberComparer = exports.Heap = exports.delay = exports.compareArrays = exports.assert = void 0;
|
|
7
|
+
exports.oob = exports.isPromiseLike = exports.isObject = exports.unreachableCase = exports.Timer = exports.setLongTimeout = exports.PromiseTimer = exports.shallowCloneObject = exports.Deferred = exports.PromiseCache = exports.LazyPromise = exports.Lazy = exports.NumberComparer = exports.Heap = exports.delay = exports.compareArrays = exports.nonProductionConditionalsIncluded = exports.configureDebugAsserts = exports.debugAssert = exports.assert = void 0;
|
|
8
8
|
var assert_js_1 = require("./assert.js");
|
|
9
9
|
Object.defineProperty(exports, "assert", { enumerable: true, get: function () { return assert_js_1.assert; } });
|
|
10
|
+
Object.defineProperty(exports, "debugAssert", { enumerable: true, get: function () { return assert_js_1.debugAssert; } });
|
|
11
|
+
Object.defineProperty(exports, "configureDebugAsserts", { enumerable: true, get: function () { return assert_js_1.configureDebugAsserts; } });
|
|
12
|
+
Object.defineProperty(exports, "nonProductionConditionalsIncluded", { enumerable: true, get: function () { return assert_js_1.nonProductionConditionalsIncluded; } });
|
|
10
13
|
var compare_js_1 = require("./compare.js");
|
|
11
14
|
Object.defineProperty(exports, "compareArrays", { enumerable: true, get: function () { return compare_js_1.compareArrays; } });
|
|
12
15
|
var delay_js_1 = require("./delay.js");
|
|
@@ -21,6 +24,8 @@ var promiseCache_js_1 = require("./promiseCache.js");
|
|
|
21
24
|
Object.defineProperty(exports, "PromiseCache", { enumerable: true, get: function () { return promiseCache_js_1.PromiseCache; } });
|
|
22
25
|
var promises_js_1 = require("./promises.js");
|
|
23
26
|
Object.defineProperty(exports, "Deferred", { enumerable: true, get: function () { return promises_js_1.Deferred; } });
|
|
27
|
+
var shallowClone_js_1 = require("./shallowClone.js");
|
|
28
|
+
Object.defineProperty(exports, "shallowCloneObject", { enumerable: true, get: function () { return shallowClone_js_1.shallowCloneObject; } });
|
|
24
29
|
var timer_js_1 = require("./timer.js");
|
|
25
30
|
Object.defineProperty(exports, "PromiseTimer", { enumerable: true, get: function () { return timer_js_1.PromiseTimer; } });
|
|
26
31
|
Object.defineProperty(exports, "setLongTimeout", { enumerable: true, get: function () { return timer_js_1.setLongTimeout; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,yCAKqB;AAJpB,mGAAA,MAAM,OAAA;AACN,wGAAA,WAAW,OAAA;AACX,kHAAA,qBAAqB,OAAA;AACrB,8HAAA,iCAAiC,OAAA;AAElC,2CAA6C;AAApC,2GAAA,aAAa,OAAA;AACtB,uCAAmC;AAA1B,iGAAA,KAAK,OAAA;AAEd,qCAAiD;AAAxC,+FAAA,IAAI,OAAA;AAAE,yGAAA,cAAc,OAAA;AAC7B,qCAA8C;AAArC,+FAAA,IAAI,OAAA;AAAE,sGAAA,WAAW,OAAA;AAE1B,qDAAiD;AAAxC,+GAAA,YAAY,OAAA;AACrB,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,qDAAuD;AAA9C,qHAAA,kBAAkB,OAAA;AAE3B,uCAAiE;AAAxD,wGAAA,YAAY,OAAA;AAAE,0GAAA,cAAc,OAAA;AAAE,iGAAA,KAAK,OAAA;AAC5C,mDAAmD;AAA1C,iHAAA,eAAe,OAAA;AACxB,mDAA2D;AAAlD,0GAAA,QAAQ,OAAA;AAAE,+GAAA,aAAa,OAAA;AAChC,mCAA+B;AAAtB,6FAAA,GAAG,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tassert,\n\tdebugAssert,\n\tconfigureDebugAsserts,\n\tnonProductionConditionalsIncluded,\n} from \"./assert.js\";\nexport { compareArrays } from \"./compare.js\";\nexport { delay } from \"./delay.js\";\nexport type { IComparer, IHeapNode } from \"./heap.js\";\nexport { Heap, NumberComparer } from \"./heap.js\";\nexport { Lazy, LazyPromise } from \"./lazy.js\";\nexport type { PromiseCacheExpiry, PromiseCacheOptions } from \"./promiseCache.js\";\nexport { PromiseCache } from \"./promiseCache.js\";\nexport { Deferred } from \"./promises.js\";\nexport { shallowCloneObject } from \"./shallowClone.js\";\nexport type { IPromiseTimer, IPromiseTimerResult, ITimer } from \"./timer.js\";\nexport { PromiseTimer, setLongTimeout, Timer } from \"./timer.js\";\nexport { unreachableCase } from \"./unreachable.js\";\nexport { isObject, isPromiseLike } from \"./typesGuards.js\";\nexport { oob } from \"./oob.js\";\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Shallow clone an object.
|
|
7
|
+
*
|
|
8
|
+
* @param value - The object to clone
|
|
9
|
+
* @returns A shallow clone of the input value
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function shallowCloneObject<T extends object>(value: T): T;
|
|
13
|
+
//# sourceMappingURL=shallowClone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shallowClone.d.ts","sourceRoot":"","sources":["../src/shallowClone.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAKhE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.shallowCloneObject = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Shallow clone an object.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The object to clone
|
|
12
|
+
* @returns A shallow clone of the input value
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
function shallowCloneObject(value) {
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
return [...value];
|
|
18
|
+
}
|
|
19
|
+
return { ...value };
|
|
20
|
+
}
|
|
21
|
+
exports.shallowCloneObject = shallowCloneObject;
|
|
22
|
+
//# sourceMappingURL=shallowClone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shallowClone.js","sourceRoot":"","sources":["../src/shallowClone.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAmB,KAAQ;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,KAAK,CAAM,CAAC;IACxB,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACrB,CAAC;AALD,gDAKC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Shallow clone an object.\n *\n * @param value - The object to clone\n * @returns A shallow clone of the input value\n * @internal\n */\nexport function shallowCloneObject<T extends object>(value: T): T {\n\tif (Array.isArray(value)) {\n\t\treturn [...value] as T;\n\t}\n\treturn { ...value };\n}\n"]}
|
package/lib/assert.d.ts
CHANGED
|
@@ -3,16 +3,82 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Asserts the specified condition.
|
|
7
|
+
*
|
|
8
8
|
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
|
9
9
|
* Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.
|
|
10
10
|
* @param message - The message to include in the error when the condition does not hold.
|
|
11
11
|
* A number should not be specified manually: use a string.
|
|
12
12
|
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
|
13
13
|
* use numbered error codes instead.
|
|
14
|
+
* @remarks
|
|
15
|
+
* Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.
|
|
16
|
+
*
|
|
17
|
+
* Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.
|
|
18
|
+
* Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.
|
|
19
|
+
* It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.
|
|
20
|
+
*
|
|
21
|
+
* In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead
|
|
22
|
+
* to optimize bundle size.
|
|
23
|
+
*
|
|
24
|
+
* This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.
|
|
25
|
+
* @privateRemarks
|
|
26
|
+
* This should be deprecated (as a non internal API) then moved to purely internal.
|
|
27
|
+
* When done the `debugAssert` reference above should be turned into a link.
|
|
14
28
|
* @legacy
|
|
15
29
|
* @alpha
|
|
16
30
|
*/
|
|
17
31
|
export declare function assert(condition: boolean, message: string | number): asserts condition;
|
|
32
|
+
/**
|
|
33
|
+
* Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.
|
|
34
|
+
*
|
|
35
|
+
* Disabled by default.
|
|
36
|
+
*
|
|
37
|
+
* If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.
|
|
38
|
+
*
|
|
39
|
+
* @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.
|
|
40
|
+
* This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.
|
|
41
|
+
* @remarks
|
|
42
|
+
* Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.
|
|
43
|
+
*
|
|
44
|
+
* Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.
|
|
45
|
+
* The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.
|
|
46
|
+
*
|
|
47
|
+
* These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.
|
|
48
|
+
* Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.
|
|
49
|
+
* These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.
|
|
50
|
+
*
|
|
51
|
+
* @privateRemarks
|
|
52
|
+
* This design was chosen to accomplish two main goals:
|
|
53
|
+
*
|
|
54
|
+
* 1. Make it easy to compile debug asserts fully out of production builds.
|
|
55
|
+
* For webpack this happens by default, avoiding the need for customers to do special configuration.
|
|
56
|
+
* This is important for both performance and bundle size.
|
|
57
|
+
*
|
|
58
|
+
* 2. Make it easy to test (both manually and automated) with and without the predicates running.
|
|
59
|
+
* This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.
|
|
60
|
+
*
|
|
61
|
+
* The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export declare function debugAssert(predicate: () => true | {
|
|
65
|
+
toString(): string;
|
|
66
|
+
}): void;
|
|
67
|
+
/**
|
|
68
|
+
* Enables {@link debugAssert} validation.
|
|
69
|
+
* @remarks
|
|
70
|
+
* Throws if debugAsserts have been optimized out.
|
|
71
|
+
* @returns The previous state of debugAsserts.
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export declare function configureDebugAsserts(enabled: boolean): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if non-production conditional code like {@link debugAssert} is included in this build.
|
|
77
|
+
* @remarks
|
|
78
|
+
* Such code can be optimized out by bundlers: this checks if that has occurred.
|
|
79
|
+
* @privateRemarks
|
|
80
|
+
* See {@link skipInProduction}.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
export declare function nonProductionConditionalsIncluded(): boolean;
|
|
18
84
|
//# sourceMappingURL=assert.d.ts.map
|
package/lib/assert.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,CAMtF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,IAAI,GAAG;IAAE,QAAQ,IAAI,MAAM,CAAA;CAAE,GAAG,IAAI,CAahF;AAID;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ/D;AAED;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,IAAI,OAAO,CAM3D"}
|
package/lib/assert.js
CHANGED
|
@@ -3,14 +3,28 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Asserts the specified condition.
|
|
7
|
+
*
|
|
8
8
|
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
|
9
9
|
* Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.
|
|
10
10
|
* @param message - The message to include in the error when the condition does not hold.
|
|
11
11
|
* A number should not be specified manually: use a string.
|
|
12
12
|
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
|
13
13
|
* use numbered error codes instead.
|
|
14
|
+
* @remarks
|
|
15
|
+
* Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.
|
|
16
|
+
*
|
|
17
|
+
* Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.
|
|
18
|
+
* Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.
|
|
19
|
+
* It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.
|
|
20
|
+
*
|
|
21
|
+
* In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead
|
|
22
|
+
* to optimize bundle size.
|
|
23
|
+
*
|
|
24
|
+
* This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.
|
|
25
|
+
* @privateRemarks
|
|
26
|
+
* This should be deprecated (as a non internal API) then moved to purely internal.
|
|
27
|
+
* When done the `debugAssert` reference above should be turned into a link.
|
|
14
28
|
* @legacy
|
|
15
29
|
* @alpha
|
|
16
30
|
*/
|
|
@@ -19,4 +33,105 @@ export function assert(condition, message) {
|
|
|
19
33
|
throw new Error(typeof message === "number" ? `0x${message.toString(16).padStart(3, "0")}` : message);
|
|
20
34
|
}
|
|
21
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.
|
|
38
|
+
*
|
|
39
|
+
* Disabled by default.
|
|
40
|
+
*
|
|
41
|
+
* If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.
|
|
42
|
+
*
|
|
43
|
+
* @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.
|
|
44
|
+
* This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.
|
|
45
|
+
* @remarks
|
|
46
|
+
* Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.
|
|
47
|
+
*
|
|
48
|
+
* Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.
|
|
49
|
+
* The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.
|
|
50
|
+
*
|
|
51
|
+
* These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.
|
|
52
|
+
* Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.
|
|
53
|
+
* These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.
|
|
54
|
+
*
|
|
55
|
+
* @privateRemarks
|
|
56
|
+
* This design was chosen to accomplish two main goals:
|
|
57
|
+
*
|
|
58
|
+
* 1. Make it easy to compile debug asserts fully out of production builds.
|
|
59
|
+
* For webpack this happens by default, avoiding the need for customers to do special configuration.
|
|
60
|
+
* This is important for both performance and bundle size.
|
|
61
|
+
*
|
|
62
|
+
* 2. Make it easy to test (both manually and automated) with and without the predicates running.
|
|
63
|
+
* This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.
|
|
64
|
+
*
|
|
65
|
+
* The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
export function debugAssert(predicate) {
|
|
69
|
+
// This is valid since the contract for this function is that "predicate" should be side effect free and never return non true in production scenarios:
|
|
70
|
+
// it returning non-true indicates a bug is present, and that the validation it does to detect the bug is only desired in specific test/debug situations.
|
|
71
|
+
// Production scenarios, where pure code is removed, should never hit a failing predicate, and thus this code should be side effect free.
|
|
72
|
+
skipInProduction(() => {
|
|
73
|
+
if (debugAssertsEnabled) {
|
|
74
|
+
const result = predicate();
|
|
75
|
+
if (result !== true) {
|
|
76
|
+
debugger;
|
|
77
|
+
throw new Error(`Debug assert failed: ${result.toString()}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
let debugAssertsEnabled = false;
|
|
83
|
+
/**
|
|
84
|
+
* Enables {@link debugAssert} validation.
|
|
85
|
+
* @remarks
|
|
86
|
+
* Throws if debugAsserts have been optimized out.
|
|
87
|
+
* @returns The previous state of debugAsserts.
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export function configureDebugAsserts(enabled) {
|
|
91
|
+
assert(nonProductionConditionalsIncluded(), 0xab1 /* Debug asserts cannot be configured since they have been optimized out. */);
|
|
92
|
+
const old = debugAssertsEnabled;
|
|
93
|
+
debugAssertsEnabled = enabled;
|
|
94
|
+
return old;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checks if non-production conditional code like {@link debugAssert} is included in this build.
|
|
98
|
+
* @remarks
|
|
99
|
+
* Such code can be optimized out by bundlers: this checks if that has occurred.
|
|
100
|
+
* @privateRemarks
|
|
101
|
+
* See {@link skipInProduction}.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export function nonProductionConditionalsIncluded() {
|
|
105
|
+
let included = false;
|
|
106
|
+
skipInProduction(() => {
|
|
107
|
+
included = true;
|
|
108
|
+
});
|
|
109
|
+
return included;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Run `conditional` only in debug/development (non optimized/minified) builds, but optimize it out of production builds.
|
|
113
|
+
*
|
|
114
|
+
* @param conditional - This function will only be run in some configurations so it should be pure (at least in production scenarios).
|
|
115
|
+
* It can be used to interact with debug only functionality that is also removed in production builds, or to do validation/testing/debugging that can be assumed to be sideeffect free in production where it might be removed.
|
|
116
|
+
* @remarks
|
|
117
|
+
* Great care must be taken when using this to ensure that bugs are not introduced which only occur when `conditional` is not run.
|
|
118
|
+
* One way to do this is to provide an alternative way to disable the effects of `conditional` in development builds so both configurations can be tested:
|
|
119
|
+
* {@link debugAssert} uses this pattern.
|
|
120
|
+
*
|
|
121
|
+
* @privateRemarks
|
|
122
|
+
* Since this function has no built in option for toggling it in development for testing, it is not exported and is only used as a building block for other testable options.
|
|
123
|
+
* There are some additional details about syntax and bundler support in https://github.com/javascript-compiler-hints/compiler-notations-spec/tree/main .
|
|
124
|
+
* This code uses both NO_SIDE_EFFECTS and PURE to maximize compatibility: for any bundler supporting both they are redundant.
|
|
125
|
+
*/
|
|
126
|
+
// Using the exact syntax from https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md to maximize compatibility with tree-shaking tools.
|
|
127
|
+
// eslint-disable-next-line spaced-comment
|
|
128
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
129
|
+
function skipInProduction(conditional) {
|
|
130
|
+
// Here __PURE__ annotation is used to indicate that is is safe to optimize out this call.
|
|
131
|
+
// This is valid since the contract for this function is that "conditional" should be side effect free if it were run in production scenarios
|
|
132
|
+
// See https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free for documentation on this annotation.
|
|
133
|
+
// Using the exact syntax from https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free to maximize compatibility with tree-shaking tools.
|
|
134
|
+
// eslint-disable-next-line spaced-comment
|
|
135
|
+
/*#__PURE__*/ conditional();
|
|
136
|
+
}
|
|
22
137
|
//# sourceMappingURL=assert.js.map
|
package/lib/assert.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,MAAM,CAAC,SAAkB,EAAE,OAAwB;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CACpF,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,WAAW,CAAC,SAA8C;IACzE,uJAAuJ;IACvJ,yJAAyJ;IACzJ,yIAAyI;IACzI,gBAAgB,CAAC,GAAG,EAAE;QACrB,IAAI,mBAAmB,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACrB,QAAQ,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC9D,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACrD,MAAM,CACL,iCAAiC,EAAE,EACnC,KAAK,CAAC,4EAA4E,CAClF,CAAC;IACF,MAAM,GAAG,GAAG,mBAAmB,CAAC;IAChC,mBAAmB,GAAG,OAAO,CAAC;IAC9B,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iCAAiC;IAChD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,gBAAgB,CAAC,GAAG,EAAE;QACrB,QAAQ,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,iMAAiM;AACjM,0CAA0C;AAC1C,wBAAwB;AACxB,SAAS,gBAAgB,CAAC,WAAuB;IAChD,0FAA0F;IAC1F,6IAA6I;IAC7I,iIAAiI;IAEjI,sKAAsK;IACtK,0CAA0C;IAC1C,aAAa,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Asserts the specified condition.\n *\n * @param condition - The condition that should be true, if the condition is false an error will be thrown.\n * Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.\n * @param message - The message to include in the error when the condition does not hold.\n * A number should not be specified manually: use a string.\n * Before a release, policy-check should be run, which will convert any asserts still using strings to\n * use numbered error codes instead.\n * @remarks\n * Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.\n *\n * Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.\n * Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.\n * It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.\n *\n * In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead\n * to optimize bundle size.\n *\n * This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.\n * @privateRemarks\n * This should be deprecated (as a non internal API) then moved to purely internal.\n * When done the `debugAssert` reference above should be turned into a link.\n * @legacy\n * @alpha\n */\nexport function assert(condition: boolean, message: string | number): asserts condition {\n\tif (!condition) {\n\t\tthrow new Error(\n\t\t\ttypeof message === \"number\" ? `0x${message.toString(16).padStart(3, \"0\")}` : message,\n\t\t);\n\t}\n}\n\n/**\n * Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.\n *\n * Disabled by default.\n *\n * If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.\n *\n * @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.\n * This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.\n * @remarks\n * Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.\n *\n * Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.\n * The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.\n *\n * These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.\n * Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.\n * These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.\n *\n * @privateRemarks\n * This design was chosen to accomplish two main goals:\n *\n * 1. Make it easy to compile debug asserts fully out of production builds.\n * For webpack this happens by default, avoiding the need for customers to do special configuration.\n * This is important for both performance and bundle size.\n *\n * 2. Make it easy to test (both manually and automated) with and without the predicates running.\n * This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.\n *\n * The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.\n * @internal\n */\nexport function debugAssert(predicate: () => true | { toString(): string }): void {\n\t// This is valid since the contract for this function is that \"predicate\" should be side effect free and never return non true in production scenarios:\n\t// it returning non-true indicates a bug is present, and that the validation it does to detect the bug is only desired in specific test/debug situations.\n\t// Production scenarios, where pure code is removed, should never hit a failing predicate, and thus this code should be side effect free.\n\tskipInProduction(() => {\n\t\tif (debugAssertsEnabled) {\n\t\t\tconst result = predicate();\n\t\t\tif (result !== true) {\n\t\t\t\tdebugger;\n\t\t\t\tthrow new Error(`Debug assert failed: ${result.toString()}`);\n\t\t\t}\n\t\t}\n\t});\n}\n\nlet debugAssertsEnabled = false;\n\n/**\n * Enables {@link debugAssert} validation.\n * @remarks\n * Throws if debugAsserts have been optimized out.\n * @returns The previous state of debugAsserts.\n * @internal\n */\nexport function configureDebugAsserts(enabled: boolean): boolean {\n\tassert(\n\t\tnonProductionConditionalsIncluded(),\n\t\t0xab1 /* Debug asserts cannot be configured since they have been optimized out. */,\n\t);\n\tconst old = debugAssertsEnabled;\n\tdebugAssertsEnabled = enabled;\n\treturn old;\n}\n\n/**\n * Checks if non-production conditional code like {@link debugAssert} is included in this build.\n * @remarks\n * Such code can be optimized out by bundlers: this checks if that has occurred.\n * @privateRemarks\n * See {@link skipInProduction}.\n * @internal\n */\nexport function nonProductionConditionalsIncluded(): boolean {\n\tlet included = false;\n\tskipInProduction(() => {\n\t\tincluded = true;\n\t});\n\treturn included;\n}\n\n/**\n * Run `conditional` only in debug/development (non optimized/minified) builds, but optimize it out of production builds.\n *\n * @param conditional - This function will only be run in some configurations so it should be pure (at least in production scenarios).\n * It can be used to interact with debug only functionality that is also removed in production builds, or to do validation/testing/debugging that can be assumed to be sideeffect free in production where it might be removed.\n * @remarks\n * Great care must be taken when using this to ensure that bugs are not introduced which only occur when `conditional` is not run.\n * One way to do this is to provide an alternative way to disable the effects of `conditional` in development builds so both configurations can be tested:\n * {@link debugAssert} uses this pattern.\n *\n * @privateRemarks\n * Since this function has no built in option for toggling it in development for testing, it is not exported and is only used as a building block for other testable options.\n * There are some additional details about syntax and bundler support in https://github.com/javascript-compiler-hints/compiler-notations-spec/tree/main .\n * This code uses both NO_SIDE_EFFECTS and PURE to maximize compatibility: for any bundler supporting both they are redundant.\n */\n// Using the exact syntax from https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md to maximize compatibility with tree-shaking tools.\n// eslint-disable-next-line spaced-comment\n/*#__NO_SIDE_EFFECTS__*/\nfunction skipInProduction(conditional: () => void): void {\n\t// Here __PURE__ annotation is used to indicate that is is safe to optimize out this call.\n\t// This is valid since the contract for this function is that \"conditional\" should be side effect free if it were run in production scenarios\n\t// See https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free for documentation on this annotation.\n\n\t// Using the exact syntax from https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free to maximize compatibility with tree-shaking tools.\n\t// eslint-disable-next-line spaced-comment\n\t/*#__PURE__*/ conditional();\n}\n"]}
|
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
export { assert } from "./assert.js";
|
|
5
|
+
export { assert, debugAssert, configureDebugAsserts, nonProductionConditionalsIncluded, } from "./assert.js";
|
|
6
6
|
export { compareArrays } from "./compare.js";
|
|
7
7
|
export { delay } from "./delay.js";
|
|
8
8
|
export type { IComparer, IHeapNode } from "./heap.js";
|
|
@@ -11,6 +11,7 @@ export { Lazy, LazyPromise } from "./lazy.js";
|
|
|
11
11
|
export type { PromiseCacheExpiry, PromiseCacheOptions } from "./promiseCache.js";
|
|
12
12
|
export { PromiseCache } from "./promiseCache.js";
|
|
13
13
|
export { Deferred } from "./promises.js";
|
|
14
|
+
export { shallowCloneObject } from "./shallowClone.js";
|
|
14
15
|
export type { IPromiseTimer, IPromiseTimerResult, ITimer } from "./timer.js";
|
|
15
16
|
export { PromiseTimer, setLongTimeout, Timer } from "./timer.js";
|
|
16
17
|
export { unreachableCase } from "./unreachable.js";
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,MAAM,EACN,WAAW,EACX,qBAAqB,EACrB,iCAAiC,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
export { assert } from "./assert.js";
|
|
5
|
+
export { assert, debugAssert, configureDebugAsserts, nonProductionConditionalsIncluded, } from "./assert.js";
|
|
6
6
|
export { compareArrays } from "./compare.js";
|
|
7
7
|
export { delay } from "./delay.js";
|
|
8
8
|
export { Heap, NumberComparer } from "./heap.js";
|
|
9
9
|
export { Lazy, LazyPromise } from "./lazy.js";
|
|
10
10
|
export { PromiseCache } from "./promiseCache.js";
|
|
11
11
|
export { Deferred } from "./promises.js";
|
|
12
|
+
export { shallowCloneObject } from "./shallowClone.js";
|
|
12
13
|
export { PromiseTimer, setLongTimeout, Timer } from "./timer.js";
|
|
13
14
|
export { unreachableCase } from "./unreachable.js";
|
|
14
15
|
export { isObject, isPromiseLike } from "./typesGuards.js";
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,MAAM,EACN,WAAW,EACX,qBAAqB,EACrB,iCAAiC,GACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tassert,\n\tdebugAssert,\n\tconfigureDebugAsserts,\n\tnonProductionConditionalsIncluded,\n} from \"./assert.js\";\nexport { compareArrays } from \"./compare.js\";\nexport { delay } from \"./delay.js\";\nexport type { IComparer, IHeapNode } from \"./heap.js\";\nexport { Heap, NumberComparer } from \"./heap.js\";\nexport { Lazy, LazyPromise } from \"./lazy.js\";\nexport type { PromiseCacheExpiry, PromiseCacheOptions } from \"./promiseCache.js\";\nexport { PromiseCache } from \"./promiseCache.js\";\nexport { Deferred } from \"./promises.js\";\nexport { shallowCloneObject } from \"./shallowClone.js\";\nexport type { IPromiseTimer, IPromiseTimerResult, ITimer } from \"./timer.js\";\nexport { PromiseTimer, setLongTimeout, Timer } from \"./timer.js\";\nexport { unreachableCase } from \"./unreachable.js\";\nexport { isObject, isPromiseLike } from \"./typesGuards.js\";\nexport { oob } from \"./oob.js\";\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Shallow clone an object.
|
|
7
|
+
*
|
|
8
|
+
* @param value - The object to clone
|
|
9
|
+
* @returns A shallow clone of the input value
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function shallowCloneObject<T extends object>(value: T): T;
|
|
13
|
+
//# sourceMappingURL=shallowClone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shallowClone.d.ts","sourceRoot":"","sources":["../src/shallowClone.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAKhE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Shallow clone an object.
|
|
7
|
+
*
|
|
8
|
+
* @param value - The object to clone
|
|
9
|
+
* @returns A shallow clone of the input value
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export function shallowCloneObject(value) {
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
return [...value];
|
|
15
|
+
}
|
|
16
|
+
return { ...value };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=shallowClone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shallowClone.js","sourceRoot":"","sources":["../src/shallowClone.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAmB,KAAQ;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,KAAK,CAAM,CAAC;IACxB,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACrB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Shallow clone an object.\n *\n * @param value - The object to clone\n * @returns A shallow clone of the input value\n * @internal\n */\nexport function shallowCloneObject<T extends object>(value: T): T {\n\tif (Array.isArray(value)) {\n\t\treturn [...value] as T;\n\t}\n\treturn { ...value };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/core-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.0",
|
|
4
4
|
"description": "Not intended for use outside the Fluid client repo.",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
71
71
|
"@biomejs/biome": "~1.9.3",
|
|
72
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
72
|
+
"@fluid-internal/mocha-test-setup": "~2.21.0",
|
|
73
73
|
"@fluid-tools/benchmark": "^0.50.0",
|
|
74
74
|
"@fluid-tools/build-cli": "^0.51.0",
|
|
75
75
|
"@fluidframework/build-common": "^2.0.3",
|
|
76
76
|
"@fluidframework/build-tools": "^0.51.0",
|
|
77
|
-
"@fluidframework/core-utils-previous": "npm:@fluidframework/core-utils@2.
|
|
78
|
-
"@fluidframework/eslint-config-fluid": "^5.
|
|
77
|
+
"@fluidframework/core-utils-previous": "npm:@fluidframework/core-utils@2.20.0",
|
|
78
|
+
"@fluidframework/eslint-config-fluid": "^5.7.3",
|
|
79
79
|
"@microsoft/api-extractor": "7.47.8",
|
|
80
80
|
"@types/mocha": "^10.0.10",
|
|
81
81
|
"@types/node": "^18.19.0",
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
"ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor.current.json",
|
|
130
130
|
"ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
|
|
131
131
|
"ci:build:docs": "api-extractor run",
|
|
132
|
-
"clean": "rimraf --glob dist lib
|
|
132
|
+
"clean": "rimraf --glob dist lib {alpha,beta,internal,legacy}.d.ts \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
|
|
133
133
|
"eslint": "eslint --format stylish src",
|
|
134
134
|
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
135
135
|
"format": "npm run format:biome",
|
package/src/assert.ts
CHANGED
|
@@ -4,14 +4,28 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Asserts the specified condition.
|
|
8
|
+
*
|
|
9
9
|
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
|
10
10
|
* Only use this API when `false` indicates a logic error in the problem and thus a bug that should be fixed.
|
|
11
11
|
* @param message - The message to include in the error when the condition does not hold.
|
|
12
12
|
* A number should not be specified manually: use a string.
|
|
13
13
|
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
|
14
14
|
* use numbered error codes instead.
|
|
15
|
+
* @remarks
|
|
16
|
+
* Use this instead of the node 'assert' package, which requires polyfills and has a big impact on bundle sizes.
|
|
17
|
+
*
|
|
18
|
+
* Assertions using this API will be included in all configurations: there is no option to disable or optimize them out.
|
|
19
|
+
* Thus this API is suitable for detecting conditions that should terminate the application and produce a useful diagnostic message.
|
|
20
|
+
* It can be used to ensure bad states are detected early and to avoid data corruption or harder to debug errors.
|
|
21
|
+
*
|
|
22
|
+
* In cases where the assert is very unlikely to have an impact on production code but is still useful as documentation and for debugging, consider using `debugAssert` instead
|
|
23
|
+
* to optimize bundle size.
|
|
24
|
+
*
|
|
25
|
+
* This API is not intended for use outside of the Fluid Framework client codebase: it will most likely be made internal in the future.
|
|
26
|
+
* @privateRemarks
|
|
27
|
+
* This should be deprecated (as a non internal API) then moved to purely internal.
|
|
28
|
+
* When done the `debugAssert` reference above should be turned into a link.
|
|
15
29
|
* @legacy
|
|
16
30
|
* @alpha
|
|
17
31
|
*/
|
|
@@ -22,3 +36,113 @@ export function assert(condition: boolean, message: string | number): asserts co
|
|
|
22
36
|
);
|
|
23
37
|
}
|
|
24
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Asserts that can be conditionally enabled in debug/development builds but will be optimized out of production builds.
|
|
42
|
+
*
|
|
43
|
+
* Disabled by default.
|
|
44
|
+
*
|
|
45
|
+
* If the assert must be enforced/checked in production or enabled by default, use {@link assert} instead.
|
|
46
|
+
*
|
|
47
|
+
* @param predicate - A pure function that should return true if the condition holds, or a string or object describing the condition that failed.
|
|
48
|
+
* This function will only be run in some configurations so it should be pure, and only used to detect bugs (when debugAssert are enabled), and must not be relied on to enforce the condition is true: for that use {@link assert}.
|
|
49
|
+
* @remarks
|
|
50
|
+
* Optimizing the asserts out of the bundle requires a bundler like webpack which leverages `__PURE__` annotations like https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free.
|
|
51
|
+
*
|
|
52
|
+
* Exceptions thrown by this function must never be caught in production code, as that will result in different behavior when testing and when running optimized builds.
|
|
53
|
+
* The `predicate` function must be pure (have no side-effects) to ensure that the behavior of code is the same regardless of if the asserts are disabled, enabled or optimized out.
|
|
54
|
+
*
|
|
55
|
+
* These asserts are disabled by default, even in debug builds to ensure that by default code will be tested as production runs, with them disabled.
|
|
56
|
+
* Additionally, this ensures that apps that use a bundler which does not remove `__PURE__` will not incur the runtime cost of calling the predicate.
|
|
57
|
+
* These asserts can be can be enabled by calling `configureDebugAsserts(true)`: see {@link configureDebugAsserts}.
|
|
58
|
+
*
|
|
59
|
+
* @privateRemarks
|
|
60
|
+
* This design was chosen to accomplish two main goals:
|
|
61
|
+
*
|
|
62
|
+
* 1. Make it easy to compile debug asserts fully out of production builds.
|
|
63
|
+
* For webpack this happens by default, avoiding the need for customers to do special configuration.
|
|
64
|
+
* This is important for both performance and bundle size.
|
|
65
|
+
*
|
|
66
|
+
* 2. Make it easy to test (both manually and automated) with and without the predicates running.
|
|
67
|
+
* This ensures it is possible to benefit from the asserts when enabled, but also test with them disabled to ensure this disablement doesn't cause bugs.
|
|
68
|
+
*
|
|
69
|
+
* The default behavior of having debugAsserts disabled helps ensure that tests which don't know about debug asserts will still run in a way that is most similar to production.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export function debugAssert(predicate: () => true | { toString(): string }): void {
|
|
73
|
+
// This is valid since the contract for this function is that "predicate" should be side effect free and never return non true in production scenarios:
|
|
74
|
+
// it returning non-true indicates a bug is present, and that the validation it does to detect the bug is only desired in specific test/debug situations.
|
|
75
|
+
// Production scenarios, where pure code is removed, should never hit a failing predicate, and thus this code should be side effect free.
|
|
76
|
+
skipInProduction(() => {
|
|
77
|
+
if (debugAssertsEnabled) {
|
|
78
|
+
const result = predicate();
|
|
79
|
+
if (result !== true) {
|
|
80
|
+
debugger;
|
|
81
|
+
throw new Error(`Debug assert failed: ${result.toString()}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let debugAssertsEnabled = false;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Enables {@link debugAssert} validation.
|
|
91
|
+
* @remarks
|
|
92
|
+
* Throws if debugAsserts have been optimized out.
|
|
93
|
+
* @returns The previous state of debugAsserts.
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
export function configureDebugAsserts(enabled: boolean): boolean {
|
|
97
|
+
assert(
|
|
98
|
+
nonProductionConditionalsIncluded(),
|
|
99
|
+
0xab1 /* Debug asserts cannot be configured since they have been optimized out. */,
|
|
100
|
+
);
|
|
101
|
+
const old = debugAssertsEnabled;
|
|
102
|
+
debugAssertsEnabled = enabled;
|
|
103
|
+
return old;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Checks if non-production conditional code like {@link debugAssert} is included in this build.
|
|
108
|
+
* @remarks
|
|
109
|
+
* Such code can be optimized out by bundlers: this checks if that has occurred.
|
|
110
|
+
* @privateRemarks
|
|
111
|
+
* See {@link skipInProduction}.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
export function nonProductionConditionalsIncluded(): boolean {
|
|
115
|
+
let included = false;
|
|
116
|
+
skipInProduction(() => {
|
|
117
|
+
included = true;
|
|
118
|
+
});
|
|
119
|
+
return included;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Run `conditional` only in debug/development (non optimized/minified) builds, but optimize it out of production builds.
|
|
124
|
+
*
|
|
125
|
+
* @param conditional - This function will only be run in some configurations so it should be pure (at least in production scenarios).
|
|
126
|
+
* It can be used to interact with debug only functionality that is also removed in production builds, or to do validation/testing/debugging that can be assumed to be sideeffect free in production where it might be removed.
|
|
127
|
+
* @remarks
|
|
128
|
+
* Great care must be taken when using this to ensure that bugs are not introduced which only occur when `conditional` is not run.
|
|
129
|
+
* One way to do this is to provide an alternative way to disable the effects of `conditional` in development builds so both configurations can be tested:
|
|
130
|
+
* {@link debugAssert} uses this pattern.
|
|
131
|
+
*
|
|
132
|
+
* @privateRemarks
|
|
133
|
+
* Since this function has no built in option for toggling it in development for testing, it is not exported and is only used as a building block for other testable options.
|
|
134
|
+
* There are some additional details about syntax and bundler support in https://github.com/javascript-compiler-hints/compiler-notations-spec/tree/main .
|
|
135
|
+
* This code uses both NO_SIDE_EFFECTS and PURE to maximize compatibility: for any bundler supporting both they are redundant.
|
|
136
|
+
*/
|
|
137
|
+
// Using the exact syntax from https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md to maximize compatibility with tree-shaking tools.
|
|
138
|
+
// eslint-disable-next-line spaced-comment
|
|
139
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
140
|
+
function skipInProduction(conditional: () => void): void {
|
|
141
|
+
// Here __PURE__ annotation is used to indicate that is is safe to optimize out this call.
|
|
142
|
+
// This is valid since the contract for this function is that "conditional" should be side effect free if it were run in production scenarios
|
|
143
|
+
// See https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free for documentation on this annotation.
|
|
144
|
+
|
|
145
|
+
// Using the exact syntax from https://webpack.js.org/guides/tree-shaking/#mark-a-function-call-as-side-effect-free to maximize compatibility with tree-shaking tools.
|
|
146
|
+
// eslint-disable-next-line spaced-comment
|
|
147
|
+
/*#__PURE__*/ conditional();
|
|
148
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export {
|
|
6
|
+
export {
|
|
7
|
+
assert,
|
|
8
|
+
debugAssert,
|
|
9
|
+
configureDebugAsserts,
|
|
10
|
+
nonProductionConditionalsIncluded,
|
|
11
|
+
} from "./assert.js";
|
|
7
12
|
export { compareArrays } from "./compare.js";
|
|
8
13
|
export { delay } from "./delay.js";
|
|
9
14
|
export type { IComparer, IHeapNode } from "./heap.js";
|
|
@@ -12,6 +17,7 @@ export { Lazy, LazyPromise } from "./lazy.js";
|
|
|
12
17
|
export type { PromiseCacheExpiry, PromiseCacheOptions } from "./promiseCache.js";
|
|
13
18
|
export { PromiseCache } from "./promiseCache.js";
|
|
14
19
|
export { Deferred } from "./promises.js";
|
|
20
|
+
export { shallowCloneObject } from "./shallowClone.js";
|
|
15
21
|
export type { IPromiseTimer, IPromiseTimerResult, ITimer } from "./timer.js";
|
|
16
22
|
export { PromiseTimer, setLongTimeout, Timer } from "./timer.js";
|
|
17
23
|
export { unreachableCase } from "./unreachable.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shallow clone an object.
|
|
8
|
+
*
|
|
9
|
+
* @param value - The object to clone
|
|
10
|
+
* @returns A shallow clone of the input value
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function shallowCloneObject<T extends object>(value: T): T {
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return [...value] as T;
|
|
16
|
+
}
|
|
17
|
+
return { ...value };
|
|
18
|
+
}
|