@cordy/electro-generator 1.2.21 → 1.3.0

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.
package/dist/index.d.mts CHANGED
@@ -2,11 +2,11 @@ import { ViewDefinition } from "@cordy/electro";
2
2
 
3
3
  //#region src/types.d.ts
4
4
  /**
5
- * Codegen scan result types.
6
- *
7
- * These are the shapes the AST scanner produces and the generator consumes.
8
- * First iteration uses method names only — full type extraction is future work.
9
- */
5
+ * Codegen scan result types.
6
+ *
7
+ * These are the shapes the AST scanner produces and the generator consumes.
8
+ * First iteration uses method names only — full type extraction is future work.
9
+ */
10
10
  interface ScannedService {
11
11
  id: string;
12
12
  scope: string;
@@ -67,17 +67,17 @@ interface GeneratorOutput {
67
67
  envTypes: GeneratedFile;
68
68
  }
69
69
  /**
70
- * Generate all output files from scan results and view definitions.
71
- */
70
+ * Generate all output files from scan results and view definitions.
71
+ */
72
72
  declare function generate(input: GeneratorInput): GeneratorOutput;
73
73
  //#endregion
74
74
  //#region src/scanner.d.ts
75
75
  /**
76
- * Scan TypeScript source files and extract feature/service metadata.
77
- *
78
- * @param basePath - Root directory to scan (e.g., `./src`)
79
- * @returns Aggregated scan result with all discovered features and services.
80
- */
76
+ * Scan TypeScript source files and extract feature/service metadata.
77
+ *
78
+ * @param basePath - Root directory to scan (e.g., `./src`)
79
+ * @returns Aggregated scan result with all discovered features and services.
80
+ */
81
81
  declare function scan(basePath: string): Promise<ScanResult>;
82
82
  //#endregion
83
83
  export { type GeneratedFile, type GeneratorInput, type GeneratorOutput, type ScanResult, type ScannedFeature, type ScannedService, type ScannedTask, type ScannedWindow, generate, scan };
package/dist/index.mjs CHANGED
@@ -2,7 +2,6 @@ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
2
2
  import { PolicyEngine } from "@cordy/electro";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { Visitor, parseSync } from "oxc-parser";
5
-
6
5
  //#region src/generator.ts
7
6
  /**
8
7
  * Code Generator — produces preload scripts, bridge types, and context types.
@@ -15,6 +14,9 @@ const HEADER = "// Auto-generated by Electro codegen. Do not edit.\n";
15
14
  function q(name) {
16
15
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
17
16
  }
17
+ function isFeatureScopedService(featureId, serviceId) {
18
+ return featureId === serviceId;
19
+ }
18
20
  /**
19
21
  * Build the IPC stub expression for a single method.
20
22
  * Format: `(...args: unknown[]) => ipcRenderer.invoke("feature:service:method", ...args)`
@@ -37,8 +39,14 @@ function generatePreload(viewName, features, policy, preloadExtensions = []) {
37
39
  featureEntries.push(` ${q(feature.id)}: {},`);
38
40
  continue;
39
41
  }
42
+ const featureMethodEntries = [];
40
43
  const serviceEntries = [];
41
44
  for (const service of exposedServices) {
45
+ if (isFeatureScopedService(feature.id, service.id)) {
46
+ const methodEntries = service.methods.map((m) => ` ${q(m)}: ${methodStub(feature.id, service.id, m)},`).join("\n");
47
+ if (methodEntries.length > 0) featureMethodEntries.push(methodEntries);
48
+ continue;
49
+ }
42
50
  if (service.methods.length === 0) {
43
51
  serviceEntries.push(` ${q(service.id)}: {},`);
44
52
  continue;
@@ -46,7 +54,8 @@ function generatePreload(viewName, features, policy, preloadExtensions = []) {
46
54
  const methodEntries = service.methods.map((m) => ` ${q(m)}: ${methodStub(feature.id, service.id, m)},`).join("\n");
47
55
  serviceEntries.push(` ${q(service.id)}: {\n${methodEntries}\n },`);
48
56
  }
49
- featureEntries.push(` ${q(feature.id)}: {\n${serviceEntries.join("\n")}\n },`);
57
+ const featureBody = [...featureMethodEntries, ...serviceEntries].join("\n");
58
+ featureEntries.push(` ${q(feature.id)}: {\n${featureBody}\n },`);
50
59
  }
51
60
  if (allowedFeatures.length > 0) featureEntries.push(` events: {
52
61
  on: (channel: string, handler: (...args: unknown[]) => void) => {
@@ -94,12 +103,21 @@ function generateBridgeTypes(view, features, policy) {
94
103
  featureTypes.push(` ${q(feature.id)}: Record<string, never>;`);
95
104
  continue;
96
105
  }
106
+ let featureScopedType = null;
97
107
  const serviceTypes = [];
98
- for (const service of exposedServices) if (service.exported) {
108
+ for (const service of exposedServices) {
99
109
  const importPath = toImportPathFrom(bridgeModulePath, service.filePath);
100
- serviceTypes.push(` ${q(service.id)}: _SvcApi<typeof import("${importPath}").${service.varName}>;`);
101
- } else serviceTypes.push(` ${q(service.id)}: unknown;`);
102
- featureTypes.push(` ${q(feature.id)}: {\n${serviceTypes.join("\n")}\n };`);
110
+ const serviceType = service.exported ? `_SvcApi<typeof import("${importPath}").${service.varName}>` : "unknown";
111
+ if (isFeatureScopedService(feature.id, service.id)) {
112
+ featureScopedType = serviceType;
113
+ continue;
114
+ }
115
+ if (service.exported) serviceTypes.push(` ${q(service.id)}: ${serviceType};`);
116
+ else serviceTypes.push(` ${q(service.id)}: unknown;`);
117
+ }
118
+ if (featureScopedType && serviceTypes.length > 0) featureTypes.push(` ${q(feature.id)}: ${featureScopedType} & {\n${serviceTypes.join("\n")}\n };`);
119
+ else if (featureScopedType) featureTypes.push(` ${q(feature.id)}: ${featureScopedType};`);
120
+ else featureTypes.push(` ${q(feature.id)}: {\n${serviceTypes.join("\n")}\n };`);
103
121
  }
104
122
  const eventTypeEntries = [];
105
123
  for (const feature of allowedFeatures) for (const evt of feature.events ?? []) {
@@ -270,7 +288,6 @@ function generate(input) {
270
288
  envTypes: generateFeatureTypes(scanResult.features, srcDir, views, scanResult.windows ?? [])
271
289
  };
272
290
  }
273
-
274
291
  //#endregion
275
292
  //#region src/scanner.ts
276
293
  /**
@@ -688,6 +705,5 @@ async function scan(basePath) {
688
705
  windows: allWindows.map((pw) => pw.window)
689
706
  };
690
707
  }
691
-
692
708
  //#endregion
693
- export { generate, scan };
709
+ export { generate, scan };
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@cordy/electro-generator",
3
- "version": "1.2.21",
3
+ "version": "1.3.0",
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",
7
- "sideEffects": false,
8
7
  "keywords": [
9
8
  "electron",
10
9
  "codegen",
@@ -24,9 +23,6 @@
24
23
  "publishConfig": {
25
24
  "access": "public"
26
25
  },
27
- "engines": {
28
- "bun": ">=1.0.0"
29
- },
30
26
  "main": "./dist/index.mjs",
31
27
  "types": "./dist/index.d.mts",
32
28
  "files": [
@@ -44,15 +40,19 @@
44
40
  "prepublishOnly": "bun run build"
45
41
  },
46
42
  "peerDependencies": {
47
- "@cordy/electro": "1.2.21"
43
+ "@cordy/electro": ">=1",
44
+ "electron": ">=41",
45
+ "vite": ">=8"
48
46
  },
49
47
  "dependencies": {
50
- "oxc-parser": "^0.115.0",
48
+ "oxc-parser": "^0.120.0",
51
49
  "tinyglobby": "^0.2.15"
52
50
  },
53
51
  "devDependencies": {
54
- "@cordy/electro": "1.2.21",
55
- "tsdown": "^0.20.3",
56
- "vitest": "v4.1.0-beta.3"
52
+ "@cordy/electro": "1.3.0",
53
+ "electron": "^41.0.3",
54
+ "tsdown": "^0.21.4",
55
+ "vite": "^8.0.0",
56
+ "vitest": "4.1.0"
57
57
  }
58
58
  }