@_linked/core 2.36.2 → 2.36.3
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
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.36.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#357](https://github.com/linked-fw/core/pull/357) [`5985c51`](https://github.com/linked-fw/core/commit/5985c51ded778653187f5934c3b1c9fec169f10b) Thanks [@flyon](https://github.com/flyon)! - `isLinkedInstance` memoises its prototype-chain lookup per prototype, so a repeated failed check is
|
|
8
|
+
one WeakMap and one Map lookup instead of a walk. This recovers most of the query-building time
|
|
9
|
+
2.36.2 added: select +50% → +17%, create +30% → +20% against 2.36.1 (medians). The rest is tracked
|
|
10
|
+
in backlog 058.
|
|
11
|
+
|
|
3
12
|
## 2.36.2
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
@@ -40,6 +40,7 @@ export function brandLinkedClass(Cls, pkg, name) {
|
|
|
40
40
|
const brand = linkedErrorBrand(pkg, name);
|
|
41
41
|
Object.defineProperty(Cls, LINKED_ERROR_BRAND, { value: brand, configurable: true });
|
|
42
42
|
Object.defineProperty(Cls.prototype, brand, { value: true, configurable: true });
|
|
43
|
+
brandsByPrototype = new WeakMap();
|
|
43
44
|
return Cls;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
@@ -79,11 +80,33 @@ export function isLinkedInstance(value, Cls) {
|
|
|
79
80
|
if (!Object.prototype.hasOwnProperty.call(Cls, LINKED_ERROR_BRAND))
|
|
80
81
|
return false;
|
|
81
82
|
const brand = Cls[LINKED_ERROR_BRAND];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
const proto = Object.getPrototypeOf(value);
|
|
84
|
+
return proto !== null && prototypeChainHasBrand(proto, brand);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Per prototype, whether its chain carries each brand asked about. Most checks are misses
|
|
88
|
+
* (`isLinkedInstance(x, PendingQueryContext)` on every value a builder sees), and walking the
|
|
89
|
+
* chain each time made query building measurably slower; with this a repeat check is one
|
|
90
|
+
* WeakMap and one Map lookup. A memo, so per copy of this module. Cleared whenever this copy
|
|
91
|
+
* brands a class, so a brand added after a lookup is never hidden by it.
|
|
92
|
+
*/
|
|
93
|
+
let brandsByPrototype = new WeakMap();
|
|
94
|
+
function prototypeChainHasBrand(proto, brand) {
|
|
95
|
+
let known = brandsByPrototype.get(proto);
|
|
96
|
+
if (!known)
|
|
97
|
+
brandsByPrototype.set(proto, (known = new Map()));
|
|
98
|
+
let has = known.get(brand);
|
|
99
|
+
if (has === undefined) {
|
|
100
|
+
has = false;
|
|
101
|
+
for (let p = proto; p; p = Object.getPrototypeOf(p)) {
|
|
102
|
+
if (Object.prototype.hasOwnProperty.call(p, brand)) {
|
|
103
|
+
has = true;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
known.set(brand, has);
|
|
85
108
|
}
|
|
86
|
-
return
|
|
109
|
+
return has;
|
|
87
110
|
}
|
|
88
111
|
/** The brand symbol for a class: `Symbol.for('<pkg>:<name>')`. */
|
|
89
112
|
export function linkedErrorBrand(pkg, name) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linkedError.js","sourceRoot":"","sources":["../../../src/utils/linkedError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,6EAA6E;AAC7E,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AASlE;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAuB,GAAM,EAAE,GAAW,EAAE,IAAY;IACtF,OAAO,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAA6B,GAAM,EAAE,GAAW,EAAE,IAAY;IAC5F,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,kBAAkB,EAAE,EAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAC,CAAC,CAAC;IACnF,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAC,CAAC,CAAC;IAC/E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAuB,GAAY,EAAE,GAAM;IACtE,IAAI,GAAG,YAAY,GAAG;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IACzF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC;QAAE,OAAO,KAAK,CAAC;IACjF,MAAM,KAAK,GAAI,GAAyC,CAAC,kBAAkB,CAAC,CAAC;IAC7E,OAAQ,GAA+B,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAI,KAAc,EAAE,GAAgB;IAClE,IAAI,KAAK,YAAY,GAAG;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/F,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC;QAAE,OAAO,KAAK,CAAC;IACjF,MAAM,KAAK,GAAI,GAAyC,CAAC,kBAAkB,CAAC,CAAC;IAC7E,KAAK,IAAI,KAAK,GAAG,
|
|
1
|
+
{"version":3,"file":"linkedError.js","sourceRoot":"","sources":["../../../src/utils/linkedError.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Error identity that survives a second copy of the module that defines the error.\n *\n * `err instanceof RemoteDatasetError` is false when the error was thrown by one copy of\n * `@_linked/server` and the class was imported from another: each copy has its own class.\n * A branded class instead carries a brand, `Symbol.for('<pkg>:<ClassName>')`, on its\n * prototype. Every copy of the class carries the same symbol, so {@link isLinkedError} can\n * recognise an error from any copy. The brand is read along the error's prototype chain, so a\n * subclass instance matches its base class, as with `instanceof`.\n *\n * The convention is the symbol keys, not this module: two copies of core brand and check\n * the same keys. See https://github.com/linked-fw/cli/blob/main/docs/architecture/shared-state-and-error-brands.md.\n */\n\n/** Static key on a branded class whose value is the class's brand symbol. */\nconst LINKED_ERROR_BRAND = Symbol.for('@_linked/core:errorBrand');\n\ntype ErrorClass = abstract new (...args: never[]) => Error;\n/**\n * Any class whose instances are `T`: abstract or not, whatever its constructor takes, and\n * also one whose constructor is `private` (which no `new (...) => T` type accepts).\n */\ntype AnyClass<T = unknown> = Function & {prototype: T};\n\n/**\n * Brand an error class so {@link isLinkedError} matches its instances from any copy of the\n * defining module. Call it once, right after the class declaration.\n *\n * @param Cls The error class.\n * @param pkg The defining package's npm name, e.g. `'@_linked/server'`.\n * @param name The class name. Passed explicitly because a minifier may rename the class.\n * @returns The class, for `export const X = brandLinkedError(class X ..., pkg, 'X')` use.\n */\nexport function brandLinkedError<C extends ErrorClass>(Cls: C, pkg: string, name: string): C {\n return brandLinkedClass(Cls, pkg, name);\n}\n\n/**\n * Brand any class so {@link isLinkedInstance} matches its instances from any copy of the\n * defining module: `brandLinkedError` for classes that are not errors. Call it once, right\n * after the class declaration. The brand is the same `Symbol.for('<pkg>:<name>')` an error\n * class gets, so a branded error is also matched by `isLinkedInstance`.\n *\n * @param Cls The class.\n * @param pkg The defining package's npm name, e.g. `'@_linked/core'`.\n * @param name The class name. Passed explicitly because a minifier may rename the class.\n * @returns The class.\n */\nexport function brandLinkedClass<C extends AnyClass<object>>(Cls: C, pkg: string, name: string): C {\n const brand = linkedErrorBrand(pkg, name);\n Object.defineProperty(Cls, LINKED_ERROR_BRAND, {value: brand, configurable: true});\n Object.defineProperty(Cls.prototype, brand, {value: true, configurable: true});\n brandsByPrototype = new WeakMap();\n return Cls;\n}\n\n/**\n * `err instanceof Cls`, extended to instances of `Cls` from another copy of its module.\n *\n * Falls back to plain `instanceof` for a class that is not branded. A subclass that is not\n * branded itself does not inherit its base's brand for this check: it would otherwise match\n * every instance of the base.\n */\nexport function isLinkedError<C extends ErrorClass>(err: unknown, Cls: C): err is InstanceType<C> {\n if (err instanceof Cls) return true;\n if (err === null || (typeof err !== 'object' && typeof err !== 'function')) return false;\n if (!Object.prototype.hasOwnProperty.call(Cls, LINKED_ERROR_BRAND)) return false;\n const brand = (Cls as unknown as Record<symbol, symbol>)[LINKED_ERROR_BRAND];\n return (err as Record<symbol, unknown>)[brand] === true;\n}\n\n/**\n * `value instanceof Cls`, extended to instances of `Cls` from another copy of its module.\n *\n * Use it for a value another package (or another copy of this one) may have made: a\n * `Shape`, `ShapeSet`, `QueryBuilder`, `PendingQueryContext`, `FieldSet`. It also answers\n * `Sub.prototype instanceof Cls` when passed `Sub.prototype`.\n *\n * The brand is looked up on the value's prototype chain, never read off the value itself,\n * so a proxy whose `get` trap guards unknown keys is not touched. Falls back to plain\n * `instanceof` for a class that is not branded; a subclass that is not branded itself does\n * not inherit its base's brand for this check.\n */\nexport function isLinkedInstance<T>(value: unknown, Cls: AnyClass<T>): value is T {\n if (value instanceof Cls) return true;\n if (value === null || (typeof value !== 'object' && typeof value !== 'function')) return false;\n if (!Object.prototype.hasOwnProperty.call(Cls, LINKED_ERROR_BRAND)) return false;\n const brand = (Cls as unknown as Record<symbol, symbol>)[LINKED_ERROR_BRAND];\n const proto = Object.getPrototypeOf(value);\n return proto !== null && prototypeChainHasBrand(proto, brand);\n}\n\n/**\n * Per prototype, whether its chain carries each brand asked about. Most checks are misses\n * (`isLinkedInstance(x, PendingQueryContext)` on every value a builder sees), and walking the\n * chain each time made query building measurably slower; with this a repeat check is one\n * WeakMap and one Map lookup. A memo, so per copy of this module. Cleared whenever this copy\n * brands a class, so a brand added after a lookup is never hidden by it.\n */\nlet brandsByPrototype = new WeakMap<object, Map<symbol, boolean>>();\n\nfunction prototypeChainHasBrand(proto: object, brand: symbol): boolean {\n let known = brandsByPrototype.get(proto);\n if (!known) brandsByPrototype.set(proto, (known = new Map()));\n let has = known.get(brand);\n if (has === undefined) {\n has = false;\n for (let p: object | null = proto; p; p = Object.getPrototypeOf(p)) {\n if (Object.prototype.hasOwnProperty.call(p, brand)) {\n has = true;\n break;\n }\n }\n known.set(brand, has);\n }\n return has;\n}\n\n/** The brand symbol for a class: `Symbol.for('<pkg>:<name>')`. */\nexport function linkedErrorBrand(pkg: string, name: string): symbol {\n return Symbol.for(`${pkg}:${name}`);\n}\n"]}
|