fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

7
node_modules/memize/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,7 @@
[The MIT License (MIT)](https://opensource.org/licenses/MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

79
node_modules/memize/README.md generated vendored Normal file
View File

@@ -0,0 +1,79 @@
Memize
======
Memize is a unabashedly-barebones memoization library with an aim toward speed.
Why use Memize?
- 🚀 **It's very fast.** Implemented as a least recently used (LRU) cache, it's heavily optimized for scenarios where the function is called repeatedly with the same arguments.
- 🔬 **It's tiny.** It weighs in at less than 0.3kb minified and gzipped, with no dependencies.
- 🔀 **It supports common arguments patterns**, including multiple arguments and non-primitive arguments (by reference).
## Example
Simply pass your original function as an argument to Memize. The return value is a new, memoized function.
```js
function fibonacci( number ) {
if ( number < 2 ) {
return number;
}
return fibonacci( number - 1 ) + fibonacci( number - 2 );
}
var memoizedFibonacci = memize( fibonacci );
memoizedFibonnaci( 8 ); // Invoked, cached, and returned
memoizedFibonnaci( 8 ); // Returned from cache
memoizedFibonnaci( 5 ); // Invoked, cached, and returned
memoizedFibonnaci( 8 ); // Returned from cache
```
## Installation
Using [npm](https://www.npmjs.com/) as a package manager:
```
npm install memize
```
## Usage
Memize accepts a function to be memoized, and returns a new memoized function.
```
memize( fn: Function, options: ?{
maxSize?: number
} ): Function
```
Optionally, pass an options object with `maxSize` defining the maximum size of the cache.
The memoized function exposes a `clear` function if you need to reset the cache:
```js
memoizedFn.clear();
```
## Benchmarks
Implemented as a least recently used (LRU), Memize is heavily optimized for scenarios where the function is called repeatedly with the same arguments. In these scenarios, Memize outperformed most other memoization libraries at the time of initial publication.
To learn more about these benchmarks, important caveats, and how to run them yourself, refer to [`benchmark/README.md`](./benchmark/README.md).
## How it works
If you haven't already, feel free to [glance over the source code](./index.js). The code is heavily commented and should help provide substance to the implementation concepts.
Memize creates a [last-in first-out stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) implemented as a [doubly linked list](https://en.wikipedia.org/wiki/Doubly_linked_list). It biases recent access favoring real-world scenarios where the function is subsequently invoked multiple times with the same arguments. The choice to implement as a linked list is due to dramatically better performance characteristics compared to `Array#unshift` for surfacing an entry to the head of the list ([jsperf](https://jsperf.com/array-unshift-linked-list)). A downside of linked lists is inability to efficiently access arbitrary indices, but iterating from the beginning of the cache list is optimized by guaranteeing the list is sorted by recent access / insertion.
Each node in the list tracks the original arguments as an array. This acts as a key of sorts, matching arguments of the current invocation by performing a shallow equality comparison on the two arrays. Other memoization implementations often use `JSON.stringify` to generate a string key for lookup in an object cache, but this benchmarks much slower than a shallow comparison ([jsperf](https://jsperf.com/lookup-json-stringify-vs-shallow-equality)).
Finally, special care is made toward treatment of `arguments` due to engine-specific deoptimizations which can occur in V8 via [arguments leaking](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments). Order is important here; we only create a shallow clone when necessary, after the cache has been checked, to avoid creating a clone unnecessarily if a cache entry exists. Looking at the code, you'd not be blamed for thinking that dropping the shallow clone would improve performance, but in fact it would _slow_ execution by approximately 60%. This is due to how the lingering `arguments` reference would carry over by reference ("leaks") in the node's `args` property. _**Update:** As of November 2019, engine improvements are such that `arguments` leaking does not have as dramatic an effect. However, my testing shows that the shallow clone still performs equal or better than referencing `arguments` directly, and as such the implementation has not been revised in order to achieve optimal performance in the most versions of V8._
## License
Copyright 2018-2020 Andrew Duthie
Released under the [MIT License](./LICENSE.md).

162
node_modules/memize/dist/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,162 @@
'use strict';
/**
* Memize options object.
*
* @typedef MemizeOptions
*
* @property {number} [maxSize] Maximum size of the cache.
*/
/**
* Internal cache entry.
*
* @typedef MemizeCacheNode
*
* @property {?MemizeCacheNode|undefined} [prev] Previous node.
* @property {?MemizeCacheNode|undefined} [next] Next node.
* @property {Array<*>} args Function arguments for cache
* entry.
* @property {*} val Function result.
*/
/**
* Properties of the enhanced function for controlling cache.
*
* @typedef MemizeMemoizedFunction
*
* @property {()=>void} clear Clear the cache.
*/
/**
* Accepts a function to be memoized, and returns a new memoized function, with
* optional options.
*
* @template {(...args: any[]) => any} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
*/
function memize(fn, options) {
var size = 0;
/** @type {?MemizeCacheNode|undefined} */
var head;
/** @type {?MemizeCacheNode|undefined} */
var tail;
options = options || {};
function memoized(/* ...args */) {
var node = head,
len = arguments.length,
args,
i;
searchCache: while (node) {
// Perform a shallow equality test to confirm that whether the node
// under test is a candidate for the arguments passed. Two arrays
// are shallowly equal if their length matches and each entry is
// strictly equal between the two sets. Avoid abstracting to a
// function which could incur an arguments leaking deoptimization.
// Check whether node arguments match arguments length
if (node.args.length !== arguments.length) {
node = node.next;
continue;
}
// Check whether node arguments match arguments values
for (i = 0; i < len; i++) {
if (node.args[i] !== arguments[i]) {
node = node.next;
continue searchCache;
}
}
// At this point we can assume we've found a match
// Surface matched node to head if not already
if (node !== head) {
// As tail, shift to previous. Must only shift if not also
// head, since if both head and tail, there is no previous.
if (node === tail) {
tail = node.prev;
}
// Adjust siblings to point to each other. If node was tail,
// this also handles new tail's empty `next` assignment.
/** @type {MemizeCacheNode} */ (node.prev).next = node.next;
if (node.next) {
node.next.prev = node.prev;
}
node.next = head;
node.prev = null;
/** @type {MemizeCacheNode} */ (head).prev = node;
head = node;
}
// Return immediately
return node.val;
}
// No cached value found. Continue to insertion phase:
// Create a copy of arguments (avoid leaking deoptimization)
args = new Array(len);
for (i = 0; i < len; i++) {
args[i] = arguments[i];
}
node = {
args: args,
// Generate the result from original function
val: fn.apply(null, args),
};
// Don't need to check whether node is already head, since it would
// have been returned above already if it was
// Shift existing head down list
if (head) {
head.prev = node;
node.next = head;
} else {
// If no head, follows that there's no tail (at initial or reset)
tail = node;
}
// Trim tail if we're reached max size and are pending cache insertion
if (size === /** @type {MemizeOptions} */ (options).maxSize) {
tail = /** @type {MemizeCacheNode} */ (tail).prev;
/** @type {MemizeCacheNode} */ (tail).next = null;
} else {
size++;
}
head = node;
return node.val;
}
memoized.clear = function () {
head = null;
tail = null;
size = 0;
};
// Ignore reason: There's not a clear solution to create an intersection of
// the function with additional properties, where the goal is to retain the
// function signature of the incoming argument and add control properties
// on the return value.
// @ts-ignore
return memoized;
}
module.exports = memize;

81
node_modules/memize/dist/index.d.cts generated vendored Normal file
View File

@@ -0,0 +1,81 @@
export = memize;
/**
* Memize options object.
*
* @typedef MemizeOptions
*
* @property {number} [maxSize] Maximum size of the cache.
*/
/**
* Internal cache entry.
*
* @typedef MemizeCacheNode
*
* @property {?MemizeCacheNode|undefined} [prev] Previous node.
* @property {?MemizeCacheNode|undefined} [next] Next node.
* @property {Array<*>} args Function arguments for cache
* entry.
* @property {*} val Function result.
*/
/**
* Properties of the enhanced function for controlling cache.
*
* @typedef MemizeMemoizedFunction
*
* @property {()=>void} clear Clear the cache.
*/
/**
* Accepts a function to be memoized, and returns a new memoized function, with
* optional options.
*
* @template {(...args: any[]) => any} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
*/
declare function memize<F extends (...args: any[]) => any>(fn: F, options?: MemizeOptions | undefined): ((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction;
declare namespace memize {
export { MemizeOptions, MemizeCacheNode, MemizeMemoizedFunction };
}
/**
* Memize options object.
*/
type MemizeOptions = {
/**
* Maximum size of the cache.
*/
maxSize?: number | undefined;
};
/**
* Properties of the enhanced function for controlling cache.
*/
type MemizeMemoizedFunction = {
/**
* Clear the cache.
*/
clear: () => void;
};
/**
* Internal cache entry.
*/
type MemizeCacheNode = {
/**
* Previous node.
*/
prev?: (MemizeCacheNode | undefined) | null;
/**
* Next node.
*/
next?: (MemizeCacheNode | undefined) | null;
/**
* Function arguments for cache
* entry.
*/
args: Array<any>;
/**
* Function result.
*/
val: any;
};

77
node_modules/memize/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,77 @@
/**
* Memize options object.
*
* @typedef MemizeOptions
*
* @property {number} [maxSize] Maximum size of the cache.
*/
/**
* Internal cache entry.
*
* @typedef MemizeCacheNode
*
* @property {?MemizeCacheNode|undefined} [prev] Previous node.
* @property {?MemizeCacheNode|undefined} [next] Next node.
* @property {Array<*>} args Function arguments for cache
* entry.
* @property {*} val Function result.
*/
/**
* Properties of the enhanced function for controlling cache.
*
* @typedef MemizeMemoizedFunction
*
* @property {()=>void} clear Clear the cache.
*/
/**
* Accepts a function to be memoized, and returns a new memoized function, with
* optional options.
*
* @template {(...args: any[]) => any} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
*/
export default function memize<F extends (...args: any[]) => any>(fn: F, options?: MemizeOptions | undefined): ((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction;
/**
* Memize options object.
*/
export type MemizeOptions = {
/**
* Maximum size of the cache.
*/
maxSize?: number | undefined;
};
/**
* Internal cache entry.
*/
export type MemizeCacheNode = {
/**
* Previous node.
*/
prev?: (MemizeCacheNode | undefined) | null;
/**
* Next node.
*/
next?: (MemizeCacheNode | undefined) | null;
/**
* Function arguments for cache
* entry.
*/
args: Array<any>;
/**
* Function result.
*/
val: any;
};
/**
* Properties of the enhanced function for controlling cache.
*/
export type MemizeMemoizedFunction = {
/**
* Clear the cache.
*/
clear: () => void;
};

160
node_modules/memize/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,160 @@
/**
* Memize options object.
*
* @typedef MemizeOptions
*
* @property {number} [maxSize] Maximum size of the cache.
*/
/**
* Internal cache entry.
*
* @typedef MemizeCacheNode
*
* @property {?MemizeCacheNode|undefined} [prev] Previous node.
* @property {?MemizeCacheNode|undefined} [next] Next node.
* @property {Array<*>} args Function arguments for cache
* entry.
* @property {*} val Function result.
*/
/**
* Properties of the enhanced function for controlling cache.
*
* @typedef MemizeMemoizedFunction
*
* @property {()=>void} clear Clear the cache.
*/
/**
* Accepts a function to be memoized, and returns a new memoized function, with
* optional options.
*
* @template {(...args: any[]) => any} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
*/
function memize(fn, options) {
var size = 0;
/** @type {?MemizeCacheNode|undefined} */
var head;
/** @type {?MemizeCacheNode|undefined} */
var tail;
options = options || {};
function memoized(/* ...args */) {
var node = head,
len = arguments.length,
args,
i;
searchCache: while (node) {
// Perform a shallow equality test to confirm that whether the node
// under test is a candidate for the arguments passed. Two arrays
// are shallowly equal if their length matches and each entry is
// strictly equal between the two sets. Avoid abstracting to a
// function which could incur an arguments leaking deoptimization.
// Check whether node arguments match arguments length
if (node.args.length !== arguments.length) {
node = node.next;
continue;
}
// Check whether node arguments match arguments values
for (i = 0; i < len; i++) {
if (node.args[i] !== arguments[i]) {
node = node.next;
continue searchCache;
}
}
// At this point we can assume we've found a match
// Surface matched node to head if not already
if (node !== head) {
// As tail, shift to previous. Must only shift if not also
// head, since if both head and tail, there is no previous.
if (node === tail) {
tail = node.prev;
}
// Adjust siblings to point to each other. If node was tail,
// this also handles new tail's empty `next` assignment.
/** @type {MemizeCacheNode} */ (node.prev).next = node.next;
if (node.next) {
node.next.prev = node.prev;
}
node.next = head;
node.prev = null;
/** @type {MemizeCacheNode} */ (head).prev = node;
head = node;
}
// Return immediately
return node.val;
}
// No cached value found. Continue to insertion phase:
// Create a copy of arguments (avoid leaking deoptimization)
args = new Array(len);
for (i = 0; i < len; i++) {
args[i] = arguments[i];
}
node = {
args: args,
// Generate the result from original function
val: fn.apply(null, args),
};
// Don't need to check whether node is already head, since it would
// have been returned above already if it was
// Shift existing head down list
if (head) {
head.prev = node;
node.next = head;
} else {
// If no head, follows that there's no tail (at initial or reset)
tail = node;
}
// Trim tail if we're reached max size and are pending cache insertion
if (size === /** @type {MemizeOptions} */ (options).maxSize) {
tail = /** @type {MemizeCacheNode} */ (tail).prev;
/** @type {MemizeCacheNode} */ (tail).next = null;
} else {
size++;
}
head = node;
return node.val;
}
memoized.clear = function () {
head = null;
tail = null;
size = 0;
};
// Ignore reason: There's not a clear solution to create an intersection of
// the function with additional properties, where the goal is to retain the
// function signature of the incoming argument and add control properties
// on the return value.
// @ts-ignore
return memoized;
}
export { memize as default };

61
node_modules/memize/package.json generated vendored Normal file
View File

@@ -0,0 +1,61 @@
{
"name": "memize",
"version": "2.1.1",
"description": "Unabashedly-barebones memoization library with an aim toward speed",
"type": "module",
"main": "dist/index.js",
"exports": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"scripts": {
"build": "npm run build:bundle && npm run build:types",
"build:bundle": "rollup -c rollup.config.js",
"build:types": "tsc -b tsconfig.decl.json && tsc -b tsconfig.decl.cts.json",
"test:unit": "NODE_ENV=test mocha",
"test:lint": "eslint .",
"test:types": "tsc -b",
"test": "npm run test:unit && npm run test:lint && npm run test:types",
"prebenchmark": "npm install --no-save benchmark memoizee moize ramda underscore lodash fast-memoize lru-memoize memoizejs memoizerific cli-table2 ora",
"benchmark": "node benchmark",
"prepublishOnly": "npm test && npm run build"
},
"files": [
"dist"
],
"keywords": [
"memoize",
"memoization",
"memoisation",
"cache"
],
"repository": {
"type": "git",
"url": "https://github.com/aduth/memize.git"
},
"bugs": {
"url": "https://github.com/aduth/memize/issues"
},
"author": {
"name": "Andrew Duthie",
"email": "andrew@andrewduthie.com",
"url": "https://andrewduthie.com"
},
"license": "MIT",
"devDependencies": {
"@aduth/eslint-config": "^4.4.1",
"@rollup/plugin-replace": "^5.0.2",
"@types/chai": "^4.3.5",
"@types/mocha": "^10.0.1",
"@types/node": "^20.1.3",
"chai": "^4.3.7",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"rollup": "^3.21.6",
"sinon": "^15.0.4",
"typescript": "^5.0.4"
}
}