@cordy/electro-generator 1.2.11 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +28 -24
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -71,8 +71,9 @@ contextBridge.exposeInMainWorld("electro", ${featureEntries.length > 0 ? `{\n${f
71
71
  * Generate bridge type declarations for a specific view.
72
72
  * Makes `window.electro` type-safe in the renderer.
73
73
  */
74
- function generateBridgeTypes(viewName, features, policy) {
75
- const allowedFeatures = features.filter((f) => policy.canAccess(viewName, f.id));
74
+ function generateBridgeTypes(view, features, policy) {
75
+ const allowedFeatures = features.filter((f) => policy.canAccess(view.name, f.id));
76
+ const bridgeModulePath = join(dirname(view.__source), "bridge.gen.ts");
76
77
  const featureTypes = [];
77
78
  for (const feature of allowedFeatures) {
78
79
  const exposedServices = feature.services.filter((s) => s.scope === "exposed");
@@ -81,39 +82,42 @@ function generateBridgeTypes(viewName, features, policy) {
81
82
  continue;
82
83
  }
83
84
  const serviceTypes = [];
84
- for (const service of exposedServices) {
85
- if (service.methods.length === 0) {
86
- serviceTypes.push(` ${q(service.id)}: Record<string, never>;`);
87
- continue;
88
- }
89
- const methodTypes = service.methods.map((m) => ` ${q(m)}(...args: unknown[]): Promise<unknown>;`).join("\n");
90
- serviceTypes.push(` ${q(service.id)}: {\n${methodTypes}\n };`);
91
- }
85
+ for (const service of exposedServices) if (service.exported) {
86
+ const importPath = toImportPathFrom(bridgeModulePath, service.filePath);
87
+ serviceTypes.push(` ${q(service.id)}: _SvcApi<typeof import("${importPath}").${service.varName}>;`);
88
+ } else serviceTypes.push(` ${q(service.id)}: unknown;`);
92
89
  featureTypes.push(` ${q(feature.id)}: {\n${serviceTypes.join("\n")}\n };`);
93
90
  }
94
- const eventKeys = [];
95
- for (const feature of allowedFeatures) for (const evt of feature.events ?? []) eventKeys.push(`"${feature.id}:${evt.id}"`);
96
- if (allowedFeatures.length > 0) {
97
- const channelType = eventKeys.length > 0 ? eventKeys.join(" | ") : "string";
98
- featureTypes.push(` events: {\n on(channel: ${channelType} | (string & {}), handler: (payload: unknown) => void): () => void;\n };`);
91
+ const eventTypeEntries = [];
92
+ for (const feature of allowedFeatures) for (const evt of feature.events ?? []) {
93
+ const eventKey = `${feature.id}:${evt.id}`;
94
+ if (evt.exported) {
95
+ const importPath = toImportPathFrom(bridgeModulePath, evt.filePath);
96
+ eventTypeEntries.push(` ${JSON.stringify(eventKey)}: _EventPayload<typeof import("${importPath}").${evt.varName}>;`);
97
+ } else eventTypeEntries.push(` ${JSON.stringify(eventKey)}: unknown;`);
99
98
  }
99
+ const eventMapTypes = eventTypeEntries.length > 0 ? `\ntype ElectroEventMap = {\n${eventTypeEntries.join("\n")}\n};` : "";
100
+ if (allowedFeatures.length > 0) if (eventTypeEntries.length > 0) featureTypes.push(` events: {\n on<K extends keyof ElectroEventMap>(channel: K, handler: (payload: ElectroEventMap[K]) => void): () => void;\n on(channel: string & {}, handler: (payload: unknown) => void): () => void;\n };`);
101
+ else featureTypes.push(` events: {\n on(channel: string & {}, handler: (payload: unknown) => void): () => void;\n };`);
100
102
  const content = `${HEADER}
101
- export interface ElectroBridge ${featureTypes.length > 0 ? `{\n${featureTypes.join("\n")}\n }` : "{}"}
103
+ type _SvcApi<T> = T extends { api(): infer R } ? NonNullable<R> : never;
104
+ type _EventPayload<T> = T extends { payload(): infer P } ? P : unknown;${eventMapTypes}
102
105
 
103
- declare global {
104
- interface Window {
105
- electro: ElectroBridge;
106
- }
107
- }
106
+ export interface ElectroBridge ${featureTypes.length > 0 ? `{\n${featureTypes.join("\n")}\n }` : "{}"}
108
107
  `;
109
108
  return {
110
- path: `generated/views/${viewName}.bridge.d.ts`,
109
+ path: `generated/views/${view.name}.bridge.d.ts`,
111
110
  content
112
111
  };
113
112
  }
114
113
  /** Calculate the import path from the generated env types file to a source file. */
114
+ function toImportPathFrom(outputFilePath, sourceFilePath) {
115
+ const importPath = relative(dirname(outputFilePath), sourceFilePath).replace(/\.(?:[cm]?tsx?|[cm]?jsx?)$/, "");
116
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
117
+ }
118
+ /** Calculate the import path from the generated env types file to a source file. */
115
119
  function toImportPath(envTypesDir, sourceFilePath) {
116
- const importPath = relative(dirname(join(envTypesDir, "electro-env.d.ts")), sourceFilePath).replace(/\.ts$/, "");
120
+ const importPath = relative(dirname(join(envTypesDir, "electro-env.d.ts")), sourceFilePath).replace(/\.(?:[cm]?tsx?|[cm]?jsx?)$/, "");
117
121
  return importPath.startsWith(".") ? importPath : `./${importPath}`;
118
122
  }
119
123
  const FEATURE_TYPES_HEADER = `// Auto-generated by Electro codegen. Do not edit.
@@ -238,7 +242,7 @@ function generate(input) {
238
242
  const knownIds = new Set(scanResult.features.map((f) => f.id));
239
243
  for (const fId of view.features ?? []) if (!knownIds.has(fId)) console.warn(`[generator] View "${view.name}" references unknown feature "${fId}"`);
240
244
  files.push(generatePreload(view.name, scanResult.features, policy, view.preload));
241
- files.push(generateBridgeTypes(view.name, scanResult.features, policy));
245
+ files.push(generateBridgeTypes(view, scanResult.features, policy));
242
246
  }
243
247
  return {
244
248
  files,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordy/electro-generator",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "description": "Code generator for @cordy/electro — scans features and emits preload scripts and bridge types",
5
5
  "license": "MIT",
6
6
  "type": "module",