Skip to content

Commit 362b38f

Browse files
committed
fix(nx-infra-plugin): handle flat transpile layout in state-manager-optimize and fail fast
1 parent 4383cd1 commit 362b38f

2 files changed

Lines changed: 85 additions & 30 deletions

File tree

packages/nx-infra-plugin/src/executors/state-manager-optimize/executor.e2e.spec.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3+
import { logger } from '@nx/devkit';
34
import executor from './executor';
45
import { StateManagerOptimizeExecutorSchema } from './schema';
56
import {
@@ -37,9 +38,9 @@ describe('StateManagerOptimizeExecutor E2E', () => {
3738
const indexPathFor = (variant: Variant): string =>
3839
path.join(stateManagerAbsoluteFor(variant), 'index.js');
3940

40-
const runOptimize = async (): Promise<void> => {
41+
const runOptimize = async (): Promise<{ success: boolean }> => {
4142
const options: StateManagerOptimizeExecutorSchema = { transpiledDirs: [TRANSPILED_DIR] };
42-
await executor(options, context);
43+
return executor(options, context);
4344
};
4445

4546
beforeEach(async () => {
@@ -98,4 +99,51 @@ describe('StateManagerOptimizeExecutor E2E', () => {
9899
const cjsIndexContent = await readFileText(indexPathFor('cjs'));
99100
expect(cjsIndexContent).toContain('require("./prod/index")');
100101
}, 30000);
102+
103+
it('should optimize index.js when state_manager lives at flat root layout (no cjs/esm variant subdir)', async () => {
104+
const flatStateManagerDir = path.join(projectDir, TRANSPILED_DIR, STATE_MANAGER_RELATIVE_PATH);
105+
await writeFileText(path.join(flatStateManagerDir, 'index.js'), INDEX_DEV_CONTENT);
106+
await writeFileText(path.join(flatStateManagerDir, 'dev', 'index.js'), DEV_FILE_CONTENT);
107+
await writeFileText(path.join(flatStateManagerDir, 'prod', 'index.js'), PROD_FILE_CONTENT);
108+
await writeFileText(
109+
path.join(flatStateManagerDir, 'state_manager.test.js'),
110+
TOP_LEVEL_NON_INDEX_CONTENT,
111+
);
112+
113+
await runOptimize();
114+
115+
expect(await readFileText(path.join(flatStateManagerDir, 'index.js'))).toBe(INDEX_PROD_CONTENT);
116+
expect(fs.existsSync(path.join(flatStateManagerDir, 'dev'))).toBe(false);
117+
expect(fs.existsSync(path.join(flatStateManagerDir, 'state_manager.test.js'))).toBe(false);
118+
expect(await readFileText(path.join(flatStateManagerDir, 'prod', 'index.js'))).toBe(
119+
PROD_FILE_CONTENT,
120+
);
121+
}, 30000);
122+
123+
it('should optimize state_manager at any depth (mixed flat + nested in same tree)', async () => {
124+
const flatStateManagerDir = path.join(projectDir, TRANSPILED_DIR, STATE_MANAGER_RELATIVE_PATH);
125+
await writeFileText(path.join(flatStateManagerDir, 'index.js'), INDEX_DEV_CONTENT);
126+
await writeFileText(path.join(flatStateManagerDir, 'dev', 'index.js'), DEV_FILE_CONTENT);
127+
await writeFileText(path.join(flatStateManagerDir, 'prod', 'index.js'), PROD_FILE_CONTENT);
128+
129+
await runOptimize();
130+
131+
expect(await readFileText(path.join(flatStateManagerDir, 'index.js'))).toBe(INDEX_PROD_CONTENT);
132+
expect(await readFileText(indexPathFor('cjs'))).toContain('require("./prod/index")');
133+
}, 30000);
134+
135+
it('should throw when no state_manager directories are found in any transpiledDir', async () => {
136+
const errorSpy = jest.spyOn(logger, 'error').mockImplementation(() => undefined);
137+
138+
const options: StateManagerOptimizeExecutorSchema = {
139+
transpiledDirs: ['./artifacts/transpiled-no-state-manager'],
140+
};
141+
const result = await executor(options, context);
142+
143+
expect(result.success).toBe(false);
144+
const errorMessage = String(errorSpy.mock.calls[0][0]);
145+
expect(errorMessage).toContain('No state_manager/index.js');
146+
147+
errorSpy.mockRestore();
148+
}, 30000);
101149
});
Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
import * as fs from 'fs-extra';
21
import * as path from 'path';
32
import * as babel from '@babel/core';
3+
import { glob } from 'glob';
44
import { logger } from '@nx/devkit';
55
import { createExecutor } from '../../utils/create-executor';
66
import { writeFileText } from '../../utils/file-operations';
77
import { removeDirectoryRespectingExclusions } from '../clean/clean.impl';
8+
import { toPosixPath } from '../../utils/path-resolver';
89
import { StateManagerOptimizeExecutorSchema } from './schema';
910

1011
const ESM_REEXPORT = "export * from './prod/index';";
11-
const STATE_MANAGER_REL_PATH = path.join('__internal', 'core', 'state_manager');
12+
const STATE_MANAGER_INDEX_GLOB = '**/__internal/core/state_manager/index.js';
1213
const ERROR_BABEL_NO_CODE = 'Babel returned no code for CJS state_manager index.js';
14+
const ERROR_NO_STATE_MANAGER_FOUND =
15+
'No state_manager/index.js found in any configured transpiledDirs';
1316

14-
const VARIANTS = ['esm', 'cjs'] as const;
15-
type Variant = (typeof VARIANTS)[number];
16-
type ContentBuilder = (indexPath: string) => string;
17-
18-
function transformReexportToCjs(indexPath: string): string {
17+
export function transformReexportToCjs(indexPath: string): string {
1918
const result = babel.transformSync(ESM_REEXPORT, {
2019
filename: indexPath,
2120
plugins: [['@babel/plugin-transform-modules-commonjs']],
@@ -28,33 +27,33 @@ function transformReexportToCjs(indexPath: string): string {
2827
return result.code;
2928
}
3029

31-
const CONTENT_BUILDERS: Record<Variant, ContentBuilder> = {
32-
esm: () => ESM_REEXPORT,
33-
cjs: (indexPath) => transformReexportToCjs(indexPath),
34-
};
35-
36-
async function optimizeVariant(variant: Variant, transpiledRoot: string): Promise<void> {
37-
const stateManagerDir = path.join(transpiledRoot, variant, STATE_MANAGER_REL_PATH);
38-
39-
if (!fs.existsSync(stateManagerDir)) {
40-
logger.verbose(`Skipping ${variant} state_manager: ${stateManagerDir} does not exist`);
41-
return;
42-
}
30+
function isCjsFile(filePath: string): boolean {
31+
return toPosixPath(filePath).includes('/cjs/');
32+
}
4333

44-
const indexPath = path.join(stateManagerDir, 'index.js');
45-
if (fs.existsSync(indexPath)) {
46-
await writeFileText(indexPath, CONTENT_BUILDERS[variant](indexPath));
47-
}
34+
async function optimizeIndexFile(indexPath: string): Promise<void> {
35+
const content = isCjsFile(indexPath) ? transformReexportToCjs(indexPath) : ESM_REEXPORT;
36+
await writeFileText(indexPath, content);
4837

38+
const stateManagerDir = path.dirname(indexPath);
4939
await removeDirectoryRespectingExclusions(stateManagerDir, [
5040
indexPath,
5141
path.join(stateManagerDir, 'prod'),
5242
]);
5343
}
5444

55-
async function optimizeTranspiledDir(transpiledDir: string, projectRoot: string): Promise<void> {
56-
const transpiledRoot = path.join(projectRoot, transpiledDir);
57-
await Promise.all(VARIANTS.map((variant) => optimizeVariant(variant, transpiledRoot)));
45+
async function optimizeTranspiledDir(transpiledRoot: string): Promise<number> {
46+
const indexFiles = await glob(STATE_MANAGER_INDEX_GLOB, {
47+
cwd: toPosixPath(transpiledRoot),
48+
absolute: true,
49+
nodir: true,
50+
});
51+
52+
logger.verbose(`Found ${indexFiles.length} state_manager index.js file(s) in ${transpiledRoot}`);
53+
54+
await Promise.all(indexFiles.map(optimizeIndexFile));
55+
56+
return indexFiles.length;
5857
}
5958

6059
interface ResolvedStateManagerOptimize {
@@ -73,10 +72,18 @@ export default createExecutor<StateManagerOptimizeExecutorSchema, ResolvedStateM
7372
`Optimizing state_manager modules in ${resolved.transpiledDirs.length} transpiled tree(s)`,
7473
);
7574

76-
await Promise.all(
75+
const counts = await Promise.all(
7776
resolved.transpiledDirs.map((transpiledDir) =>
78-
optimizeTranspiledDir(transpiledDir, resolved.projectRoot),
77+
optimizeTranspiledDir(path.join(resolved.projectRoot, transpiledDir)),
7978
),
8079
);
80+
81+
const totalFound = counts.reduce((sum, count) => sum + count, 0);
82+
83+
if (totalFound === 0) {
84+
throw new Error(
85+
`${ERROR_NO_STATE_MANAGER_FOUND}: ${resolved.transpiledDirs.join(', ')}. Check transpile output layout or transpiledDirs option.`,
86+
);
87+
}
8188
},
8289
});

0 commit comments

Comments
 (0)