liferay-npm-bundler-preset-reactjs
Version:
liferay npm bundler preset react
145 lines (112 loc) • 3.57 kB
text/typescript
/**
* SPDX-FileCopyrightText: © 2020 Liferay, Inc. <https://liferay.com>
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
import fs from 'fs';
import path from 'path';
import readJsonSync from 'read-json-sync';
/** A null object pattern for {@link fs.Stats} object */
interface NullFsStats {
isDirectory: () => boolean;
isFile: () => boolean;
}
/**
* Converts a package name (optionally versioned) to its target folder name
* inside bundled node_modules.
* @param name a package name
* @param version an optional package version
* @return the target folder
*/
export function getPackageTargetDir(
name: string,
version: string = null
): string {
let targetFolder = name.replace('/', '%2F');
if (version) {
targetFolder += `@${version}`;
}
return targetFolder;
}
/**
* Resolves a module name inside a package directory to a file relative (to
* package directory) path.
* For example, if you pass './lib' as moduleName and there's an 'index.js' file
* inside the 'lib' dir, the method returns './lib/index.js'.
* It also honors any 'package.json' with a 'main' entry in package subfolders.
* @param pkgPath path to package directory
* @param moduleName the module name
* @return a path relative to pkgDir
*/
export function resolveModuleFile(pkgPath: string, moduleName: string): string {
let fullModulePath = path.resolve(
path.join(pkgPath, ...moduleName.split('/'))
);
let moduleStats = safeStat(fullModulePath);
if (moduleStats.isDirectory()) {
// Given module name is a directory
const pkgJsonPath = path.join(fullModulePath, 'package.json');
const pkgJsonStats = safeStat(pkgJsonPath);
if (pkgJsonStats.isFile()) {
// Module directory has package.json file
const pkgJson = readJsonSync(pkgJsonPath);
const {main} = pkgJson;
if (main) {
// Module directory has package.json file with main entry:
// recursively resolve the main entry's file path
fullModulePath = path.join(
pkgPath,
resolveModuleFile(pkgPath, path.join(moduleName, main))
);
}
else {
// Module directory has package.json file without main entry:
// assume index.js
fullModulePath = path.join(fullModulePath, 'index.js');
}
}
else {
// Module directory has not package.json file: assume index.js
fullModulePath = path.join(fullModulePath, 'index.js');
}
}
else if (moduleStats.isFile()) {
// Given module name is a file: do nothing
}
else if (fullModulePath.endsWith('.js')) {
// Given module name is not a directory nor a file but ends with '.js'
// extension: see if corresponding '.js.js' file exists
moduleStats = safeStat(`${fullModulePath}.js`);
if (moduleStats.isFile()) {
// Given module name has a corresponding '.js.js' file: add '.js'
// extension
fullModulePath += '.js';
}
else {
// Given module name has no corresponding '.js.js' file: do nothing
// and assume that the '.js' in the module name is just the
// extension of the file and doesn't belong to its name.
}
}
else {
// Given module name is not a directory nor a file and doesn't end with
// '.js' extension: add '.js' extension
fullModulePath += '.js';
}
return path.relative(pkgPath, fullModulePath);
}
/**
* Do as fs.statSync without throwing errors.
* @param path path to check
* @return {fs.Stats} a real fs.Stats object or a null object
*/
function safeStat(path: string): fs.Stats | NullFsStats {
try {
return fs.statSync(path);
}
catch (err) {
return {
isDirectory: () => false,
isFile: () => false,
};
}
}