feat(providence-analytics): add export-map functionality to InputDataService
This commit is contained in:
parent
b568bcd1dd
commit
9593c45695
4 changed files with 429 additions and 122 deletions
5
.changeset/moody-days-yawn.md
Normal file
5
.changeset/moody-days-yawn.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'providence-analytics': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
providence-analytics: add export-map functionality to InputDataService
|
||||||
|
|
@ -220,7 +220,9 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
(a dependency installed via npm) or a git repository, different paths will be
|
(a dependency installed via npm) or a git repository, different paths will be
|
||||||
automatically put in the appropiate mode.
|
automatically put in the appropiate mode.
|
||||||
A mode of 'npm' will look at the package.json "files" entry and a mode of
|
A mode of 'npm' will look at the package.json "files" entry and a mode of
|
||||||
'git' will look at '.gitignore' entry. The mode will be auto detected, but can be overridden
|
'git' will look at '.gitignore' entry. A mode of 'export-map' will look for all paths
|
||||||
|
exposed via an export map.
|
||||||
|
The mode will be auto detected, but can be overridden
|
||||||
via this option.`,
|
via this option.`,
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,33 @@ function multiGlobSync(patterns, { keepDirs = false, root } = {}) {
|
||||||
return Array.from(res);
|
return Array.from(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripDotSlashFromLocalPath(localPathWithDotSlash) {
|
||||||
|
return localPathWithDotSlash.replace(/^\.\//, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLocalPathWithDotSlash(localPathWithoutDotSlash) {
|
||||||
|
if (!localPathWithoutDotSlash.startsWith('.')) {
|
||||||
|
return `./${localPathWithoutDotSlash}`;
|
||||||
|
}
|
||||||
|
return localPathWithoutDotSlash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{val:object|string;nodeResolveMode:string}} opts
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getStringOrObjectValOfExportMapEntry({ val, nodeResolveMode, packageRootPath }) {
|
||||||
|
if (typeof val !== 'object') {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
if (!val[nodeResolveMode]) {
|
||||||
|
throw new Error(
|
||||||
|
`[getExportMapExports]: nodeResolveMode "${nodeResolveMode}" not found in package.json of package ${packageRootPath}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return val[nodeResolveMode];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To be used in main program.
|
* To be used in main program.
|
||||||
* It creates an instance on which the 'files' array is stored.
|
* It creates an instance on which the 'files' array is stored.
|
||||||
|
|
@ -215,13 +242,20 @@ function multiGlobSync(patterns, { keepDirs = false, root } = {}) {
|
||||||
class InputDataService {
|
class InputDataService {
|
||||||
/**
|
/**
|
||||||
* Create an array of ProjectData
|
* Create an array of ProjectData
|
||||||
* @param {PathFromSystemRoot[]} projectPaths
|
* @param {PathFromSystemRoot | ProjectInputData []} projectPaths
|
||||||
* @param {Partial<GatherFilesConfig>} gatherFilesConfig
|
* @param {Partial<GatherFilesConfig>} gatherFilesConfig
|
||||||
* @returns {ProjectInputData[]}
|
* @returns {ProjectInputData[]}
|
||||||
*/
|
*/
|
||||||
static createDataObject(projectPaths, gatherFilesConfig = {}) {
|
static createDataObject(projectPaths, gatherFilesConfig = {}) {
|
||||||
/** @type {ProjectInputData[]} */
|
/** @type {ProjectInputData[]} */
|
||||||
const inputData = projectPaths.map(projectPath => ({
|
const inputData = projectPaths.map(projectPathOrObj => {
|
||||||
|
if (typeof projectPathOrObj === 'object') {
|
||||||
|
// ProjectInputData was provided already manually
|
||||||
|
return projectPathOrObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectPath = projectPathOrObj;
|
||||||
|
return {
|
||||||
project: /** @type {Project} */ ({
|
project: /** @type {Project} */ ({
|
||||||
name: pathLib.basename(projectPath),
|
name: pathLib.basename(projectPath),
|
||||||
path: projectPath,
|
path: projectPath,
|
||||||
|
|
@ -230,7 +264,8 @@ class InputDataService {
|
||||||
...this.defaultGatherFilesConfig,
|
...this.defaultGatherFilesConfig,
|
||||||
...gatherFilesConfig,
|
...gatherFilesConfig,
|
||||||
}),
|
}),
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return this._addMetaToProjectsData(inputData);
|
return this._addMetaToProjectsData(inputData);
|
||||||
}
|
}
|
||||||
|
|
@ -456,7 +491,8 @@ class InputDataService {
|
||||||
...(customConfig.allowlist || []),
|
...(customConfig.allowlist || []),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const allowlistModes = ['npm', 'git', 'all'];
|
|
||||||
|
const allowlistModes = ['npm', 'git', 'all', 'export-map'];
|
||||||
if (customConfig.allowlistMode && !allowlistModes.includes(customConfig.allowlistMode)) {
|
if (customConfig.allowlistMode && !allowlistModes.includes(customConfig.allowlistMode)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[gatherFilesConfig] Please provide a valid allowListMode like "${allowlistModes.join(
|
`[gatherFilesConfig] Please provide a valid allowListMode like "${allowlistModes.join(
|
||||||
|
|
@ -465,6 +501,15 @@ class InputDataService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg.allowlistMode === 'export-map') {
|
||||||
|
const pkgJson = getPackageJson(startPath);
|
||||||
|
if (!pkgJson.exports) {
|
||||||
|
LogService.error(`No exports found in package.json of ${startPath}`);
|
||||||
|
}
|
||||||
|
const exposedAndInternalPaths = this.getPathsFromExportMap(pkgJson.exports, { packageRootPath: startPath });
|
||||||
|
return exposedAndInternalPaths.map(p => p.internal);
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let gitIgnorePaths = [];
|
let gitIgnorePaths = [];
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
|
|
@ -564,6 +609,62 @@ class InputDataService {
|
||||||
// TODO: support forward compatibility for npm?
|
// TODO: support forward compatibility for npm?
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} exports
|
||||||
|
* @param {object} opts
|
||||||
|
* @param {'default'|'development'|string} [opts.nodeResolveMode='default']
|
||||||
|
* @param {string} opts.packageRootPath
|
||||||
|
* @returns {Promise<{internalExportMapPaths:string[]; exposedExportMapPaths:string[]}>}
|
||||||
|
*/
|
||||||
|
static getPathsFromExportMap(exports, { nodeResolveMode = 'default', packageRootPath }) {
|
||||||
|
const exportMapPaths = [];
|
||||||
|
|
||||||
|
for (const [key, val] of Object.entries(exports)) {
|
||||||
|
if (!key.includes('*')) {
|
||||||
|
exportMapPaths.push({
|
||||||
|
internal: getStringOrObjectValOfExportMapEntry({ val, nodeResolveMode, packageRootPath }),
|
||||||
|
exposed: key,
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueToUseForGlob = stripDotSlashFromLocalPath(
|
||||||
|
getStringOrObjectValOfExportMapEntry({ val, nodeResolveMode, packageRootPath }),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Generate all possible entries via glob, first strip './'
|
||||||
|
const internalExportMapPathsForKeyRaw = glob.sync(valueToUseForGlob, {
|
||||||
|
cwd: packageRootPath,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exposedExportMapPathsForKeyRaw = internalExportMapPathsForKeyRaw.map(pathInside => {
|
||||||
|
// Say we have "exports": { "./*.js": "./src/*.js" }
|
||||||
|
// => internalExportMapPathsForKey: ['./src/a.js', './src/b.js']
|
||||||
|
// => exposedExportMapPathsForKey: ['./a.js', './b.js']
|
||||||
|
const [, variablePart] = pathInside.match(
|
||||||
|
new RegExp(valueToUseForGlob.replace('*', '(.*)')),
|
||||||
|
);
|
||||||
|
return key.replace('*', variablePart);
|
||||||
|
});
|
||||||
|
const internalExportMapPathsForKey = internalExportMapPathsForKeyRaw.map(filePath =>
|
||||||
|
normalizeLocalPathWithDotSlash(filePath),
|
||||||
|
);
|
||||||
|
const exposedExportMapPathsForKey = exposedExportMapPathsForKeyRaw.map(filePath =>
|
||||||
|
normalizeLocalPathWithDotSlash(filePath),
|
||||||
|
);
|
||||||
|
|
||||||
|
exportMapPaths.push(
|
||||||
|
...internalExportMapPathsForKey.map((internal, idx) => ({
|
||||||
|
internal,
|
||||||
|
exposed: exposedExportMapPathsForKey[idx],
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return exportMapPaths;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InputDataService.cacheDisabled = false;
|
InputDataService.cacheDisabled = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { InputDataService } = require('../../../src/program/services/InputDataService.js');
|
const { InputDataService } = require('../../../src/index.js');
|
||||||
const {
|
const {
|
||||||
restoreMockedProjects,
|
restoreMockedProjects,
|
||||||
mockProject,
|
mockProject,
|
||||||
|
mock,
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
} = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
|
|
||||||
function restoreOriginalInputDataPaths() {
|
function restoreOriginalInputDataPaths() {
|
||||||
|
|
@ -278,6 +279,66 @@ describe('InputDataService', () => {
|
||||||
expect(globOutput).to.eql(['/fictional/project/index.js']);
|
expect(globOutput).to.eql(['/fictional/project/index.js']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('AllowlistMode', () => {
|
||||||
|
it('autodetects allowlistMode', async () => {
|
||||||
|
mockProject({
|
||||||
|
'./dist/bundle.js': '',
|
||||||
|
'./package.json': JSON.stringify({
|
||||||
|
files: ['dist'],
|
||||||
|
}),
|
||||||
|
'.gitignore': '/dist',
|
||||||
|
});
|
||||||
|
const globOutput = InputDataService.gatherFilesFromDir('/fictional/project');
|
||||||
|
expect(globOutput).to.eql([
|
||||||
|
// This means allowlistMode is 'git'
|
||||||
|
]);
|
||||||
|
|
||||||
|
restoreOriginalInputDataPaths();
|
||||||
|
restoreMockedProjects();
|
||||||
|
|
||||||
|
mockProject({
|
||||||
|
'./dist/bundle.js': '',
|
||||||
|
'./package.json': JSON.stringify({
|
||||||
|
files: ['dist'],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const globOutput2 = InputDataService.gatherFilesFromDir('/fictional/project');
|
||||||
|
expect(globOutput2).to.eql([
|
||||||
|
// This means allowlistMode is 'npm'
|
||||||
|
'/fictional/project/dist/bundle.js',
|
||||||
|
]);
|
||||||
|
|
||||||
|
mockProject(
|
||||||
|
{ './dist/bundle.js': '', '.gitignore': '/dist' },
|
||||||
|
{
|
||||||
|
projectName: 'detect-as-npm',
|
||||||
|
projectPath: '/inside/proj/with/node_modules/detect-as-npm',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const globOutput3 = InputDataService.gatherFilesFromDir(
|
||||||
|
'/inside/proj/with/node_modules/detect-as-npm',
|
||||||
|
);
|
||||||
|
expect(globOutput3).to.eql([
|
||||||
|
// This means allowlistMode is 'npm' (even though we found .gitignore)
|
||||||
|
'/inside/proj/with/node_modules/detect-as-npm/dist/bundle.js',
|
||||||
|
]);
|
||||||
|
|
||||||
|
mockProject(
|
||||||
|
{ './dist/bundle.js': '', '.gitignore': '/dist' },
|
||||||
|
{
|
||||||
|
projectName: '@scoped/detect-as-npm',
|
||||||
|
projectPath: '/inside/proj/with/node_modules/@scoped/detect-as-npm',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const globOutput4 = InputDataService.gatherFilesFromDir(
|
||||||
|
'/inside/proj/with/node_modules/@scoped/detect-as-npm',
|
||||||
|
);
|
||||||
|
expect(globOutput4).to.eql([
|
||||||
|
// This means allowlistMode is 'npm' (even though we found .gitignore)
|
||||||
|
'/inside/proj/with/node_modules/@scoped/detect-as-npm/dist/bundle.js',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('filters npm "files" entries when allowlistMode is "npm"', async () => {
|
it('filters npm "files" entries when allowlistMode is "npm"', async () => {
|
||||||
mockProject({
|
mockProject({
|
||||||
'./docs/x.js': '',
|
'./docs/x.js': '',
|
||||||
|
|
@ -343,63 +404,21 @@ build/
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('autodetects allowlistMode', async () => {
|
it('filters npm export map entries when allowlistMode is "export-map"', async () => {
|
||||||
mockProject({
|
mockProject({
|
||||||
'./dist/bundle.js': '',
|
'./internal/file.js': '',
|
||||||
|
'./non-exposed/file.js': '',
|
||||||
'./package.json': JSON.stringify({
|
'./package.json': JSON.stringify({
|
||||||
files: ['dist'],
|
exports: {
|
||||||
}),
|
'./exposed/*': './internal/*',
|
||||||
'.gitignore': '/dist',
|
},
|
||||||
});
|
|
||||||
const globOutput = InputDataService.gatherFilesFromDir('/fictional/project');
|
|
||||||
expect(globOutput).to.eql([
|
|
||||||
// This means allowlistMode is 'git'
|
|
||||||
]);
|
|
||||||
|
|
||||||
restoreOriginalInputDataPaths();
|
|
||||||
restoreMockedProjects();
|
|
||||||
|
|
||||||
mockProject({
|
|
||||||
'./dist/bundle.js': '',
|
|
||||||
'./package.json': JSON.stringify({
|
|
||||||
files: ['dist'],
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const globOutput2 = InputDataService.gatherFilesFromDir('/fictional/project');
|
const globOutput = InputDataService.gatherFilesFromDir('/fictional/project', {
|
||||||
expect(globOutput2).to.eql([
|
allowlistMode: 'export-map',
|
||||||
// This means allowlistMode is 'npm'
|
});
|
||||||
'/fictional/project/dist/bundle.js',
|
expect(globOutput).to.eql(['./internal/file.js']);
|
||||||
]);
|
});
|
||||||
|
|
||||||
mockProject(
|
|
||||||
{ './dist/bundle.js': '', '.gitignore': '/dist' },
|
|
||||||
{
|
|
||||||
projectName: 'detect-as-npm',
|
|
||||||
projectPath: '/inside/proj/with/node_modules/detect-as-npm',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const globOutput3 = InputDataService.gatherFilesFromDir(
|
|
||||||
'/inside/proj/with/node_modules/detect-as-npm',
|
|
||||||
);
|
|
||||||
expect(globOutput3).to.eql([
|
|
||||||
// This means allowlistMode is 'npm' (even though we found .gitignore)
|
|
||||||
'/inside/proj/with/node_modules/detect-as-npm/dist/bundle.js',
|
|
||||||
]);
|
|
||||||
|
|
||||||
mockProject(
|
|
||||||
{ './dist/bundle.js': '', '.gitignore': '/dist' },
|
|
||||||
{
|
|
||||||
projectName: '@scoped/detect-as-npm',
|
|
||||||
projectPath: '/inside/proj/with/node_modules/@scoped/detect-as-npm',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const globOutput4 = InputDataService.gatherFilesFromDir(
|
|
||||||
'/inside/proj/with/node_modules/@scoped/detect-as-npm',
|
|
||||||
);
|
|
||||||
expect(globOutput4).to.eql([
|
|
||||||
// This means allowlistMode is 'npm' (even though we found .gitignore)
|
|
||||||
'/inside/proj/with/node_modules/@scoped/detect-as-npm/dist/bundle.js',
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('custom "allowlist" will take precedence over "allowlistMode"', async () => {
|
it('custom "allowlist" will take precedence over "allowlistMode"', async () => {
|
||||||
|
|
@ -457,5 +476,185 @@ build/
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('"getPathsFromExportMap"', () => {
|
||||||
|
it('gets "internalExportMapPaths", "exposedExportMapPaths"', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/internal-path.js': 'export const x = 0;',
|
||||||
|
'/my/proj/internal/folder-a/path.js': 'export const a = 1;',
|
||||||
|
'/my/proj/internal/folder-b/path.js': 'export const b = 2;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
|
||||||
|
const exports = {
|
||||||
|
'./exposed-path.js': './internal-path.js',
|
||||||
|
'./external/*/path.js': './internal/*/path.js',
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './internal-path.js', exposed: './exposed-path.js' },
|
||||||
|
{ internal: './internal/folder-a/path.js', exposed: './external/folder-a/path.js' },
|
||||||
|
{ internal: './internal/folder-b/path.js', exposed: './external/folder-b/path.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports 1-on-1 path maps in export map entry', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/internal-path.js': 'export const x = 0;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./exposed-path.js': './internal-path.js',
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './internal-path.js', exposed: './exposed-path.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports "./*" root mappings', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/internal-exports-folder/file-a.js': 'export const x = 0;',
|
||||||
|
'/my/proj/internal-exports-folder/file-b.js': 'export const x = 0;',
|
||||||
|
'/my/proj/internal-exports-folder/file-c.js': 'export const x = 0;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./*': './internal-exports-folder/*',
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './internal-exports-folder/file-a.js', exposed: './file-a.js' },
|
||||||
|
{ internal: './internal-exports-folder/file-b.js', exposed: './file-b.js' },
|
||||||
|
{ internal: './internal-exports-folder/file-c.js', exposed: './file-c.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports "*" on file level inside key and value of export map entry', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/internal-folder/file-a.js': 'export const a = 1;',
|
||||||
|
'/my/proj/internal-folder/file-b.js': 'export const b = 2;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./exposed-folder/*.js': './internal-folder/*.js',
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './internal-folder/file-a.js', exposed: './exposed-folder/file-a.js' },
|
||||||
|
{ internal: './internal-folder/file-b.js', exposed: './exposed-folder/file-b.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports "*" on folder level inside key and value of export map entry', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/folder-a/file.js': 'export const a = 1;',
|
||||||
|
'/my/proj/folder-b/file.js': 'export const b = 2;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
// Hypothetical example that indicates the * can be placed everywhere
|
||||||
|
'./exposed-folder/*/file.js': './*/file.js',
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './folder-a/file.js', exposed: './exposed-folder/folder-a/file.js' },
|
||||||
|
{ internal: './folder-b/file.js', exposed: './exposed-folder/folder-b/file.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ResolveMode', () => {
|
||||||
|
it('has nodeResolveMode "default" when nothing specified', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/esm-exports/file.js': 'export const x = 0;',
|
||||||
|
'/my/proj/cjs-exports/file.cjs': 'export const x = 0;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./*': { default: './esm-exports/*', require: './cjs-exports/*' },
|
||||||
|
};
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './esm-exports/file.js', exposed: './file.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports nodeResolveMode "require"', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/esm-exports/file.js': 'export const x = 0;',
|
||||||
|
'/my/proj/cjs-exports/file.cjs': 'export const x = 0;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./*': { default: './esm-exports/*', require: './cjs-exports/*' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
nodeResolveMode: 'require',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './cjs-exports/file.cjs', exposed: './file.cjs' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports other arbitrary nodeResolveModes (like "develop")', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/esm-exports/file.js': 'export const x = 0;',
|
||||||
|
'/my/proj/develop-exports/file.js': 'export const x = 0;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
const exports = {
|
||||||
|
'./*': { default: './esm-exports/*', develop: './develop-exports/*' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
nodeResolveMode: 'develop',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './develop-exports/file.js', exposed: './file.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('without "*" in key', async () => {
|
||||||
|
const fakeFs = {
|
||||||
|
'/my/proj/index.js': 'export const a = 1;',
|
||||||
|
'/my/proj/file.js': 'export const b = 2;',
|
||||||
|
};
|
||||||
|
mock(fakeFs);
|
||||||
|
|
||||||
|
const exports = {
|
||||||
|
'.': {
|
||||||
|
default: './index.js',
|
||||||
|
},
|
||||||
|
'./exposed-file.js': {
|
||||||
|
default: './file.js',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportMapPaths = await InputDataService.getPathsFromExportMap(exports, {
|
||||||
|
packageRootPath: '/my/proj',
|
||||||
|
});
|
||||||
|
expect(exportMapPaths).to.eql([
|
||||||
|
{ internal: './index.js', exposed: '.' },
|
||||||
|
{ internal: './file.js', exposed: './exposed-file.js' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue