@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.cjs +489 -20
- package/dist/index.cli.js +102 -37
- package/dist/index.d.cts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +458 -20
- package/package.json +1 -1
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
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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,
|
|
262
|
+
function validateShape(shape, path5, errors, warnings) {
|
|
198
263
|
if (!shape || typeof shape !== "object") {
|
|
199
|
-
errors.push(`Invalid shape at ${
|
|
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 ${
|
|
269
|
+
warnings.push(`Shape at ${path5 || "root"} is empty`);
|
|
205
270
|
}
|
|
206
271
|
for (const key of keys) {
|
|
207
|
-
const fieldPath =
|
|
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,
|
|
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 ${
|
|
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 ${
|
|
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
|
-
|
|
303
|
+
path5,
|
|
239
304
|
errors,
|
|
240
305
|
warnings
|
|
241
306
|
);
|
|
242
307
|
} else {
|
|
243
|
-
validateShape(type,
|
|
308
|
+
validateShape(type, path5, errors, warnings);
|
|
244
309
|
}
|
|
245
310
|
} else {
|
|
246
|
-
errors.push(`Invalid type at ${
|
|
311
|
+
errors.push(`Invalid type at ${path5}: must be a string, object, or DerivedField`);
|
|
247
312
|
}
|
|
248
313
|
}
|
|
249
|
-
function validateDerivedField(field,
|
|
314
|
+
function validateDerivedField(field, path5, errors, _warnings) {
|
|
250
315
|
if (typeof field.derive !== "function") {
|
|
251
|
-
errors.push(`Derived field at ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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
|
|
392
|
-
result.add(
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
946
|
-
import { createJiti as
|
|
947
|
-
var jiti2 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|