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

15
node_modules/npm-packlist/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

146
node_modules/npm-packlist/README.md generated vendored Normal file
View File

@@ -0,0 +1,146 @@
# npm-packlist
[![Build Status](https://travis-ci.com/npm/npm-packlist.svg?token=hHeDp9pQmz9kvsgRNVHy&branch=master)](https://travis-ci.com/npm/npm-packlist)
Get a list of the files to add from a folder into an npm package.
These can be handed to [tar](http://npm.im/tar) like so to make an npm
package tarball:
```js
const packlist = require('npm-packlist')
const tar = require('tar')
const packageDir = '/path/to/package'
const packageTarball = '/path/to/package.tgz'
packlist({ path: packageDir })
.then(files => tar.create({
prefix: 'package/',
cwd: packageDir,
file: packageTarball,
gzip: true
}, files))
.then(_ => {
// tarball has been created, continue with your day
})
```
This uses the following rules:
1. If a `package.json` file is found, and it has a `files` list,
then ignore everything that isn't in `files`. Always include the
readme, license, notice, changes, changelog, and history files, if
they exist, and the package.json file itself.
2. If there's no `package.json` file (or it has no `files` list), and
there is a `.npmignore` file, then ignore all the files in the
`.npmignore` file.
3. If there's no `package.json` with a `files` list, and there's no
`.npmignore` file, but there is a `.gitignore` file, then ignore
all the files in the `.gitignore` file.
4. Everything in the root `node_modules` is ignored, unless it's a
bundled dependency. If it IS a bundled dependency, and it's a
symbolic link, then the target of the link is included, not the
symlink itself.
4. Unless they're explicitly included (by being in a `files` list, or
a `!negated` rule in a relevant `.npmignore` or `.gitignore`),
always ignore certain common cruft files:
1. .npmignore and .gitignore files (their effect is in the package
already, there's no need to include them in the package)
2. editor junk like `.*.swp`, `._*` and `.*.orig` files
3. `.npmrc` files (these may contain private configs)
4. The `node_modules/.bin` folder
5. Waf and gyp cruft like `/build/config.gypi` and `.lock-wscript`
6. Darwin's `.DS_Store` files because wtf are those even
7. `npm-debug.log` files at the root of a project
You can explicitly re-include any of these with a `files` list in
`package.json` or a negated ignore file rule.
Only the `package.json` file in the very root of the project is ever
inspected for a `files` list. Below the top level of the root package,
`package.json` is treated as just another file, and no package-specific
semantics are applied.
### Interaction between `package.json` and `.npmignore` rules
For simplicity, it is best to use _either_ a `files` list in `package.json`
_or_ a `.npmignore` file, and not both. If you only use one of these
methods, you can skip this documentation section.
The `files` list in `package.json` is used to direct the exploration of the
tree. In other words, that's all the walker will ever look at when
exploring that level.
In some cases this can lead to a `.npmignore` file being ignored. If a
_directory_ is listed in `files`, then any rules in a root or nested
`.npmignore` files will be honored.
For example, with this package.json:
```json
{
"files": [ "dir" ]
}
```
a `.npmignore` file at `dir/.npmignore` (and any subsequent
sub-directories) will be honored. However, a `.npmignore` at the root
level will be skipped.
Conversely, with this package.json:
```
{
"files": ["dir/subdir"]
}
```
a `.npmignore` file at `dir/.npmignore` will not be honored.
Any specific file matched by a glob or filename in the package.json `files`
list will be included, and cannot be excluded by any `.npmignore` files in
nested directories, or by a `.npmignore` file in the root package
directory, unless that root `.npmignore` file is also in the `files` list.
The previous (v1) implementation used in npm 6 and below treated
`package.json` as a special sort of "reverse ignore" file. That is, it was
parsed and handled as if it was a `.npmignore` file with `!` prepended to
all of the globs in the `files` list. In order to include children of a
directory listed in `files`, they would _also_ have `/**` appended to them.
This is tricky to explain, but is a significant improvement over the
previous (v1) implementation used in npm 6 and below, with the following
beneficial properties:
- If you have `{"files":["lib"]}` in `package.json`, then the walker will
still ignore files such as `lib/.DS_Store` and `lib/.foo.swp`. The
previous implementation would include these files, as they'd be matched
by the computed `!lib/**` ignore rule.
- If you have `{"files":["lib/a.js","lib/b.js"]}` in `package.json`, and a
`lib/.npmignore` containing `a.js`, then the walker will still include
the two files indicated in `package.json`, and ignore the
`lib/.npmignore` file. The previous implementation would mark these
files for inclusion, but then _exclude_ them when it came to the nested
`.npmignore` file. (Ignore file semantics dictate that a "closer" ignore
file always takes precedence.)
- A file in `lib/pkg-template/package.json` will be included, and its
`files` list will not have any bearing on other files being included or
skipped. When treating `package.json` as just Yet Another ignore file,
this was not the case, leading to difficulty for modules that aim to
initialize a project.
In general, this walk should work as a reasonable developer would expect.
Matching human expectation is tricky business, and if you find cases where
it violates those expectations, [please let us
know](https://github.com/npm/npm-packlist/issues).
## API
Same API as [ignore-walk](http://npm.im/ignore-walk), just hard-coded
file list and rule sets.
The `Walker` and `WalkerSync` classes take a `bundled` argument, which
is a list of package names to include from node_modules. When calling
the top-level `packlist()` and `packlist.sync()` functions, this
module calls into `npm-bundled` directly.

25
node_modules/npm-packlist/bin/index.js generated vendored Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env node
const dirs = []
let doSort = false
process.argv.slice(2).forEach(arg => {
if (arg === '-h' || arg === '--help') {
console.log('usage: npm-packlist [-s --sort] [directory, directory, ...]')
process.exit(0)
} else if (arg === '-s' || arg === '--sort')
doSort = true
else
dirs.push(arg)
})
const sort = list => doSort ? list.sort((a, b) => a.localeCompare(b, 'en')) : list
const packlist = require('../')
if (!dirs.length)
console.log(sort(packlist.sync({ path: process.cwd() })).join('\n'))
else {
dirs.forEach(path => {
console.log(`> ${path}`)
console.log(sort(packlist.sync({ path })).join('\n'))
})
}

481
node_modules/npm-packlist/index.js generated vendored Normal file
View File

@@ -0,0 +1,481 @@
'use strict'
// Do a two-pass walk, first to get the list of packages that need to be
// bundled, then again to get the actual files and folders.
// Keep a cache of node_modules content and package.json data, so that the
// second walk doesn't have to re-do all the same work.
const bundleWalk = require('npm-bundled')
const BundleWalker = bundleWalk.BundleWalker
const BundleWalkerSync = bundleWalk.BundleWalkerSync
const ignoreWalk = require('ignore-walk')
const IgnoreWalker = ignoreWalk.Walker
const IgnoreWalkerSync = ignoreWalk.WalkerSync
const rootBuiltinRules = Symbol('root-builtin-rules')
const packageNecessaryRules = Symbol('package-necessary-rules')
const path = require('path')
const normalizePackageBin = require('npm-normalize-package-bin')
// Weird side-effect of this: a readme (etc) file will be included
// if it exists anywhere within a folder with a package.json file.
// The original intent was only to include these files in the root,
// but now users in the wild are dependent on that behavior for
// localized documentation and other use cases. Adding a `/` to
// these rules, while tempting and arguably more "correct", is a
// significant change that will break existing use cases.
const packageMustHaveFileNames = 'readme|copying|license|licence'
const packageMustHaves = `@(${packageMustHaveFileNames}){,.*[^~$]}`
const packageMustHavesRE = new RegExp(`^(${packageMustHaveFileNames})(\\..*[^~$])?$`, 'i')
const fs = require('fs')
const glob = require('glob')
const defaultRules = [
'.npmignore',
'.gitignore',
'**/.git',
'**/.svn',
'**/.hg',
'**/CVS',
'**/.git/**',
'**/.svn/**',
'**/.hg/**',
'**/CVS/**',
'/.lock-wscript',
'/.wafpickle-*',
'/build/config.gypi',
'npm-debug.log',
'**/.npmrc',
'.*.swp',
'.DS_Store',
'**/.DS_Store/**',
'._*',
'**/._*/**',
'*.orig',
'/package-lock.json',
'/yarn.lock',
'/archived-packages/**',
]
// There may be others, but :?|<> are handled by node-tar
const nameIsBadForWindows = file => /\*/.test(file)
// a decorator that applies our custom rules to an ignore walker
const npmWalker = Class => class Walker extends Class {
constructor (opt) {
opt = opt || {}
// the order in which rules are applied.
opt.ignoreFiles = [
rootBuiltinRules,
'package.json',
'.npmignore',
'.gitignore',
packageNecessaryRules,
]
opt.includeEmpty = false
opt.path = opt.path || process.cwd()
// only follow links in the root node_modules folder, because if those
// folders are included, it's because they're bundled, and bundles
// should include the contents, not the symlinks themselves.
// This regexp tests to see that we're either a node_modules folder,
// or a @scope within a node_modules folder, in the root's node_modules
// hierarchy (ie, not in test/foo/node_modules/ or something).
const followRe = /^(?:\/node_modules\/(?:@[^/]+\/[^/]+|[^/]+)\/)*\/node_modules(?:\/@[^/]+)?$/
const rootPath = opt.parent ? opt.parent.root : opt.path
const followTestPath = opt.path.replace(/\\/g, '/').substr(rootPath.length)
opt.follow = followRe.test(followTestPath)
super(opt)
// ignore a bunch of things by default at the root level.
// also ignore anything in the main project node_modules hierarchy,
// except bundled dependencies
if (this.isProject) {
this.bundled = opt.bundled || []
this.bundledScopes = Array.from(new Set(
this.bundled.filter(f => /^@/.test(f))
.map(f => f.split('/')[0])))
const rules = defaultRules.join('\n') + '\n'
this.packageJsonCache = this.parent ? this.parent.packageJsonCache
: (opt.packageJsonCache || new Map())
super.onReadIgnoreFile(rootBuiltinRules, rules, _ => _)
} else {
this.bundled = []
this.bundledScopes = []
this.packageJsonCache = this.parent.packageJsonCache
}
}
get isProject () {
return !this.parent || this.parent.follow && this.isSymbolicLink
}
onReaddir (entries) {
if (this.isProject) {
entries = entries.filter(e =>
e !== '.git' &&
!(e === 'node_modules' && this.bundled.length === 0)
)
}
// if we have a package.json, then look in it for 'files'
// we _only_ do this in the root project, not bundled deps
// or other random folders. Bundled deps are always assumed
// to be in the state the user wants to include them, and
// a package.json somewhere else might be a template or
// test or something else entirely.
if (!this.isProject || !entries.includes('package.json')) {
return super.onReaddir(entries)
}
// when the cache has been seeded with the root manifest,
// we must respect that (it may differ from the filesystem)
const ig = path.resolve(this.path, 'package.json')
if (this.packageJsonCache.has(ig)) {
const pkg = this.packageJsonCache.get(ig)
// fall back to filesystem when seeded manifest is invalid
if (!pkg || typeof pkg !== 'object') {
return this.readPackageJson(entries)
}
// feels wonky, but this ensures package bin is _always_
// normalized, as well as guarding against invalid JSON
return this.getPackageFiles(entries, JSON.stringify(pkg))
}
this.readPackageJson(entries)
}
onReadPackageJson (entries, er, pkg) {
if (er) {
this.emit('error', er)
} else {
this.getPackageFiles(entries, pkg)
}
}
mustHaveFilesFromPackage (pkg) {
const files = []
if (pkg.browser) {
files.push('/' + pkg.browser)
}
if (pkg.main) {
files.push('/' + pkg.main)
}
if (pkg.bin) {
// always an object because normalized already
for (const key in pkg.bin) {
files.push('/' + pkg.bin[key])
}
}
files.push(
'/package.json',
'/npm-shrinkwrap.json',
'!/package-lock.json',
packageMustHaves
)
return files
}
getPackageFiles (entries, pkg) {
try {
// XXX this could be changed to use read-package-json-fast
// which handles the normalizing of bins for us, and simplifies
// the test for bundleDependencies and bundledDependencies later.
// HOWEVER if we do this, we need to be sure that we're careful
// about what we write back out since rpj-fast removes some fields
// that the user likely wants to keep. it also would add a second
// file read that we would want to optimize away.
pkg = normalizePackageBin(JSON.parse(pkg.toString()))
} catch (er) {
// not actually a valid package.json
return super.onReaddir(entries)
}
const ig = path.resolve(this.path, 'package.json')
this.packageJsonCache.set(ig, pkg)
// no files list, just return the normal readdir() result
if (!Array.isArray(pkg.files)) {
return super.onReaddir(entries)
}
pkg.files.push(...this.mustHaveFilesFromPackage(pkg))
// If the package has a files list, then it's unlikely to include
// node_modules, because why would you do that? but since we use
// the files list as the effective readdir result, that means it
// looks like we don't have a node_modules folder at all unless we
// include it here.
if ((pkg.bundleDependencies || pkg.bundledDependencies) && entries.includes('node_modules')) {
pkg.files.push('node_modules')
}
const patterns = Array.from(new Set(pkg.files)).reduce((set, pattern) => {
const excl = pattern.match(/^!+/)
if (excl) {
pattern = pattern.substr(excl[0].length)
}
// strip off any / from the start of the pattern. /foo => foo
pattern = pattern.replace(/^\/+/, '')
// an odd number of ! means a negated pattern. !!foo ==> foo
const negate = excl && excl[0].length % 2 === 1
set.push({ pattern, negate })
return set
}, [])
let n = patterns.length
const set = new Set()
const negates = new Set()
const results = []
const then = (pattern, negate, er, fileList, i) => {
if (er) {
return this.emit('error', er)
}
results[i] = { negate, fileList }
if (--n === 0) {
processResults(results)
}
}
const processResults = results => {
for (const {negate, fileList} of results) {
if (negate) {
fileList.forEach(f => {
f = f.replace(/\/+$/, '')
set.delete(f)
negates.add(f)
})
} else {
fileList.forEach(f => {
f = f.replace(/\/+$/, '')
set.add(f)
negates.delete(f)
})
}
}
const list = Array.from(set)
// replace the files array with our computed explicit set
pkg.files = list.concat(Array.from(negates).map(f => '!' + f))
const rdResult = Array.from(new Set(
list.map(f => f.replace(/^\/+/, ''))
))
super.onReaddir(rdResult)
}
// maintain the index so that we process them in-order only once all
// are completed, otherwise the parallelism messes things up, since a
// glob like **/*.js will always be slower than a subsequent !foo.js
patterns.forEach(({pattern, negate}, i) =>
this.globFiles(pattern, (er, res) => then(pattern, negate, er, res, i)))
}
filterEntry (entry, partial) {
// get the partial path from the root of the walk
const p = this.path.substr(this.root.length + 1)
const pkgre = /^node_modules\/(@[^/]+\/?[^/]+|[^/]+)(\/.*)?$/
const { isProject } = this
const pkg = isProject && pkgre.test(entry) ?
entry.replace(pkgre, '$1') : null
const rootNM = isProject && entry === 'node_modules'
const rootPJ = isProject && entry === 'package.json'
return (
// if we're in a bundled package, check with the parent.
/^node_modules($|\/)/i.test(p) && !this.isProject ? this.parent.filterEntry(
this.basename + '/' + entry, partial)
// if package is bundled, all files included
// also include @scope dirs for bundled scoped deps
// they'll be ignored if no files end up in them.
// However, this only matters if we're in the root.
// node_modules folders elsewhere, like lib/node_modules,
// should be included normally unless ignored.
: pkg ? this.bundled.indexOf(pkg) !== -1 ||
this.bundledScopes.indexOf(pkg) !== -1
// only walk top node_modules if we want to bundle something
: rootNM ? !!this.bundled.length
// always include package.json at the root.
: rootPJ ? true
// always include readmes etc in any included dir
: packageMustHavesRE.test(entry) ? true
// npm-shrinkwrap and package.json always included in the root pkg
: isProject && (entry === 'npm-shrinkwrap.json' || entry === 'package.json')
? true
// package-lock never included
: isProject && entry === 'package-lock.json' ? false
// otherwise, follow ignore-walk's logic
: super.filterEntry(entry, partial)
)
}
filterEntries () {
if (this.ignoreRules['.npmignore']) {
this.ignoreRules['.gitignore'] = null
}
this.filterEntries = super.filterEntries
super.filterEntries()
}
addIgnoreFile (file, then) {
const ig = path.resolve(this.path, file)
if (file === 'package.json' && !this.isProject) {
then()
} else if (this.packageJsonCache.has(ig)) {
this.onPackageJson(ig, this.packageJsonCache.get(ig), then)
} else {
super.addIgnoreFile(file, then)
}
}
onPackageJson (ig, pkg, then) {
this.packageJsonCache.set(ig, pkg)
if (Array.isArray(pkg.files)) {
// in this case we already included all the must-haves
super.onReadIgnoreFile('package.json', pkg.files.map(
f => '!' + f
).join('\n') + '\n', then)
} else {
// if there's a bin, browser or main, make sure we don't ignore it
// also, don't ignore the package.json itself, or any files that
// must be included in the package.
const rules = this.mustHaveFilesFromPackage(pkg).map(f => `!${f}`)
const data = rules.join('\n') + '\n'
super.onReadIgnoreFile(packageNecessaryRules, data, then)
}
}
// override parent stat function to completely skip any filenames
// that will break windows entirely.
// XXX(isaacs) Next major version should make this an error instead.
stat ({ entry, file, dir }, then) {
if (nameIsBadForWindows(entry)) {
then()
} else {
super.stat({ entry, file, dir }, then)
}
}
// override parent onstat function to nix all symlinks, other than
// those coming out of the followed bundled symlink deps
onstat ({ st, entry, file, dir, isSymbolicLink }, then) {
if (st.isSymbolicLink()) {
then()
} else {
super.onstat({ st, entry, file, dir, isSymbolicLink }, then)
}
}
onReadIgnoreFile (file, data, then) {
if (file === 'package.json') {
try {
const ig = path.resolve(this.path, file)
this.onPackageJson(ig, JSON.parse(data), then)
} catch (er) {
// ignore package.json files that are not json
then()
}
} else {
super.onReadIgnoreFile(file, data, then)
}
}
sort (a, b) {
return sort(a, b)
}
}
class Walker extends npmWalker(IgnoreWalker) {
globFiles (pattern, cb) {
glob(pattern, { dot: true, cwd: this.path, nocase: true }, cb)
}
readPackageJson (entries) {
fs.readFile(this.path + '/package.json', (er, pkg) =>
this.onReadPackageJson(entries, er, pkg))
}
walker (entry, opt, then) {
new Walker(this.walkerOpt(entry, opt)).on('done', then).start()
}
}
class WalkerSync extends npmWalker(IgnoreWalkerSync) {
globFiles (pattern, cb) {
cb(null, glob.sync(pattern, { dot: true, cwd: this.path, nocase: true }))
}
readPackageJson (entries) {
const p = this.path + '/package.json'
try {
this.onReadPackageJson(entries, null, fs.readFileSync(p))
} catch (er) {
this.onReadPackageJson(entries, er)
}
}
walker (entry, opt, then) {
new WalkerSync(this.walkerOpt(entry, opt)).start()
then()
}
}
const walk = (options, callback) => {
options = options || {}
const p = new Promise((resolve, reject) => {
const bw = new BundleWalker(options)
bw.on('done', bundled => {
options.bundled = bundled
options.packageJsonCache = bw.packageJsonCache
new Walker(options).on('done', resolve).on('error', reject).start()
})
bw.start()
})
return callback ? p.then(res => callback(null, res), callback) : p
}
const walkSync = options => {
options = options || {}
const bw = new BundleWalkerSync(options).start()
options.bundled = bw.result
options.packageJsonCache = bw.packageJsonCache
const walker = new WalkerSync(options)
walker.start()
return walker.result
}
// optimize for compressibility
// extname, then basename, then locale alphabetically
// https://twitter.com/isntitvacant/status/1131094910923231232
const sort = (a, b) => {
const exta = path.extname(a).toLowerCase()
const extb = path.extname(b).toLowerCase()
const basea = path.basename(a).toLowerCase()
const baseb = path.basename(b).toLowerCase()
return exta.localeCompare(extb, 'en') ||
basea.localeCompare(baseb, 'en') ||
a.localeCompare(b, 'en')
}
module.exports = walk
walk.sync = walkSync
walk.Walker = Walker
walk.WalkerSync = WalkerSync

59
node_modules/npm-packlist/package.json generated vendored Normal file
View File

@@ -0,0 +1,59 @@
{
"name": "npm-packlist",
"version": "3.0.0",
"description": "Get a list of the files to add from a folder into an npm package",
"directories": {
"test": "test"
},
"main": "index.js",
"dependencies": {
"glob": "^7.1.6",
"ignore-walk": "^4.0.1",
"npm-bundled": "^1.1.1",
"npm-normalize-package-bin": "^1.0.1"
},
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC",
"files": [
"bin/index.js",
"index.js"
],
"devDependencies": {
"@npmcli/lint": "^1.0.2",
"mutate-fs": "^2.1.1",
"tap": "^15.0.6"
},
"scripts": {
"test": "tap",
"posttest": "npm run lint --",
"snap": "tap",
"postsnap": "npm run lintfix --",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"eslint": "eslint",
"lint": "npm run npmclilint -- \"*.*js\" \"test/**/*.*js\"",
"lintfix": "npm run lint -- --fix",
"npmclilint": "npmcli-lint"
},
"repository": {
"type": "git",
"url": "git+https://github.com/npm/npm-packlist.git"
},
"tap": {
"test-env": [
"LC_ALL=sk"
],
"check-coverage": true,
"nyc-arg": [
"--include=index.js",
"--include=bin/index.js"
]
},
"bin": {
"npm-packlist": "bin/index.js"
},
"engines": {
"node": ">=10"
}
}