Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
368 lines
12 KiB
Plaintext
368 lines
12 KiB
Plaintext
import fs from 'node:fs';
|
|
import module from 'node:module';
|
|
import path from 'node:path';
|
|
import isNodeCoreModule from '@nolyfill/is-core-module';
|
|
import debug from 'debug';
|
|
import { createPathsMatcher, getTsconfig } from 'get-tsconfig';
|
|
import { isBunModule } from 'is-bun-module';
|
|
import { stableHash } from 'stable-hash';
|
|
import { globSync, isDynamicPattern } from 'tinyglobby';
|
|
import { ResolverFactory } from 'unrs-resolver';
|
|
const IMPORTER_NAME = 'eslint-import-resolver-typescript';
|
|
const log = debug(IMPORTER_NAME);
|
|
export const defaultConditionNames = [
|
|
'types',
|
|
'import',
|
|
'esm2020',
|
|
'es2020',
|
|
'es2015',
|
|
'require',
|
|
'node',
|
|
'node-addons',
|
|
'browser',
|
|
'default',
|
|
];
|
|
export const defaultExtensions = [
|
|
'.ts',
|
|
'.tsx',
|
|
'.d.ts',
|
|
'.js',
|
|
'.jsx',
|
|
'.json',
|
|
'.node',
|
|
];
|
|
export const defaultExtensionAlias = {
|
|
'.js': [
|
|
'.ts',
|
|
'.tsx',
|
|
'.d.ts',
|
|
'.js',
|
|
],
|
|
'.jsx': ['.tsx', '.d.ts', '.jsx'],
|
|
'.cjs': ['.cts', '.d.cts', '.cjs'],
|
|
'.mjs': ['.mts', '.d.mts', '.mjs'],
|
|
};
|
|
export const defaultMainFields = [
|
|
'types',
|
|
'typings',
|
|
'fesm2020',
|
|
'fesm2015',
|
|
'esm2020',
|
|
'es2020',
|
|
'module',
|
|
'jsnext:main',
|
|
'main',
|
|
];
|
|
export const interfaceVersion = 2;
|
|
const JS_EXT_PATTERN = /\.(?:[cm]js|jsx?)$/;
|
|
const RELATIVE_PATH_PATTERN = /^\.{1,2}(?:\/.*)?$/;
|
|
let previousOptionsHash;
|
|
let optionsHash;
|
|
let cachedOptions;
|
|
let cachedCwd;
|
|
let mappersCachedOptions;
|
|
let mappers = [];
|
|
let resolverCachedOptions;
|
|
let cachedResolver;
|
|
export function resolve(source, file, options, resolver) {
|
|
if (!cachedOptions ||
|
|
previousOptionsHash !== (optionsHash = stableHash(options))) {
|
|
previousOptionsHash = optionsHash;
|
|
cachedOptions = {
|
|
...options,
|
|
conditionNames: options?.conditionNames ?? defaultConditionNames,
|
|
extensions: options?.extensions ?? defaultExtensions,
|
|
extensionAlias: options?.extensionAlias ?? defaultExtensionAlias,
|
|
mainFields: options?.mainFields ?? defaultMainFields,
|
|
};
|
|
}
|
|
if (!resolver) {
|
|
if (!cachedResolver || resolverCachedOptions !== cachedOptions) {
|
|
cachedResolver = new ResolverFactory(cachedOptions);
|
|
resolverCachedOptions = cachedOptions;
|
|
}
|
|
resolver = cachedResolver;
|
|
}
|
|
log('looking for', source, 'in', file);
|
|
source = removeQuerystring(source);
|
|
if (isNodeCoreModule(source) || isBunModule(source)) {
|
|
log('matched core:', source);
|
|
return {
|
|
found: true,
|
|
path: null,
|
|
};
|
|
}
|
|
if (process.versions.pnp && source === 'pnpapi') {
|
|
return {
|
|
found: true,
|
|
path: module.findPnpApi(file).resolveToUnqualified(source, file, {
|
|
considerBuiltins: false,
|
|
}),
|
|
};
|
|
}
|
|
initMappers(cachedOptions);
|
|
let mappedPaths = getMappedPaths(source, file, cachedOptions.extensions, true);
|
|
if (mappedPaths.length > 0) {
|
|
log('matched ts path:', ...mappedPaths);
|
|
}
|
|
else {
|
|
mappedPaths = [source];
|
|
}
|
|
let foundNodePath;
|
|
for (const mappedPath of mappedPaths) {
|
|
try {
|
|
const resolved = resolver.sync(path.dirname(path.resolve(file)), mappedPath);
|
|
if (resolved.path) {
|
|
foundNodePath = resolved.path;
|
|
break;
|
|
}
|
|
}
|
|
catch {
|
|
log('failed to resolve with', mappedPath);
|
|
}
|
|
}
|
|
if ((JS_EXT_PATTERN.test(foundNodePath) ||
|
|
(cachedOptions.alwaysTryTypes && !foundNodePath)) &&
|
|
!/^@types[/\\]/.test(source) &&
|
|
!path.isAbsolute(source) &&
|
|
!source.startsWith('.')) {
|
|
const definitelyTyped = resolve('@types' + path.sep + mangleScopedPackage(source), file, options);
|
|
if (definitelyTyped.found) {
|
|
return definitelyTyped;
|
|
}
|
|
}
|
|
if (foundNodePath) {
|
|
log('matched node path:', foundNodePath);
|
|
return {
|
|
found: true,
|
|
path: foundNodePath,
|
|
};
|
|
}
|
|
log("didn't find ", source);
|
|
return {
|
|
found: false,
|
|
};
|
|
}
|
|
export function createTypeScriptImportResolver(options) {
|
|
const resolver = new ResolverFactory({
|
|
...options,
|
|
conditionNames: options?.conditionNames ?? defaultConditionNames,
|
|
extensions: options?.extensions ?? defaultExtensions,
|
|
extensionAlias: options?.extensionAlias ?? defaultExtensionAlias,
|
|
mainFields: options?.mainFields ?? defaultMainFields,
|
|
});
|
|
return {
|
|
interfaceVersion: 3,
|
|
name: IMPORTER_NAME,
|
|
resolve(source, file) {
|
|
return resolve(source, file, options, resolver);
|
|
},
|
|
};
|
|
}
|
|
function removeQuerystring(id) {
|
|
const querystringIndex = id.lastIndexOf('?');
|
|
if (querystringIndex !== -1) {
|
|
return id.slice(0, querystringIndex);
|
|
}
|
|
return id;
|
|
}
|
|
const isFile = (path) => {
|
|
try {
|
|
return !!(path && fs.statSync(path, { throwIfNoEntry: false })?.isFile());
|
|
}
|
|
catch {
|
|
return false;
|
|
}
|
|
};
|
|
const isModule = (modulePath) => !!modulePath && isFile(path.resolve(modulePath, 'package.json'));
|
|
function getMappedPaths(source, file, extensions = defaultExtensions, retry) {
|
|
const originalExtensions = extensions;
|
|
extensions = ['', ...extensions];
|
|
let paths = [];
|
|
if (RELATIVE_PATH_PATTERN.test(source)) {
|
|
const resolved = path.resolve(path.dirname(file), source);
|
|
if (isFile(resolved)) {
|
|
paths = [resolved];
|
|
}
|
|
}
|
|
else {
|
|
let mapperFns = mappers
|
|
.filter(({ files }) => files.has(file))
|
|
.map(({ mapperFn }) => mapperFn);
|
|
if (mapperFns.length === 0) {
|
|
mapperFns = mappers
|
|
.map(mapper => ({
|
|
mapperFn: mapper.mapperFn,
|
|
counter: equalChars(path.dirname(file), path.dirname(mapper.path)),
|
|
}))
|
|
.sort((a, b) => b.counter - a.counter)
|
|
.map(({ mapperFn }) => mapperFn);
|
|
}
|
|
paths = mapperFns
|
|
.map(mapperFn => mapperFn(source).map(item => [
|
|
...extensions.map(ext => `${item}${ext}`),
|
|
...originalExtensions.map(ext => `${item}/index${ext}`),
|
|
]))
|
|
.flat(2)
|
|
.map(toNativePathSeparator)
|
|
.filter(mappedPath => {
|
|
try {
|
|
const stat = fs.statSync(mappedPath, { throwIfNoEntry: false });
|
|
if (stat === undefined) {
|
|
return false;
|
|
}
|
|
if (stat.isFile()) {
|
|
return true;
|
|
}
|
|
if (stat.isDirectory()) {
|
|
return isModule(mappedPath);
|
|
}
|
|
}
|
|
catch {
|
|
return false;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
if (retry && paths.length === 0) {
|
|
const isJs = JS_EXT_PATTERN.test(source);
|
|
if (isJs) {
|
|
const jsExt = path.extname(source);
|
|
const tsExt = jsExt.replace('js', 'ts');
|
|
const basename = source.replace(JS_EXT_PATTERN, '');
|
|
let resolved = getMappedPaths(basename + tsExt, file);
|
|
if (resolved.length === 0 && jsExt === '.js') {
|
|
const tsxExt = jsExt.replace('js', 'tsx');
|
|
resolved = getMappedPaths(basename + tsxExt, file);
|
|
}
|
|
if (resolved.length === 0) {
|
|
resolved = getMappedPaths(basename + '.d' + (tsExt === '.tsx' ? '.ts' : tsExt), file);
|
|
}
|
|
if (resolved.length > 0) {
|
|
return resolved;
|
|
}
|
|
}
|
|
for (const ext of extensions) {
|
|
const mappedPaths = isJs ? [] : getMappedPaths(source + ext, file);
|
|
const resolved = mappedPaths.length > 0
|
|
? mappedPaths
|
|
: getMappedPaths(source + `/index${ext}`, file);
|
|
if (resolved.length > 0) {
|
|
return resolved;
|
|
}
|
|
}
|
|
}
|
|
return paths;
|
|
}
|
|
function initMappers(options) {
|
|
if (mappers.length > 0 &&
|
|
mappersCachedOptions === options &&
|
|
cachedCwd === process.cwd()) {
|
|
return;
|
|
}
|
|
cachedCwd = process.cwd();
|
|
const configPaths = (typeof options.project === 'string'
|
|
? [options.project]
|
|
:
|
|
Array.isArray(options.project)
|
|
? options.project
|
|
: [cachedCwd])
|
|
.map(config => replacePathSeparator(config, path.sep, path.posix.sep));
|
|
const defaultInclude = ['**/*'];
|
|
const defaultIgnore = ['**/node_modules/**'];
|
|
const projectPaths = [
|
|
...new Set([
|
|
...configPaths
|
|
.filter(p => !isDynamicPattern(p))
|
|
.map(p => path.resolve(process.cwd(), p)),
|
|
...globSync(configPaths.filter(path => isDynamicPattern(path)), {
|
|
absolute: true,
|
|
dot: true,
|
|
expandDirectories: false,
|
|
ignore: defaultIgnore,
|
|
}),
|
|
]),
|
|
];
|
|
mappers = projectPaths
|
|
.map(projectPath => {
|
|
let tsconfigResult;
|
|
if (isFile(projectPath)) {
|
|
const { dir, base } = path.parse(projectPath);
|
|
tsconfigResult = getTsconfig(dir, base);
|
|
}
|
|
else {
|
|
tsconfigResult = getTsconfig(projectPath);
|
|
}
|
|
if (!tsconfigResult) {
|
|
return;
|
|
}
|
|
const mapperFn = createPathsMatcher(tsconfigResult);
|
|
if (!mapperFn) {
|
|
return;
|
|
}
|
|
const files = tsconfigResult.config.files == null &&
|
|
tsconfigResult.config.include == null
|
|
?
|
|
globSync(defaultInclude, {
|
|
absolute: true,
|
|
cwd: path.dirname(tsconfigResult.path),
|
|
dot: true,
|
|
ignore: [
|
|
...(tsconfigResult.config.exclude ?? []),
|
|
...defaultIgnore,
|
|
],
|
|
})
|
|
: [
|
|
...(tsconfigResult.config.files != null &&
|
|
tsconfigResult.config.files.length > 0
|
|
? tsconfigResult.config.files.map(file => path.normalize(path.resolve(path.dirname(tsconfigResult.path), file)))
|
|
: []),
|
|
...(tsconfigResult.config.include != null &&
|
|
tsconfigResult.config.include.length > 0
|
|
? globSync(tsconfigResult.config.include, {
|
|
absolute: true,
|
|
cwd: path.dirname(tsconfigResult.path),
|
|
dot: true,
|
|
ignore: [
|
|
...(tsconfigResult.config.exclude ?? []),
|
|
...defaultIgnore,
|
|
],
|
|
})
|
|
: []),
|
|
];
|
|
return {
|
|
path: toNativePathSeparator(tsconfigResult.path),
|
|
files: new Set(files.map(toNativePathSeparator)),
|
|
mapperFn,
|
|
};
|
|
})
|
|
.filter(Boolean);
|
|
mappersCachedOptions = options;
|
|
}
|
|
function mangleScopedPackage(moduleName) {
|
|
if (moduleName.startsWith('@')) {
|
|
const replaceSlash = moduleName.replace(path.sep, '__');
|
|
if (replaceSlash !== moduleName) {
|
|
return replaceSlash.slice(1);
|
|
}
|
|
}
|
|
return moduleName;
|
|
}
|
|
function replacePathSeparator(p, from, to) {
|
|
return from === to ? p : p.replaceAll(from, to);
|
|
}
|
|
function toNativePathSeparator(p) {
|
|
return replacePathSeparator(p, path[process.platform === 'win32' ? 'posix' : 'win32'].sep, path[process.platform === 'win32' ? 'win32' : 'posix'].sep);
|
|
}
|
|
function equalChars(a, b) {
|
|
if (a.length === 0 || b.length === 0) {
|
|
return 0;
|
|
}
|
|
let i = 0;
|
|
const length = Math.min(a.length, b.length);
|
|
while (i < length && a.charAt(i) === b.charAt(i)) {
|
|
i += 1;
|
|
}
|
|
return i;
|
|
}
|
|
//# sourceMappingURL=index.js.map |