Skip to content

Commit 3e62d31

Browse files
committed
fix: generate root barrel file in multi-target codegen
generateMulti() was generating per-target barrel files (admin/index.ts, auth/index.ts, etc.) but never creating the root src/index.ts that re-exports all targets as namespaces. The pregenerate script deletes src/index.ts via rimraf, and the codegen never recreated it, causing downstream packages like @constructive-io/node to fail with TS2307: Cannot find module '@constructive-io/sdk'. Adds generateMultiTargetBarrel() which creates: export * as admin from './admin'; export * as auth from './auth'; export * as public_ from './public'; // reserved word alias Called from generateMulti() after all targets complete.
1 parent b0ff4ed commit 3e62d31

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

graphql/codegen/src/core/codegen/barrel.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,59 @@ export function generateRootBarrel(options: RootBarrelOptions = {}): string {
230230
return generateCode(statements);
231231
}
232232

233+
// ============================================================================
234+
// Multi-target root barrel (re-exports each target as a namespace)
235+
// ============================================================================
236+
237+
/** JS reserved words that need an alias when used as export names */
238+
const JS_RESERVED = new Set([
239+
'abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch',
240+
'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do',
241+
'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final',
242+
'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import',
243+
'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new',
244+
'null', 'package', 'private', 'protected', 'public', 'return', 'short',
245+
'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws',
246+
'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while',
247+
'with', 'yield',
248+
]);
249+
250+
/**
251+
* Generate a root index.ts for multi-target output that re-exports each
252+
* target as a namespace.
253+
*
254+
* Example output:
255+
* export * as admin from './admin';
256+
* export * as auth from './auth';
257+
* export * as public_ from './public';
258+
*/
259+
export function generateMultiTargetBarrel(targetNames: string[]): string {
260+
const statements: t.Statement[] = [];
261+
262+
for (const name of targetNames) {
263+
const alias = JS_RESERVED.has(name) ? `${name}_` : name;
264+
const exportDecl = t.exportNamedDeclaration(
265+
null,
266+
[t.exportNamespaceSpecifier(t.identifier(alias))],
267+
t.stringLiteral(`./${name}`),
268+
);
269+
statements.push(exportDecl);
270+
}
271+
272+
if (statements.length > 0) {
273+
addJSDocComment(statements[0], [
274+
'@constructive-io/sdk',
275+
'',
276+
'Auto-generated GraphQL types and ORM client.',
277+
'Run `pnpm run generate` to populate this package from the schema files.',
278+
'',
279+
'@generated by @constructive-io/graphql-codegen',
280+
]);
281+
}
282+
283+
return generateCode(statements);
284+
}
285+
233286
// ============================================================================
234287
// Custom operation barrels (includes both table and custom hooks)
235288
// ============================================================================

graphql/codegen/src/core/generate.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { CliConfig, DbConfig, GraphQLSDKConfigTarget, PgpmConfig, SchemaCon
1818
import { getConfigOptions } from '../types/config';
1919
import type { Operation, Table, TypeRegistry } from '../types/schema';
2020
import { generate as generateReactQueryFiles } from './codegen';
21-
import { generateRootBarrel } from './codegen/barrel';
21+
import { generateRootBarrel, generateMultiTargetBarrel } from './codegen/barrel';
2222
import { generateCli as generateCliFiles, generateMultiTargetCli } from './codegen/cli';
2323
import type { MultiTargetCliTarget } from './codegen/cli';
2424
import {
@@ -827,16 +827,35 @@ export async function generateMulti(
827827
}
828828
}
829829

830-
// Generate root-root README if multi-target
830+
// Generate root-root README and barrel if multi-target
831831
if (names.length > 1 && targetInfos.length > 0 && !dryRun) {
832-
const rootReadme = generateRootRootReadme(targetInfos);
833832
const { writeGeneratedFiles: writeFiles } = await import('./output');
833+
834+
const rootReadme = generateRootRootReadme(targetInfos);
834835
await writeFiles(
835836
[{ path: rootReadme.fileName, content: rootReadme.content }],
836837
'.',
837838
[],
838839
{ pruneStaleFiles: false },
839840
);
841+
842+
// Write a root barrel (index.ts) that re-exports each target as a
843+
// namespace so the package has a single entry-point. Derive the
844+
// common output root from the first target's output path.
845+
const successfulNames = results
846+
.filter((r) => r.result.success)
847+
.map((r) => r.name);
848+
if (successfulNames.length > 0) {
849+
const firstOutput = getConfigOptions(configs[successfulNames[0]]).output;
850+
const outputRoot = path.dirname(firstOutput);
851+
const barrelContent = generateMultiTargetBarrel(successfulNames);
852+
await writeFiles(
853+
[{ path: 'index.ts', content: barrelContent }],
854+
outputRoot,
855+
[],
856+
{ pruneStaleFiles: false },
857+
);
858+
}
840859
}
841860

842861
} finally {

0 commit comments

Comments
 (0)