"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getPatternFromSpec = exports.createTsInternals = void 0; const path_1 = require("path"); const util_1 = require("./util"); /** @internal */ exports.createTsInternals = (0, util_1.cachedLookup)(createTsInternalsUncached); /** * Given a reference to the TS compiler, return some TS internal functions that we * could not or did not want to grab off the `ts` object. * These have been copy-pasted from TS's source and tweaked as necessary. * * NOTE: This factory returns *only* functions which need a reference to the TS * compiler. Other functions do not need a reference to the TS compiler so are * exported directly from this file. */ function createTsInternalsUncached(_ts) { const ts = _ts; /** * Copied from: * https://github.com/microsoft/TypeScript/blob/v4.3.2/src/compiler/commandLineParser.ts#L2821-L2846 */ function getExtendsConfigPath(extendedConfig, host, basePath, errors, createDiagnostic) { extendedConfig = (0, util_1.normalizeSlashes)(extendedConfig); if (isRootedDiskPath(extendedConfig) || startsWith(extendedConfig, './') || startsWith(extendedConfig, '../')) { let extendedConfigPath = getNormalizedAbsolutePath(extendedConfig, basePath); if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, ts.Extension.Json)) { extendedConfigPath = `${extendedConfigPath}.json`; if (!host.fileExists(extendedConfigPath)) { errors.push(createDiagnostic(ts.Diagnostics.File_0_not_found, extendedConfig)); return undefined; } } return extendedConfigPath; } // If the path isn't a rooted or relative path, resolve like a module const resolved = ts.nodeModuleNameResolver(extendedConfig, combinePaths(basePath, 'tsconfig.json'), { moduleResolution: ts.ModuleResolutionKind.NodeJs }, host, /*cache*/ undefined, /*projectRefs*/ undefined, /*lookupConfig*/ true); if (resolved.resolvedModule) { return resolved.resolvedModule.resolvedFileName; } errors.push(createDiagnostic(ts.Diagnostics.File_0_not_found, extendedConfig)); return undefined; } return { getExtendsConfigPath }; } // These functions have alternative implementation to avoid copying too much from TS function isRootedDiskPath(path) { return (0, path_1.isAbsolute)(path); } function combinePaths(path, ...paths) { return (0, util_1.normalizeSlashes)((0, path_1.resolve)(path, ...paths.filter((path) => path))); } function getNormalizedAbsolutePath(fileName, currentDirectory) { return (0, util_1.normalizeSlashes)(currentDirectory != null ? (0, path_1.resolve)(currentDirectory, fileName) : (0, path_1.resolve)(fileName)); } function startsWith(str, prefix) { return str.lastIndexOf(prefix, 0) === 0; } function endsWith(str, suffix) { const expectedPos = str.length - suffix.length; return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos; } // Reserved characters, forces escaping of any non-word (or digit), non-whitespace character. // It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future // proof. const reservedCharacterPattern = /[^\w\s\/]/g; /** * @internal * See also: getRegularExpressionForWildcard, which seems to do almost the same thing */ function getPatternFromSpec(spec, basePath) { const pattern = spec && getSubPatternFromSpec(spec, basePath, excludeMatcher); return pattern && `^(${pattern})${'($|/)'}`; } exports.getPatternFromSpec = getPatternFromSpec; function getSubPatternFromSpec(spec, basePath, { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter, }) { let subpattern = ''; let hasWrittenComponent = false; const components = getNormalizedPathComponents(spec, basePath); const lastComponent = last(components); // getNormalizedPathComponents includes the separator for the root component. // We need to remove to create our regex correctly. components[0] = removeTrailingDirectorySeparator(components[0]); if (isImplicitGlob(lastComponent)) { components.push('**', '*'); } let optionalCount = 0; for (let component of components) { if (component === '**') { subpattern += doubleAsteriskRegexFragment; } else { if (hasWrittenComponent) { subpattern += directorySeparator; } subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter); } hasWrittenComponent = true; } while (optionalCount > 0) { subpattern += ')?'; optionalCount--; } return subpattern; } const directoriesMatcher = { singleAsteriskRegexFragment: '[^/]*', /** * Regex for the ** wildcard. Matches any num of subdirectories. When used for including * files or directories, does not match subdirectories that start with a . character */ doubleAsteriskRegexFragment: `(/[^/.][^/]*)*?`, replaceWildcardCharacter: (match) => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment), }; const excludeMatcher = { singleAsteriskRegexFragment: '[^/]*', doubleAsteriskRegexFragment: '(/.+?)?', replaceWildcardCharacter: (match) => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment), }; function getNormalizedPathComponents(path, currentDirectory) { return reducePathComponents(getPathComponents(path, currentDirectory)); } function getPathComponents(path, currentDirectory = '') { path = combinePaths(currentDirectory, path); return pathComponents(path, getRootLength(path)); } function reducePathComponents(components) { if (!some(components)) return []; const reduced = [components[0]]; for (let i = 1; i < components.length; i++) { const component = components[i]; if (!component) continue; if (component === '.') continue; if (component === '..') { if (reduced.length > 1) { if (reduced[reduced.length - 1] !== '..') { reduced.pop(); continue; } } else if (reduced[0]) continue; } reduced.push(component); } return reduced; } function getRootLength(path) { const rootLength = getEncodedRootLength(path); return rootLength < 0 ? ~rootLength : rootLength; } function getEncodedRootLength(path) { if (!path) return 0; const ch0 = path.charCodeAt(0); // POSIX or UNC if (ch0 === 47 /* CharacterCodes.slash */ || ch0 === 92 /* CharacterCodes.backslash */) { if (path.charCodeAt(1) !== ch0) return 1; // POSIX: "/" (or non-normalized "\") const p1 = path.indexOf(ch0 === 47 /* CharacterCodes.slash */ ? directorySeparator : altDirectorySeparator, 2); if (p1 < 0) return path.length; // UNC: "//server" or "\\server" return p1 + 1; // UNC: "//server/" or "\\server\" } // DOS if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* CharacterCodes.colon */) { const ch2 = path.charCodeAt(2); if (ch2 === 47 /* CharacterCodes.slash */ || ch2 === 92 /* CharacterCodes.backslash */) return 3; // DOS: "c:/" or "c:\" if (path.length === 2) return 2; // DOS: "c:" (but not "c:d") } // URL const schemeEnd = path.indexOf(urlSchemeSeparator); if (schemeEnd !== -1) { const authorityStart = schemeEnd + urlSchemeSeparator.length; const authorityEnd = path.indexOf(directorySeparator, authorityStart); if (authorityEnd !== -1) { // URL: "file:///", "file://server/", "file://server/path" // For local "file" URLs, include the leading DOS volume (if present). // Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a // special case interpreted as "the machine from which the URL is being interpreted". const scheme = path.slice(0, schemeEnd); const authority = path.slice(authorityStart, authorityEnd); if (scheme === 'file' && (authority === '' || authority === 'localhost') && isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) { const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2); if (volumeSeparatorEnd !== -1) { if (path.charCodeAt(volumeSeparatorEnd) === 47 /* CharacterCodes.slash */) { // URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/" return ~(volumeSeparatorEnd + 1); } if (volumeSeparatorEnd === path.length) { // URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a" // but not "file:///c:d" or "file:///c%3ad" return ~volumeSeparatorEnd; } } } return ~(authorityEnd + 1); // URL: "file://server/", "http://server/" } return ~path.length; // URL: "file://server", "http://server" } // relative return 0; } function ensureTrailingDirectorySeparator(path) { if (!hasTrailingDirectorySeparator(path)) { return path + directorySeparator; } return path; } function hasTrailingDirectorySeparator(path) { return (path.length > 0 && isAnyDirectorySeparator(path.charCodeAt(path.length - 1))); } function isAnyDirectorySeparator(charCode) { return (charCode === 47 /* CharacterCodes.slash */ || charCode === 92 /* CharacterCodes.backslash */); } function removeTrailingDirectorySeparator(path) { if (hasTrailingDirectorySeparator(path)) { return path.substr(0, path.length - 1); } return path; } const directorySeparator = '/'; const altDirectorySeparator = '\\'; const urlSchemeSeparator = '://'; function isVolumeCharacter(charCode) { return ((charCode >= 97 /* CharacterCodes.a */ && charCode <= 122 /* CharacterCodes.z */) || (charCode >= 65 /* CharacterCodes.A */ && charCode <= 90 /* CharacterCodes.Z */)); } function getFileUrlVolumeSeparatorEnd(url, start) { const ch0 = url.charCodeAt(start); if (ch0 === 58 /* CharacterCodes.colon */) return start + 1; if (ch0 === 37 /* CharacterCodes.percent */ && url.charCodeAt(start + 1) === 51 /* CharacterCodes._3 */) { const ch2 = url.charCodeAt(start + 2); if (ch2 === 97 /* CharacterCodes.a */ || ch2 === 65 /* CharacterCodes.A */) return start + 3; } return -1; } function some(array, predicate) { if (array) { if (predicate) { for (const v of array) { if (predicate(v)) { return true; } } } else { return array.length > 0; } } return false; } function pathComponents(path, rootLength) { const root = path.substring(0, rootLength); const rest = path.substring(rootLength).split(directorySeparator); if (rest.length && !lastOrUndefined(rest)) rest.pop(); return [root, ...rest]; } function lastOrUndefined(array) { return array.length === 0 ? undefined : array[array.length - 1]; } function last(array) { // Debug.assert(array.length !== 0); return array[array.length - 1]; } function replaceWildcardCharacter(match, singleAsteriskRegexFragment) { return match === '*' ? singleAsteriskRegexFragment : match === '?' ? '[^/]' : '\\' + match; } /** * An "includes" path "foo" is implicitly a glob "foo/** /*" (without the space) if its last component has no extension, * and does not contain any glob characters itself. */ function isImplicitGlob(lastPathComponent) { return !/[.*?]/.test(lastPathComponent); } //# sourceMappingURL=ts-internals.js.map