snowpack
Version:
The ESM-powered frontend build tool. Fast, lightweight, unbundled.
121 lines (120 loc) • 5.11 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createImportResolver = exports.getFsStat = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const util_1 = require("../util");
const file_urls_1 = require("./file-urls");
/** Perform a file disk lookup for the requested import specifier. */
function getFsStat(importedFileOnDisk) {
try {
return fs_1.default.statSync(importedFileOnDisk);
}
catch (err) {
// file doesn't exist, that's fine
}
return false;
}
exports.getFsStat = getFsStat;
/** Resolve an import based on the state of the file/folder found on disk. */
function resolveSourceSpecifier(lazyFileLoc, { parentFile, config }) {
const lazyFileStat = getFsStat(lazyFileLoc);
// Handle directory imports (ex: "./components" -> "./components/index.js")
if (lazyFileStat && lazyFileStat.isDirectory()) {
const trailingSlash = lazyFileLoc.endsWith(path_1.default.sep) ? '' : path_1.default.sep;
lazyFileLoc = lazyFileLoc + trailingSlash + 'index.js';
}
else if (lazyFileStat && lazyFileStat.isFile()) {
lazyFileLoc = lazyFileLoc;
}
else if (util_1.hasExtension(lazyFileLoc, '.css')) {
lazyFileLoc = lazyFileLoc;
}
else if (util_1.hasExtension(lazyFileLoc, '.js')) {
const tsWorkaroundImportFileLoc = util_1.replaceExtension(lazyFileLoc, '.js', '.ts');
if (getFsStat(tsWorkaroundImportFileLoc)) {
lazyFileLoc = tsWorkaroundImportFileLoc;
}
}
else if (util_1.hasExtension(lazyFileLoc, '.jsx')) {
const tsWorkaroundImportFileLoc = util_1.replaceExtension(lazyFileLoc, '.jsx', '.tsx');
if (getFsStat(tsWorkaroundImportFileLoc)) {
lazyFileLoc = tsWorkaroundImportFileLoc;
}
}
else {
// missing extension
if (getFsStat(lazyFileLoc + path_1.default.extname(parentFile))) {
// first, try parent file’s extension
lazyFileLoc = lazyFileLoc + path_1.default.extname(parentFile);
}
else {
// otherwise, try and match any extension from the extension map
for (const [ext, outputExts] of Object.entries(config._extensionMap)) {
if (!outputExts.includes('.js'))
continue; // only look through .js-friendly extensions
if (getFsStat(lazyFileLoc + ext)) {
lazyFileLoc = lazyFileLoc + ext;
break;
}
}
}
// if still no extension match, fall back to .js
if (!path_1.default.extname(lazyFileLoc)) {
lazyFileLoc = lazyFileLoc + '.js';
}
}
// Transform the file extension (from input to output)
const extensionMatch = util_1.getExtensionMatch(lazyFileLoc, config._extensionMap);
if (extensionMatch) {
const [inputExt, outputExts] = extensionMatch;
if (outputExts.length > 1) {
lazyFileLoc = util_1.addExtension(lazyFileLoc, outputExts[0]);
}
else {
lazyFileLoc = util_1.replaceExtension(lazyFileLoc, inputExt, outputExts[0]);
}
}
const resolvedUrls = file_urls_1.getUrlsForFile(lazyFileLoc, config);
return resolvedUrls ? resolvedUrls[0] : resolvedUrls;
}
/**
* Create a import resolver function, which converts any import relative to the given file at "fileLoc"
* to a proper URL. Returns false if no matching import was found, which usually indicates a package
* not found in the import map.
*/
function createImportResolver({ fileLoc, config }) {
return function importResolver(spec) {
var _a;
// Ignore "http://*" imports
if (util_1.isRemoteUrl(spec)) {
return spec;
}
// Ignore packages marked as external
if ((_a = config.packageOptions.external) === null || _a === void 0 ? void 0 : _a.includes(spec)) {
return spec;
}
if (spec[0] === '/') {
return spec;
}
if (util_1.isPathImport(spec)) {
const importedFileLoc = path_1.default.resolve(path_1.default.dirname(fileLoc), path_1.default.normalize(spec));
return resolveSourceSpecifier(importedFileLoc, { parentFile: fileLoc, config }) || spec;
}
const aliasEntry = util_1.findMatchingAliasEntry(config, spec);
if (aliasEntry && (aliasEntry.type === 'path' || aliasEntry.type === 'url')) {
const { from, to } = aliasEntry;
let result = spec.replace(from, to);
if (aliasEntry.type === 'url') {
return result;
}
const importedFileLoc = path_1.default.resolve(config.root, result);
return resolveSourceSpecifier(importedFileLoc, { parentFile: fileLoc, config }) || spec;
}
return false;
};
}
exports.createImportResolver = createImportResolver;