Skip to content

Commit

Permalink
feat: substitute aliased modules
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-pribilinskiy committed Feb 19, 2024
1 parent 2e57cee commit 2479783
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { FederationConfig } from '../../../models';
import { setLogger } from '../../../helpers';
import { includeTypesFromNodeModules } from '../includeTypesFromNodeModules';

// Assuming logger mock setup is similar to previous example
const mockLogger = {
log: jest.fn(),
warn: jest.fn(),
};

setLogger(mockLogger);

describe('includeTypesFromNodeModules', () => {
test('correctly includes typings for exposed NPM packages', () => {
const federationConfig: FederationConfig = {
name: 'myApp',
exposes: {
ModuleA: './node_modules/libraryA',
ModuleB: './node_modules/libraryB',
},
};
const initialTypings = 'initial typings content';

const result = includeTypesFromNodeModules(federationConfig, initialTypings);

const moduleADeclaration = [
'declare module "myApp/ModuleA" {',
' export * from "libraryA"',
'}',
].join('\n');
const moduleBDeclaration = [
'declare module "myApp/ModuleB" {',
' export * from "libraryB"',
'}',
].join('\n');

expect(result).toBe([initialTypings, moduleADeclaration, moduleBDeclaration].join('\n'));
expect(mockLogger.log).toHaveBeenCalledWith('Including typings for npm packages:', [
['ModuleA', 'libraryA'],
['ModuleB', 'libraryB'],
]);
});

test('does not modify typings when there are no NPM package paths', () => {
const federationConfig: FederationConfig = {
name: 'myApp',
exposes: {
LocalModule: './src/LocalModule',
},
};
const initialTypings = 'initial typings content';

const result = includeTypesFromNodeModules(federationConfig, initialTypings);

expect(result).toBe(initialTypings);
expect(mockLogger.log).not.toHaveBeenCalledWith();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { substituteAliasedModules } from '../substituteAliasedModules';
import {
getLogger, setLogger,
} from '../../../helpers';
import { PREFIX_NOT_FOR_IMPORT } from '../../../constants';

const mockLogger = {
log: jest.fn(),
};

setLogger(mockLogger);

describe('substituteAliasedModules', () => {
const federatedModuleName = 'myCommon';
const logger = getLogger();

test('substitutes import path when #not-for-import version exists', () => {
const modulePath = 'libs/currency';
const typings = `
Some import("${modulePath}") more content
declare module "${PREFIX_NOT_FOR_IMPORT}/${federatedModuleName}/${modulePath}"
`;

const subsituted = substituteAliasedModules(federatedModuleName, typings);

expect(subsituted).toBe(`
Some import("${PREFIX_NOT_FOR_IMPORT}/${federatedModuleName}/${modulePath}") more content
declare module "${PREFIX_NOT_FOR_IMPORT}/${federatedModuleName}/${modulePath}"
`);
expect(logger.log).toHaveBeenCalledWith(`Substituting import path: ${modulePath}`);
});

test('does not modify typings when a #not-for-import version does not exist', () => {
const originalTypings = 'Some content import("another/module") more content';

const result = substituteAliasedModules(federatedModuleName, originalTypings);

expect(result).toBe(originalTypings);
expect(logger.log).not.toHaveBeenCalled();
});
});
11 changes: 5 additions & 6 deletions src/compileTypes/helpers/includeTypesFromNodeModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ export function includeTypesFromNodeModules(federationConfig: FederationConfig,
exposeTargetPath.replace('./node_modules/', ''),
]);

// language=TypeScript
const createNpmModule = (exposedModuleKey: string, packageName: string) => `
declare module "${federationConfig.name}/${exposedModuleKey}" {
export * from "${packageName}"
}
`;
const createNpmModule = (exposedModuleKey: string, packageName: string) => [
`declare module "${federationConfig.name}/${exposedModuleKey}" {`,
` export * from "${packageName}"`,
'}',
].join('\n');

if (exposedNpmPackages.length) {
logger.log('Including typings for npm packages:', exposedNpmPackages);
Expand Down
1 change: 1 addition & 0 deletions src/compileTypes/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './getTSConfigCompilerOptions';
export * from './includeTypesFromNodeModules';
export * from './reportCompileDiagnostic';
export * from './substituteAliasedModules';
31 changes: 31 additions & 0 deletions src/compileTypes/helpers/substituteAliasedModules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getLogger } from '../../helpers';
import { PREFIX_NOT_FOR_IMPORT } from '../../constants';

export function substituteAliasedModules(federatedModuleName: string, typings: string): string {
const logger = getLogger();

// Collect all instances of `import("...")`
const regexImportPaths = /import\("([^"]*)"\)/g;
const uniqueImportPaths = new Set();

let match = regexImportPaths.exec(typings);
while (match) {
uniqueImportPaths.add(match[1]);
match = regexImportPaths.exec(typings);
}

uniqueImportPaths.forEach(importPath => {
const notForImportPath = `${PREFIX_NOT_FOR_IMPORT}/${federatedModuleName}/${importPath}`;

if (typings.includes(`declare module "${notForImportPath}"`)) {
logger.log(`Substituting import path: ${importPath}`);

typings = typings.replace(
new RegExp(`import\\("${importPath}"\\)`, 'g'),
`import("${notForImportPath}")`,
);
}
});

return typings;
}
8 changes: 6 additions & 2 deletions src/compileTypes/rewritePathsWithExposedFederatedModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import fs from 'fs';
import mkdirp from 'mkdirp';

import { FederationConfig } from '../models';
import { PREFIX_NOT_FOR_IMPORT } from '../constants';

import { includeTypesFromNodeModules } from './helpers';
import {
includeTypesFromNodeModules, substituteAliasedModules,
} from './helpers';

export function rewritePathsWithExposedFederatedModules(
federationConfig: FederationConfig,
Expand Down Expand Up @@ -38,7 +41,7 @@ export function rewritePathsWithExposedFederatedModules(

let federatedModulePath = exposedModuleKey
? `${federationConfig.name}/${exposedModuleKey}`
: `#not-for-import/${federationConfig.name}/${importPath}`;
: `${PREFIX_NOT_FOR_IMPORT}/${federationConfig.name}/${importPath}`;

federatedModulePath = federatedModulePath.replace(/\/index$/, '');

Expand All @@ -55,6 +58,7 @@ export function rewritePathsWithExposedFederatedModules(
].join('\n');
});

typingsUpdated = substituteAliasedModules(federationConfig.name, typingsUpdated);
typingsUpdated = includeTypesFromNodeModules(federationConfig, typingsUpdated);

mkdirp.sync(path.dirname(outFile));
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const DEFAULT_DIR_GLOBAL_TYPES = 'src/@types';
export const DEFAULT_DIR_DOWNLOADED_TYPES = 'src/@types/remotes';

export const DEFAULT_DOWNLOAD_TYPES_INTERVAL_IN_SECONDS = 60;

export const PREFIX_NOT_FOR_IMPORT = '#not-for-import';

1 comment on commit 2479783

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🔴 Statements 55.44% 214/386
🔴 Branches 37.96% 41/108
🔴 Functions 38.6% 22/57
🔴 Lines 55.35% 212/383

Test suite run success

16 tests passing in 5 suites.

Report generated by 🧪jest coverage report action from 2479783

Please sign in to comment.