Adds @xuqm/h5-sdk/private entry point with JSON-based initialization, feature gating, and error codes for private deployment scenarios. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
177 行
8.4 KiB
JavaScript
177 行
8.4 KiB
JavaScript
"use strict";
|
|
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
// See LICENSE in the project root for license information.
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || (function () {
|
|
var ownKeys = function(o) {
|
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
var ar = [];
|
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
return ar;
|
|
};
|
|
return ownKeys(o);
|
|
};
|
|
return function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.RealNodeModulePathResolver = void 0;
|
|
const nodeFs = __importStar(require("node:fs"));
|
|
const nodePath = __importStar(require("node:path"));
|
|
/**
|
|
* This class encapsulates a caching resolver for symlinks in node_modules directories.
|
|
* It assumes that the only symlinks that exist in input paths are those that correspond to
|
|
* npm packages.
|
|
*
|
|
* @remarks
|
|
* In a repository with a symlinked node_modules installation, some symbolic links need to be mapped for
|
|
* node module resolution to produce correct results. However, calling `fs.realpathSync.native` on every path,
|
|
* as is commonly done by most resolvers, involves an enormous number of file system operations (for reference,
|
|
* each invocation of `fs.realpathSync.native` involves a series of `fs.readlinkSync` calls, up to one for each
|
|
* path segment in the input).
|
|
*
|
|
* @public
|
|
*/
|
|
class RealNodeModulePathResolver {
|
|
constructor(options = {}) {
|
|
const { fs: { lstatSync = nodeFs.lstatSync, readlinkSync = nodeFs.readlinkSync } = nodeFs, path: { isAbsolute = nodePath.isAbsolute, join = nodePath.join, resolve = nodePath.resolve, sep = nodePath.sep } = nodePath, ignoreMissingPaths = false } = options;
|
|
const cache = (this._cache = new Map());
|
|
this._errorCache = new Map();
|
|
this._fs = {
|
|
lstatSync,
|
|
readlinkSync
|
|
};
|
|
this._path = {
|
|
isAbsolute,
|
|
join,
|
|
resolve,
|
|
sep
|
|
};
|
|
this._lstatOptions = {
|
|
throwIfNoEntry: !ignoreMissingPaths
|
|
};
|
|
const nodeModulesToken = `${sep}node_modules${sep}`;
|
|
const self = this;
|
|
function realNodeModulePathInternal(input) {
|
|
// Find the last node_modules path segment
|
|
const nodeModulesIndex = input.lastIndexOf(nodeModulesToken);
|
|
if (nodeModulesIndex < 0) {
|
|
// No node_modules in path, so we assume it is already the real path
|
|
return input;
|
|
}
|
|
// First assume that the next path segment after node_modules is a symlink
|
|
let linkStart = nodeModulesIndex + nodeModulesToken.length - 1;
|
|
let linkEnd = input.indexOf(sep, linkStart + 1);
|
|
// If the path segment starts with a '@', then it is a scoped package
|
|
const isScoped = input.charAt(linkStart + 1) === '@';
|
|
if (isScoped) {
|
|
// For a scoped package, the scope is an ordinary directory, so we need to find the next path segment
|
|
if (linkEnd < 0) {
|
|
// Symlink missing, so see if anything before the last node_modules needs resolving,
|
|
// and preserve the rest of the path
|
|
return join(realNodeModulePathInternal(input.slice(0, nodeModulesIndex)), input.slice(nodeModulesIndex + 1),
|
|
// Joining to `.` will clean up any extraneous trailing slashes
|
|
'.');
|
|
}
|
|
linkStart = linkEnd;
|
|
linkEnd = input.indexOf(sep, linkStart + 1);
|
|
}
|
|
// No trailing separator, so the link is the last path segment
|
|
if (linkEnd < 0) {
|
|
linkEnd = input.length;
|
|
}
|
|
const linkCandidate = input.slice(0, linkEnd);
|
|
// Check if the link is a symlink
|
|
const linkTarget = self._tryReadLink(linkCandidate);
|
|
if (linkTarget && isAbsolute(linkTarget)) {
|
|
// Absolute path, combine the link target with any remaining path segments
|
|
// Cache the resolution to avoid the readlink call in subsequent calls
|
|
cache.set(linkCandidate, linkTarget);
|
|
cache.set(linkTarget, linkTarget);
|
|
// Joining to `.` will clean up any extraneous trailing slashes
|
|
return join(linkTarget, input.slice(linkEnd + 1), '.');
|
|
}
|
|
// Relative path or does not exist
|
|
// Either way, the path before the last node_modules could itself be in a node_modules folder
|
|
// So resolve the base path to find out what paths are relative to
|
|
const realpathBeforeNodeModules = realNodeModulePathInternal(input.slice(0, nodeModulesIndex));
|
|
if (linkTarget) {
|
|
// Relative path in symbolic link. Should be resolved relative to real path of base path.
|
|
const resolvedTarget = resolve(realpathBeforeNodeModules, input.slice(nodeModulesIndex + 1, linkStart), linkTarget);
|
|
// Cache the result of the combined resolution to avoid the readlink call in subsequent calls
|
|
cache.set(linkCandidate, resolvedTarget);
|
|
cache.set(resolvedTarget, resolvedTarget);
|
|
// Joining to `.` will clean up any extraneous trailing slashes
|
|
return join(resolvedTarget, input.slice(linkEnd + 1), '.');
|
|
}
|
|
// No symlink, so just return the real path before the last node_modules combined with the
|
|
// subsequent path segments
|
|
// Joining to `.` will clean up any extraneous trailing slashes
|
|
return join(realpathBeforeNodeModules, input.slice(nodeModulesIndex + 1), '.');
|
|
}
|
|
this.realNodeModulePath = (input) => {
|
|
return realNodeModulePathInternal(resolve(input));
|
|
};
|
|
}
|
|
/**
|
|
* Clears the cache of resolved symlinks.
|
|
* @public
|
|
*/
|
|
clearCache() {
|
|
this._cache.clear();
|
|
}
|
|
/**
|
|
* Tries to read a symbolic link at the specified path.
|
|
* If the input is not a symbolic link, returns undefined.
|
|
* @param link - The link to try to read
|
|
* @returns The target of the symbolic link, or undefined if the input is not a symbolic link
|
|
*/
|
|
_tryReadLink(link) {
|
|
const cached = this._cache.get(link);
|
|
if (cached !== undefined) {
|
|
return cached || undefined;
|
|
}
|
|
const cachedError = this._errorCache.get(link);
|
|
if (cachedError) {
|
|
// Fill the properties but fix the stack trace.
|
|
throw Object.assign(new Error(cachedError.message), cachedError);
|
|
}
|
|
// On Windows, calling `readlink` on a directory throws an EUNKOWN, not EINVAL, so just pay the cost
|
|
// of an lstat call.
|
|
try {
|
|
const stat = this._fs.lstatSync(link, this._lstatOptions);
|
|
if (stat === null || stat === void 0 ? void 0 : stat.isSymbolicLink()) {
|
|
// path.join(x, '.') will trim trailing slashes, if applicable
|
|
const result = this._path.join(this._fs.readlinkSync(link, 'utf8'), '.');
|
|
return result;
|
|
}
|
|
// Ensure we cache that this was not a symbolic link.
|
|
this._cache.set(link, false);
|
|
}
|
|
catch (err) {
|
|
this._errorCache.set(link, err);
|
|
}
|
|
}
|
|
}
|
|
exports.RealNodeModulePathResolver = RealNodeModulePathResolver;
|
|
//# sourceMappingURL=RealNodeModulePath.js.map
|