@reactive-contracts/compiler 0.1.3-beta → 0.2.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.cli.js CHANGED
@@ -134,19 +134,84 @@ ${gitignoreTemplate}` : gitignoreTemplate;
134
134
 
135
135
  // src/cli/commands/compile.ts
136
136
  import { glob } from "glob";
137
- import * as path2 from "path";
138
- import { createJiti } from "jiti";
137
+ import * as path3 from "path";
138
+ import { createJiti as createJiti2 } from "jiti";
139
139
 
140
140
  // src/config/index.ts
141
- async function loadConfig(_configPath = "./rcontracts.config.ts") {
142
- return {
143
- contracts: "./contracts/**/*.contract.ts",
144
- output: {
145
- frontend: "./generated/frontend",
146
- backend: "./generated/backend",
147
- runtime: "./generated/runtime"
141
+ import { createJiti } from "jiti";
142
+ import * as path2 from "path";
143
+ import { existsSync as existsSync2 } from "fs";
144
+ var defaultConfig = {
145
+ contracts: "./contracts/**/*.contract.ts",
146
+ output: {
147
+ frontend: "./generated/frontend",
148
+ backend: "./generated/backend",
149
+ runtime: "./generated/runtime"
150
+ },
151
+ validation: {
152
+ strictLatency: false,
153
+ requireIntent: true,
154
+ maxComplexity: 10
155
+ },
156
+ optimization: {
157
+ bundleSplitting: false,
158
+ treeShaking: false,
159
+ precompute: []
160
+ }
161
+ };
162
+ function resolveConfigPath(configPath, cwd = process.cwd()) {
163
+ if (configPath) {
164
+ const absolutePath = path2.isAbsolute(configPath) ? configPath : path2.join(cwd, configPath);
165
+ return existsSync2(absolutePath) ? absolutePath : null;
166
+ }
167
+ const configNames = [
168
+ "rcontracts.config.ts",
169
+ "rcontracts.config.js",
170
+ "rcontracts.config.mjs",
171
+ "reactive-contracts.config.ts",
172
+ "reactive-contracts.config.js"
173
+ ];
174
+ for (const name of configNames) {
175
+ const fullPath = path2.join(cwd, name);
176
+ if (existsSync2(fullPath)) {
177
+ return fullPath;
148
178
  }
149
- };
179
+ }
180
+ return null;
181
+ }
182
+ async function loadConfig(configPath, cwd = process.cwd()) {
183
+ const resolvedPath = resolveConfigPath(configPath, cwd);
184
+ if (!resolvedPath) {
185
+ return { ...defaultConfig };
186
+ }
187
+ const jiti3 = createJiti(import.meta.url, {
188
+ interopDefault: true,
189
+ moduleCache: false
190
+ // Disable cache to get fresh config on reload
191
+ });
192
+ try {
193
+ const module = await jiti3.import(resolvedPath);
194
+ const config = module.default || module;
195
+ return {
196
+ ...defaultConfig,
197
+ ...config,
198
+ output: {
199
+ ...defaultConfig.output,
200
+ ...config.output || {}
201
+ },
202
+ validation: {
203
+ ...defaultConfig.validation,
204
+ ...config.validation || {}
205
+ },
206
+ optimization: {
207
+ ...defaultConfig.optimization,
208
+ ...config.optimization || {}
209
+ }
210
+ };
211
+ } catch (err) {
212
+ const errorMessage = err instanceof Error ? err.message : String(err);
213
+ throw new Error(`Failed to load config from ${resolvedPath}: ${errorMessage}`);
214
+ }
150
215
  }
151
216
 
152
217
  // src/validator/index.ts
@@ -194,17 +259,17 @@ function validateContract(contract) {
194
259
  warnings
195
260
  };
196
261
  }
197
- function validateShape(shape, path4, errors, warnings) {
262
+ function validateShape(shape, path5, errors, warnings) {
198
263
  if (!shape || typeof shape !== "object") {
199
- errors.push(`Invalid shape at ${path4 || "root"}: must be an object`);
264
+ errors.push(`Invalid shape at ${path5 || "root"}: must be an object`);
200
265
  return;
201
266
  }
202
267
  const keys = Object.keys(shape);
203
268
  if (keys.length === 0) {
204
- warnings.push(`Shape at ${path4 || "root"} is empty`);
269
+ warnings.push(`Shape at ${path5 || "root"} is empty`);
205
270
  }
206
271
  for (const key of keys) {
207
- const fieldPath = path4 ? `${path4}.${key}` : key;
272
+ const fieldPath = path5 ? `${path5}.${key}` : key;
208
273
  const value = shape[key];
209
274
  if (!value) {
210
275
  errors.push(`Field "${fieldPath}" has undefined value`);
@@ -218,48 +283,48 @@ function validateShape(shape, path4, errors, warnings) {
218
283
  validateTypeDefinition(value, fieldPath, errors, warnings);
219
284
  }
220
285
  }
221
- function validateTypeDefinition(type, path4, errors, warnings) {
286
+ function validateTypeDefinition(type, path5, errors, warnings) {
222
287
  if (typeof type === "string") {
223
288
  const validPrimitives = ["string", "number", "boolean", "Date", "null", "undefined"];
224
289
  const isURL = type === "URL" || type.startsWith("URL<");
225
290
  if (!validPrimitives.includes(type) && !isURL) {
226
- errors.push(`Invalid type at ${path4}: "${type}" is not a valid primitive or URL type`);
291
+ errors.push(`Invalid type at ${path5}: "${type}" is not a valid primitive or URL type`);
227
292
  }
228
293
  if (isURL && type !== "URL") {
229
294
  const urlMatch = type.match(/^URL<(.+)>$/);
230
295
  if (!urlMatch) {
231
- errors.push(`Invalid URL type at ${path4}: must be "URL" or "URL<options>"`);
296
+ errors.push(`Invalid URL type at ${path5}: must be "URL" or "URL<options>"`);
232
297
  }
233
298
  }
234
299
  } else if (typeof type === "object" && type !== null) {
235
300
  if ("_brand" in type && type._brand === "DerivedField") {
236
301
  validateDerivedField(
237
302
  type,
238
- path4,
303
+ path5,
239
304
  errors,
240
305
  warnings
241
306
  );
242
307
  } else {
243
- validateShape(type, path4, errors, warnings);
308
+ validateShape(type, path5, errors, warnings);
244
309
  }
245
310
  } else {
246
- errors.push(`Invalid type at ${path4}: must be a string, object, or DerivedField`);
311
+ errors.push(`Invalid type at ${path5}: must be a string, object, or DerivedField`);
247
312
  }
248
313
  }
249
- function validateDerivedField(field, path4, errors, _warnings) {
314
+ function validateDerivedField(field, path5, errors, _warnings) {
250
315
  if (typeof field.derive !== "function") {
251
- errors.push(`Derived field at ${path4} must have a derive function`);
316
+ errors.push(`Derived field at ${path5} must have a derive function`);
252
317
  }
253
318
  if (field.dependencies && !Array.isArray(field.dependencies)) {
254
- errors.push(`Derived field dependencies at ${path4} must be an array`);
319
+ errors.push(`Derived field dependencies at ${path5} must be an array`);
255
320
  }
256
321
  if (field.preferredLayer && !["client", "edge", "origin"].includes(field.preferredLayer)) {
257
- errors.push(`Derived field preferredLayer at ${path4} must be 'client', 'edge', or 'origin'`);
322
+ errors.push(`Derived field preferredLayer at ${path5} must be 'client', 'edge', or 'origin'`);
258
323
  }
259
324
  if (field.dependencies && Array.isArray(field.dependencies)) {
260
325
  for (const dep of field.dependencies) {
261
326
  if (typeof dep !== "string") {
262
- errors.push(`Derived field dependency at ${path4} must be a string`);
327
+ errors.push(`Derived field dependency at ${path5} must be a string`);
263
328
  }
264
329
  }
265
330
  }
@@ -388,10 +453,10 @@ function validateVersioning(versioning, errors, warnings) {
388
453
  }
389
454
  function collectFieldPaths(shape, prefix, result) {
390
455
  for (const [key, value] of Object.entries(shape)) {
391
- const path4 = prefix ? `${prefix}.${key}` : key;
392
- result.add(path4);
456
+ const path5 = prefix ? `${prefix}.${key}` : key;
457
+ result.add(path5);
393
458
  if (typeof value === "object" && value !== null && !("_brand" in value) && typeof value !== "string") {
394
- collectFieldPaths(value, path4, result);
459
+ collectFieldPaths(value, path5, result);
395
460
  }
396
461
  }
397
462
  }
@@ -824,7 +889,7 @@ ${indentStr}}`;
824
889
  }
825
890
 
826
891
  // src/cli/commands/compile.ts
827
- var jiti = createJiti(import.meta.url, {
892
+ var jiti = createJiti2(import.meta.url, {
828
893
  interopDefault: true,
829
894
  moduleCache: false
830
895
  // Disable cache to avoid stale imports
@@ -850,7 +915,7 @@ async function compile() {
850
915
  let successCount = 0;
851
916
  let errorCount = 0;
852
917
  for (const file of contractFiles) {
853
- const fileName = path2.basename(file, ".contract.ts");
918
+ const fileName = path3.basename(file, ".contract.ts");
854
919
  start(`Processing ${fileName}...`);
855
920
  try {
856
921
  const module = await jiti.import(file);
@@ -896,19 +961,19 @@ async function compile() {
896
961
  }
897
962
  }
898
963
  const contractName = contract.definition.name;
899
- const frontendPath = path2.join(
964
+ const frontendPath = path3.join(
900
965
  process.cwd(),
901
966
  config.output.frontend,
902
967
  `${contractName}.ts`
903
968
  );
904
969
  await generateFrontendTypes(contract, frontendPath);
905
- const backendPath = path2.join(
970
+ const backendPath = path3.join(
906
971
  process.cwd(),
907
972
  config.output.backend,
908
973
  `${contractName}.resolver.ts`
909
974
  );
910
975
  await generateBackendResolver(contract, backendPath);
911
- const runtimePath = path2.join(
976
+ const runtimePath = path3.join(
912
977
  process.cwd(),
913
978
  config.output.runtime,
914
979
  `${contractName}.negotiator.ts`
@@ -942,9 +1007,9 @@ async function compile() {
942
1007
 
943
1008
  // src/cli/commands/validate.ts
944
1009
  import { glob as glob2 } from "glob";
945
- import * as path3 from "path";
946
- import { createJiti as createJiti2 } from "jiti";
947
- var jiti2 = createJiti2(import.meta.url, {
1010
+ import * as path4 from "path";
1011
+ import { createJiti as createJiti3 } from "jiti";
1012
+ var jiti2 = createJiti3(import.meta.url, {
948
1013
  interopDefault: true,
949
1014
  moduleCache: false
950
1015
  // Disable cache to avoid stale imports
@@ -971,7 +1036,7 @@ async function validate() {
971
1036
  let invalidCount = 0;
972
1037
  let warningCount = 0;
973
1038
  for (const file of contractFiles) {
974
- const fileName = path3.basename(file, ".contract.ts");
1039
+ const fileName = path4.basename(file, ".contract.ts");
975
1040
  start(`Validating ${fileName}...`);
976
1041
  try {
977
1042
  const module = await jiti2.import(file);
package/dist/index.d.cts CHANGED
@@ -43,11 +43,52 @@ interface CompilationResult {
43
43
  type ConfigDefinition = CompilerConfig;
44
44
 
45
45
  declare function defineConfig(config: CompilerConfig): ConfigDefinition;
46
+ declare function loadConfig(configPath?: string, cwd?: string): Promise<CompilerConfig>;
46
47
 
47
48
  declare function validateContract(contract: Contract): ValidationResult;
48
49
 
49
50
  declare function analyzeLatency(contract: Contract): LatencyAnalysisResult;
50
51
 
51
52
  declare function generateFrontendTypes(contract: Contract, outputPath: string): Promise<void>;
53
+ declare function generateBackendResolver(contract: Contract, outputPath: string): Promise<void>;
54
+ declare function generateRuntimeNegotiator(contract: Contract, outputPath: string): Promise<void>;
52
55
 
53
- export { type CompilationResult, type CompilerConfig, type ConfigDefinition, type LatencyAnalysisResult, type ValidationResult, analyzeLatency, defineConfig, generateFrontendTypes, validateContract };
56
+ interface CompilerLogger {
57
+ info: (message: string) => void;
58
+ success: (message: string) => void;
59
+ warning: (message: string) => void;
60
+ error: (message: string) => void;
61
+ verbose?: (message: string) => void;
62
+ }
63
+ declare const silentLogger: CompilerLogger;
64
+ declare const consoleLogger: CompilerLogger;
65
+ interface CompileOptions {
66
+ config: CompilerConfig;
67
+ cwd?: string;
68
+ logger?: CompilerLogger;
69
+ file?: string;
70
+ }
71
+ interface CompileResult {
72
+ success: boolean;
73
+ results: CompilationResult[];
74
+ errors: string[];
75
+ warnings: string[];
76
+ }
77
+ declare function parseContractFile(filePath: string, logger?: CompilerLogger): Promise<{
78
+ contracts: Array<{
79
+ name: string;
80
+ contract: Contract;
81
+ }>;
82
+ errors: string[];
83
+ }>;
84
+ declare function compileContract(contract: Contract, config: CompilerConfig, cwd?: string, logger?: CompilerLogger): Promise<CompilationResult>;
85
+ declare function findContractFiles(config: CompilerConfig, cwd?: string): Promise<string[]>;
86
+ declare function compileAll(options: CompileOptions): Promise<CompileResult>;
87
+ declare function isContractFile(filePath: string): boolean;
88
+ declare function getGeneratedFilesForContract(contractName: string, config: CompilerConfig, cwd?: string): {
89
+ frontend: string;
90
+ backend: string;
91
+ runtime: string;
92
+ };
93
+
94
+ export { type CompilationResult, type CompileOptions, type CompileResult, type CompilerConfig, type CompilerLogger, type ConfigDefinition, type LatencyAnalysisResult, type ValidationResult, analyzeLatency, compileAll, compileContract, consoleLogger, defineConfig, findContractFiles, generateBackendResolver, generateFrontendTypes, generateRuntimeNegotiator, getGeneratedFilesForContract, isContractFile, loadConfig, parseContractFile, silentLogger, validateContract };
package/dist/index.d.ts CHANGED
@@ -43,11 +43,52 @@ interface CompilationResult {
43
43
  type ConfigDefinition = CompilerConfig;
44
44
 
45
45
  declare function defineConfig(config: CompilerConfig): ConfigDefinition;
46
+ declare function loadConfig(configPath?: string, cwd?: string): Promise<CompilerConfig>;
46
47
 
47
48
  declare function validateContract(contract: Contract): ValidationResult;
48
49
 
49
50
  declare function analyzeLatency(contract: Contract): LatencyAnalysisResult;
50
51
 
51
52
  declare function generateFrontendTypes(contract: Contract, outputPath: string): Promise<void>;
53
+ declare function generateBackendResolver(contract: Contract, outputPath: string): Promise<void>;
54
+ declare function generateRuntimeNegotiator(contract: Contract, outputPath: string): Promise<void>;
52
55
 
53
- export { type CompilationResult, type CompilerConfig, type ConfigDefinition, type LatencyAnalysisResult, type ValidationResult, analyzeLatency, defineConfig, generateFrontendTypes, validateContract };
56
+ interface CompilerLogger {
57
+ info: (message: string) => void;
58
+ success: (message: string) => void;
59
+ warning: (message: string) => void;
60
+ error: (message: string) => void;
61
+ verbose?: (message: string) => void;
62
+ }
63
+ declare const silentLogger: CompilerLogger;
64
+ declare const consoleLogger: CompilerLogger;
65
+ interface CompileOptions {
66
+ config: CompilerConfig;
67
+ cwd?: string;
68
+ logger?: CompilerLogger;
69
+ file?: string;
70
+ }
71
+ interface CompileResult {
72
+ success: boolean;
73
+ results: CompilationResult[];
74
+ errors: string[];
75
+ warnings: string[];
76
+ }
77
+ declare function parseContractFile(filePath: string, logger?: CompilerLogger): Promise<{
78
+ contracts: Array<{
79
+ name: string;
80
+ contract: Contract;
81
+ }>;
82
+ errors: string[];
83
+ }>;
84
+ declare function compileContract(contract: Contract, config: CompilerConfig, cwd?: string, logger?: CompilerLogger): Promise<CompilationResult>;
85
+ declare function findContractFiles(config: CompilerConfig, cwd?: string): Promise<string[]>;
86
+ declare function compileAll(options: CompileOptions): Promise<CompileResult>;
87
+ declare function isContractFile(filePath: string): boolean;
88
+ declare function getGeneratedFilesForContract(contractName: string, config: CompilerConfig, cwd?: string): {
89
+ frontend: string;
90
+ backend: string;
91
+ runtime: string;
92
+ };
93
+
94
+ export { type CompilationResult, type CompileOptions, type CompileResult, type CompilerConfig, type CompilerLogger, type ConfigDefinition, type LatencyAnalysisResult, type ValidationResult, analyzeLatency, compileAll, compileContract, consoleLogger, defineConfig, findContractFiles, generateBackendResolver, generateFrontendTypes, generateRuntimeNegotiator, getGeneratedFilesForContract, isContractFile, loadConfig, parseContractFile, silentLogger, validateContract };