Skip to content

Commit 06ed3e9

Browse files
committed
chore(repo): change to file based nx-payload plugin
closed COD-346
1 parent 268bf7e commit 06ed3e9

6 files changed

Lines changed: 248 additions & 30 deletions

File tree

nx.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@
268268
"serveStaticTargetName": "serve-static"
269269
}
270270
},
271-
"@cdwr/nx-payload/plugin"
271+
"./packages/nx-payload/plugin.ts"
272272
]
273273
}

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
"devDependencies": {
8686
"@babel/core": "^7.14.5",
8787
"@babel/preset-react": "^7.14.5",
88-
"@cdwr/nx-payload": "2.0.0",
8988
"@clack/prompts": "^0.11.0",
9089
"@commitlint/cli": "^19.0.0",
9190
"@commitlint/config-angular": "^19.0.0",

packages/nx-payload/src/plugins/utils/create-payload-nodes.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { readFile } from 'fs/promises';
21
import { dirname, join, relative } from 'path/posix';
32

43
import {
@@ -15,6 +14,7 @@ import { getLockFileName } from '@nx/js';
1514

1615
import { createPayloadTargets } from '../../utils/create-payload-targets';
1716
import { findUpFs } from '../../utils/find-up-fs';
17+
import { isGraphQLDisabled } from '../../utils/is-graphql-disabled';
1818

1919
import {
2020
type PayloadPluginOptions,
@@ -41,8 +41,9 @@ export const createPayloadNodes = async (
4141
// Convert to POSIX on Windows (workspacePath is os formatted)
4242
const workspaceRoot = normalizePath(context.workspaceRoot);
4343

44-
// configFilePath is POSIX formatted
44+
// configFilePath is POSIX formatted, convert to absolute OS-specific paths for file reading
4545
const configRoot = dirname(configFilePath);
46+
const fullConfigPath = join(workspaceRoot, configFilePath);
4647
const fullConfigRoot = join(workspaceRoot, configRoot);
4748

4849
// Payload config file can be located anywhere, though it's generated initially in the 'src' folder.
@@ -65,24 +66,21 @@ export const createPayloadNodes = async (
6566
readJsonFile<ProjectConfiguration>(projectJsonPath);
6667

6768
// Get current GraphQL config state
68-
const configContent = await readFile(configFilePath, 'utf-8');
69-
const isGraphQLDisabled = /graphQL:\s*\{[^}]*disable:\s*true[^}]*\}/.test(
70-
configContent
71-
);
69+
const graphQLDisabled = await isGraphQLDisabled(fullConfigPath);
7270

7371
const hash = await calculateHashForCreateNodes(
7472
projectRoot,
7573
normalizePluginOptions(options),
7674
context,
7775
[
7876
getLockFileName(detectPackageManager(workspaceRoot)),
79-
String(isGraphQLDisabled)
77+
String(graphQLDisabled)
8078
]
8179
);
8280

8381
// Get payload targets to be inferred for the project
8482
targetsCache[hash] ??= createPayloadTargets({
85-
isGraphQLDisabled,
83+
isGraphQLDisabled: graphQLDisabled,
8684
projectName: String(projectName), // Should have a value by design?
8785
projectRoot
8886
});
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import { readFile } from 'fs/promises';
2+
3+
import { isGraphQLDisabled } from './is-graphql-disabled';
4+
5+
jest.mock('fs/promises');
6+
7+
describe('isGraphQLDisabled', () => {
8+
const mockReadFile = jest.mocked(readFile);
9+
10+
beforeEach(() => {
11+
jest.clearAllMocks();
12+
});
13+
14+
afterEach(() => {
15+
jest.restoreAllMocks();
16+
});
17+
18+
it('should return true when graphQL.disable is true (basic format)', async () => {
19+
const content = `
20+
export default buildConfig({
21+
graphQL: { disable: true }
22+
})
23+
`;
24+
mockReadFile.mockResolvedValue(content);
25+
26+
const result = await isGraphQLDisabled('/path/to/config.ts');
27+
28+
expect(result).toBe(true);
29+
expect(mockReadFile).toHaveBeenCalledWith('/path/to/config.ts', 'utf-8');
30+
});
31+
32+
it('should return true when graphQL.disable is true (with trailing comma)', async () => {
33+
const content = `
34+
export default buildConfig({
35+
graphQL: { disable: true, }
36+
})
37+
`;
38+
mockReadFile.mockResolvedValue(content);
39+
40+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
41+
});
42+
43+
it('should return true when disable is first property', async () => {
44+
const content = `
45+
export default buildConfig({
46+
graphQL: {
47+
disable: true,
48+
schema: { /* ... */ }
49+
}
50+
})
51+
`;
52+
mockReadFile.mockResolvedValue(content);
53+
54+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
55+
});
56+
57+
it('should return true when disable is middle property', async () => {
58+
const content = `
59+
export default buildConfig({
60+
graphQL: {
61+
schema: { /* ... */ },
62+
disable: true,
63+
playground: false
64+
}
65+
})
66+
`;
67+
mockReadFile.mockResolvedValue(content);
68+
69+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
70+
});
71+
72+
it('should return true when disable is last property', async () => {
73+
const content = `
74+
export default buildConfig({
75+
graphQL: {
76+
schema: { /* ... */ },
77+
disable: true
78+
}
79+
})
80+
`;
81+
mockReadFile.mockResolvedValue(content);
82+
83+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
84+
});
85+
86+
it('should return true with no spaces around colons', async () => {
87+
const content = `
88+
export default buildConfig({
89+
graphQL:{disable:true}
90+
})
91+
`;
92+
mockReadFile.mockResolvedValue(content);
93+
94+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
95+
});
96+
97+
it('should return true with multiple newlines and spaces', async () => {
98+
const content = `
99+
export default buildConfig({
100+
graphQL: {
101+
102+
disable: true
103+
104+
}
105+
})
106+
`;
107+
mockReadFile.mockResolvedValue(content);
108+
109+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(true);
110+
});
111+
112+
it('should return false when graphQL.disable is false', async () => {
113+
const content = `
114+
export default buildConfig({
115+
graphQL: { disable: false }
116+
})
117+
`;
118+
mockReadFile.mockResolvedValue(content);
119+
120+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
121+
});
122+
123+
it('should return false when graphQL.disable is missing', async () => {
124+
const content = `
125+
export default buildConfig({
126+
graphQL: { schema: { /* ... */ } }
127+
})
128+
`;
129+
mockReadFile.mockResolvedValue(content);
130+
131+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
132+
});
133+
134+
it('should return false when graphQL config is missing', async () => {
135+
const content = `
136+
export default buildConfig({
137+
collections: []
138+
})
139+
`;
140+
mockReadFile.mockResolvedValue(content);
141+
142+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
143+
});
144+
145+
it('should not match commented out disable', async () => {
146+
const content = `
147+
export default buildConfig({
148+
graphQL: {
149+
// disable: true
150+
schema: { /* ... */ }
151+
}
152+
})
153+
`;
154+
mockReadFile.mockResolvedValue(content);
155+
156+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
157+
});
158+
159+
it('should return false when file read fails', async () => {
160+
const consoleWarnSpy = jest
161+
.spyOn(console, 'warn')
162+
.mockImplementation(() => {
163+
// Suppress console output during tests
164+
});
165+
mockReadFile.mockRejectedValue(new Error('File not found'));
166+
167+
const result = await isGraphQLDisabled('/path/to/config.ts');
168+
169+
expect(result).toBe(false);
170+
expect(consoleWarnSpy).toHaveBeenCalledWith(
171+
expect.stringContaining('Failed to check GraphQL status'),
172+
'File not found'
173+
);
174+
175+
consoleWarnSpy.mockRestore();
176+
});
177+
178+
it('should return false when file read throws non-Error', async () => {
179+
const consoleWarnSpy = jest
180+
.spyOn(console, 'warn')
181+
.mockImplementation(() => {
182+
// Suppress console output during tests
183+
});
184+
mockReadFile.mockRejectedValue('Some string error');
185+
186+
const result = await isGraphQLDisabled('/path/to/config.ts');
187+
188+
expect(result).toBe(false);
189+
expect(consoleWarnSpy).toHaveBeenCalledWith(
190+
expect.stringContaining('Failed to check GraphQL status'),
191+
'Some string error'
192+
);
193+
194+
consoleWarnSpy.mockRestore();
195+
});
196+
197+
it('should handle empty file', async () => {
198+
mockReadFile.mockResolvedValue('');
199+
200+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
201+
});
202+
203+
it('should handle malformed content gracefully', async () => {
204+
mockReadFile.mockResolvedValue('{');
205+
206+
expect(await isGraphQLDisabled('/path/to/config.ts')).toBe(false);
207+
});
208+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { readFile } from 'fs/promises';
2+
3+
/**
4+
* Checks if GraphQL is disabled in a Payload config file.
5+
*
6+
* @param configFilePath - Path to the Payload config file
7+
* @returns Promise resolving to true if GraphQL is disabled, false otherwise
8+
*/
9+
export const isGraphQLDisabled = async (
10+
configFilePath: string
11+
): Promise<boolean> => {
12+
try {
13+
const configContent = await readFile(configFilePath, 'utf-8');
14+
15+
// Remove single-line comments to avoid false positives
16+
const contentWithoutComments = configContent.replace(/\/\/.*$/gm, '');
17+
18+
// Match graphQL config with disable: true
19+
// Pattern allows disable property to appear anywhere in the graphQL object
20+
// Handles various formatting: spaces, newlines, with/without trailing commas
21+
// [\s\S]* matches any character including newlines
22+
const pattern = /graphQL:\s*\{[\s\S]*?disable:\s*true[\s\S]*?\}/;
23+
return pattern.test(contentWithoutComments);
24+
} catch (error) {
25+
// If we can't read the file or parse it, assume GraphQL is not disabled
26+
// This prevents the plugin from breaking due to file system errors
27+
console.warn(
28+
`Failed to check GraphQL status in ${configFilePath}:`,
29+
error instanceof Error ? error.message : String(error)
30+
);
31+
return false;
32+
}
33+
};

pnpm-lock.yaml

Lines changed: 0 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)