@sembl/compiler 0.1.0 → 0.2.1
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/cli/index.js +543 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{chunk-Y4FKH2ZU.js → index.cjs} +136 -36
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +220 -0
- package/dist/index.d.ts +41 -2
- package/dist/index.js +524 -12
- package/dist/index.js.map +1 -1
- package/package.json +16 -7
- package/dist/chunk-Y4FKH2ZU.js.map +0 -1
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { SchemaBundle, RuntimeSchema, FieldConstraints, FieldType, Provider, EnumResolver, CoerceOptions } from '@sembl/core';
|
|
2
|
+
import { Node, ClassDeclaration, PropertyDeclaration, Type } from 'ts-morph';
|
|
3
|
+
import { EvalReport, EvalDiff, TokenPrices } from '@sembl/testing';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Annotation extracted from a @Schema decorator.
|
|
7
|
+
*/
|
|
8
|
+
interface SchemaAnnotation {
|
|
9
|
+
/** Class name */
|
|
10
|
+
className: string;
|
|
11
|
+
/** Description string from @Schema(description) */
|
|
12
|
+
description: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Annotation extracted from a @Describe decorator on a property.
|
|
16
|
+
*/
|
|
17
|
+
interface FieldAnnotation {
|
|
18
|
+
/** Property name */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Description string from @Describe(description) */
|
|
21
|
+
description: string;
|
|
22
|
+
/** Raw TypeScript type text */
|
|
23
|
+
rawType: string;
|
|
24
|
+
/** Whether the property is optional (?:) */
|
|
25
|
+
optional: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configuration for the compiler.
|
|
29
|
+
*/
|
|
30
|
+
interface CompilerConfig {
|
|
31
|
+
/** Glob patterns for input source files */
|
|
32
|
+
inputPatterns: string[];
|
|
33
|
+
/** Output directory for generated schema files */
|
|
34
|
+
outputDir: string;
|
|
35
|
+
/** Optional tsconfig path */
|
|
36
|
+
tsconfigPath?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Result of extracting schemas from source files.
|
|
40
|
+
*
|
|
41
|
+
* Extends `SchemaBundle` so it can be handed straight to the emitter, and adds
|
|
42
|
+
* the diagnostics raised on the way — a field whose type the schema contract
|
|
43
|
+
* cannot express still emits, so the warnings are what tell the caller the
|
|
44
|
+
* output does not match the source.
|
|
45
|
+
*/
|
|
46
|
+
interface ExtractionResult extends SchemaBundle {
|
|
47
|
+
/** Any warnings generated during extraction, in discovery order */
|
|
48
|
+
warnings: string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface ExtractOptions {
|
|
52
|
+
/** Glob patterns for source files */
|
|
53
|
+
filePatterns: string[];
|
|
54
|
+
/** Optional tsconfig.json path */
|
|
55
|
+
tsconfigPath?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extract all @Schema-decorated classes from the given source files.
|
|
59
|
+
*
|
|
60
|
+
* Returns the schemas alongside any warnings raised while resolving them —
|
|
61
|
+
* unsupported field types, annotations that could not be read. Extraction
|
|
62
|
+
* never throws on a bad field, so the warnings are the only signal that the
|
|
63
|
+
* emitted schemas are not what the source described.
|
|
64
|
+
*/
|
|
65
|
+
declare function extractSchemas(options: ExtractOptions): ExtractionResult;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Emit a SchemaBundle as a set of individual .schema.ts files
|
|
69
|
+
* plus a bundle index file.
|
|
70
|
+
*/
|
|
71
|
+
declare function emitSchemas(bundle: SchemaBundle, outputDir: string): string[];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Where a field sits in the source, carried through type resolution and
|
|
75
|
+
* decorator parsing.
|
|
76
|
+
*
|
|
77
|
+
* Every diagnostic names the class and the property, because a warning that
|
|
78
|
+
* only says "unsupported type" sends the reader hunting through the whole
|
|
79
|
+
* input directory for it.
|
|
80
|
+
*/
|
|
81
|
+
interface FieldScope {
|
|
82
|
+
/** Name of the @Schema class that owns the field. */
|
|
83
|
+
className: string;
|
|
84
|
+
/** Property name, dotted through synthesized inline objects. */
|
|
85
|
+
propertyPath: string;
|
|
86
|
+
/**
|
|
87
|
+
* Declaration the type was read from. Members of an anonymous object type
|
|
88
|
+
* have no declaration of their own to resolve against, so they are typed
|
|
89
|
+
* relative to this node.
|
|
90
|
+
*/
|
|
91
|
+
node: Node;
|
|
92
|
+
/** Collector for diagnostics and synthesized schemas. */
|
|
93
|
+
context: ExtractionContext;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Accumulates everything an extraction produces beyond the schemas themselves:
|
|
97
|
+
* diagnostics, schemas synthesized for anonymous object types, and the nested
|
|
98
|
+
* schema references that can only be validated once all files are visited.
|
|
99
|
+
*/
|
|
100
|
+
interface ExtractionContext {
|
|
101
|
+
/** Diagnostics raised so far, in discovery order. */
|
|
102
|
+
readonly warnings: readonly string[];
|
|
103
|
+
/** Schemas synthesized for anonymous inline object types, keyed by id. */
|
|
104
|
+
readonly synthesizedSchemas: Readonly<Record<string, RuntimeSchema>>;
|
|
105
|
+
/** Record a diagnostic against a field. */
|
|
106
|
+
warn(scope: FieldScope, message: string): void;
|
|
107
|
+
/** Add a schema synthesized for an inline object type. */
|
|
108
|
+
registerSynthesizedSchema(schema: RuntimeSchema): void;
|
|
109
|
+
/** Note that a field points at `nestedSchemaId`, to be checked later. */
|
|
110
|
+
recordNestedReference(scope: FieldScope, nestedSchemaId: string, typeText: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* Warn about every recorded reference whose target is not among
|
|
113
|
+
* `knownSchemaIds`. Call once, after all classes have been visited.
|
|
114
|
+
*/
|
|
115
|
+
reportUnresolvedNestedSchemas(knownSchemaIds: ReadonlySet<string>): void;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create an empty {@link ExtractionContext} for a single extraction run.
|
|
119
|
+
*/
|
|
120
|
+
declare function createExtractionContext(): ExtractionContext;
|
|
121
|
+
/**
|
|
122
|
+
* Derive the id of a schema synthesized from an anonymous object type.
|
|
123
|
+
*
|
|
124
|
+
* The id becomes a filename and an exported binding in the generated output
|
|
125
|
+
* (`<id>.schema.ts`, `<id>Schema`), so it has to be a valid identifier. The
|
|
126
|
+
* path prefix keeps generated files traceable back to the declaration they
|
|
127
|
+
* came from; the digest of the resolved shape makes the id collision-resistant
|
|
128
|
+
* against a hand-written @Schema class and stable across runs and machines —
|
|
129
|
+
* it is derived from the resolved fields, never from absolute source paths.
|
|
130
|
+
*/
|
|
131
|
+
declare function synthesizedSchemaId(scope: FieldScope, structuralSignature: string): string;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Visit a class declaration and extract a RuntimeSchema if it has @Schema decorator.
|
|
135
|
+
* Returns undefined if the class is not decorated with @Schema.
|
|
136
|
+
*
|
|
137
|
+
* Diagnostics and schemas synthesized for inline object types are collected
|
|
138
|
+
* into `context` rather than thrown, so one questionable field does not stop
|
|
139
|
+
* the rest of the extraction.
|
|
140
|
+
*/
|
|
141
|
+
declare function visitClass(classDecl: ClassDeclaration, context: ExtractionContext): RuntimeSchema | undefined;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Extract the @Schema description from a class declaration.
|
|
145
|
+
* Returns undefined if the class doesn't have a @Schema decorator.
|
|
146
|
+
*/
|
|
147
|
+
declare function parseSchemaDecorator(classDecl: ClassDeclaration): string | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* Extract the @Describe description from a property declaration.
|
|
150
|
+
* Returns undefined if the property doesn't have a @Describe decorator.
|
|
151
|
+
*/
|
|
152
|
+
declare function parseDescribeDecorator(propDecl: PropertyDeclaration): string | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* Extract the @Constrain bounds from a property declaration.
|
|
155
|
+
*
|
|
156
|
+
* The decorator's argument has to be an inline object literal: decorators are
|
|
157
|
+
* never evaluated, so a value that is not written out in source cannot be
|
|
158
|
+
* resolved. Unreadable and unknown entries are warned about and skipped
|
|
159
|
+
* individually, so one bad bound does not discard the rest.
|
|
160
|
+
*
|
|
161
|
+
* Returns undefined if there is no @Constrain decorator, or if nothing in it
|
|
162
|
+
* could be read.
|
|
163
|
+
*/
|
|
164
|
+
declare function parseConstrainDecorator(propDecl: PropertyDeclaration, scope: FieldScope): FieldConstraints | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* Extract the enum source id from a property's @ValuesFrom decorator.
|
|
167
|
+
*
|
|
168
|
+
* Returns undefined if there is no @ValuesFrom decorator, or if its argument
|
|
169
|
+
* is not a string literal.
|
|
170
|
+
*/
|
|
171
|
+
declare function parseValuesFromDecorator(propDecl: PropertyDeclaration, scope: FieldScope): string | undefined;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Resolve a TypeScript type to a FieldType descriptor.
|
|
175
|
+
*
|
|
176
|
+
* Maps TS types to the schema type system: string, number, boolean, array,
|
|
177
|
+
* object, enum. Anything the contract cannot express is reported through
|
|
178
|
+
* `scope.context` rather than quietly coerced.
|
|
179
|
+
*/
|
|
180
|
+
declare function resolveFieldType(type: Type, scope: FieldScope): FieldType;
|
|
181
|
+
|
|
182
|
+
interface EvalCommandOptions {
|
|
183
|
+
/** A JS module exporting the schema and provider to evaluate with. */
|
|
184
|
+
config: string;
|
|
185
|
+
/** Directory of fixture JSON files. */
|
|
186
|
+
fixtures: string;
|
|
187
|
+
/** Where to write the report; defaults to `<fixtures>/.sembl-eval/last-run.json`. */
|
|
188
|
+
out?: string;
|
|
189
|
+
mode?: "coerce" | "partialCoerce";
|
|
190
|
+
provenance?: boolean;
|
|
191
|
+
concurrency?: number;
|
|
192
|
+
/** Replay recordings from this directory, recording misses through the provider. */
|
|
193
|
+
replay?: string;
|
|
194
|
+
/** Exit non-zero when overall recall lands below this fraction. */
|
|
195
|
+
minRecall?: number;
|
|
196
|
+
/** Exit non-zero when overall precision lands below this fraction. */
|
|
197
|
+
minPrecision?: number;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* What an eval config module exports. Written as a plain JS module so the
|
|
201
|
+
* CLI can `import()` it without a TypeScript loader; a TS project can point
|
|
202
|
+
* at its build output, or keep the config in `.mjs`.
|
|
203
|
+
*/
|
|
204
|
+
interface EvalConfig {
|
|
205
|
+
schema: RuntimeSchema;
|
|
206
|
+
provider: Provider;
|
|
207
|
+
bundle?: SchemaBundle;
|
|
208
|
+
enumResolver?: EnumResolver;
|
|
209
|
+
prices?: TokenPrices;
|
|
210
|
+
/** Any other coercion options: `onInvalidField`, `maxRepairAttempts`, `maxInputChars`, … */
|
|
211
|
+
coerceOptions?: Partial<Omit<CoerceOptions, "schema" | "provider" | "bundle" | "enumResolver">>;
|
|
212
|
+
}
|
|
213
|
+
interface EvalCommandResult {
|
|
214
|
+
report?: EvalReport;
|
|
215
|
+
diff?: EvalDiff;
|
|
216
|
+
exitCode: number;
|
|
217
|
+
}
|
|
218
|
+
declare function evalCommand(options: EvalCommandOptions): Promise<EvalCommandResult>;
|
|
219
|
+
|
|
220
|
+
export { type CompilerConfig, type EvalCommandOptions, type EvalCommandResult, type EvalConfig, type ExtractOptions, type ExtractionContext, type ExtractionResult, type FieldAnnotation, type FieldScope, type SchemaAnnotation, createExtractionContext, emitSchemas, evalCommand, extractSchemas, parseConstrainDecorator, parseDescribeDecorator, parseSchemaDecorator, parseValuesFromDecorator, resolveFieldType, synthesizedSchemaId, visitClass };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SchemaBundle, RuntimeSchema, FieldConstraints, FieldType } from '@sembl/core';
|
|
1
|
+
import { SchemaBundle, RuntimeSchema, FieldConstraints, FieldType, Provider, EnumResolver, CoerceOptions } from '@sembl/core';
|
|
2
2
|
import { Node, ClassDeclaration, PropertyDeclaration, Type } from 'ts-morph';
|
|
3
|
+
import { EvalReport, EvalDiff, TokenPrices } from '@sembl/testing';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Annotation extracted from a @Schema decorator.
|
|
@@ -178,4 +179,42 @@ declare function parseValuesFromDecorator(propDecl: PropertyDeclaration, scope:
|
|
|
178
179
|
*/
|
|
179
180
|
declare function resolveFieldType(type: Type, scope: FieldScope): FieldType;
|
|
180
181
|
|
|
181
|
-
|
|
182
|
+
interface EvalCommandOptions {
|
|
183
|
+
/** A JS module exporting the schema and provider to evaluate with. */
|
|
184
|
+
config: string;
|
|
185
|
+
/** Directory of fixture JSON files. */
|
|
186
|
+
fixtures: string;
|
|
187
|
+
/** Where to write the report; defaults to `<fixtures>/.sembl-eval/last-run.json`. */
|
|
188
|
+
out?: string;
|
|
189
|
+
mode?: "coerce" | "partialCoerce";
|
|
190
|
+
provenance?: boolean;
|
|
191
|
+
concurrency?: number;
|
|
192
|
+
/** Replay recordings from this directory, recording misses through the provider. */
|
|
193
|
+
replay?: string;
|
|
194
|
+
/** Exit non-zero when overall recall lands below this fraction. */
|
|
195
|
+
minRecall?: number;
|
|
196
|
+
/** Exit non-zero when overall precision lands below this fraction. */
|
|
197
|
+
minPrecision?: number;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* What an eval config module exports. Written as a plain JS module so the
|
|
201
|
+
* CLI can `import()` it without a TypeScript loader; a TS project can point
|
|
202
|
+
* at its build output, or keep the config in `.mjs`.
|
|
203
|
+
*/
|
|
204
|
+
interface EvalConfig {
|
|
205
|
+
schema: RuntimeSchema;
|
|
206
|
+
provider: Provider;
|
|
207
|
+
bundle?: SchemaBundle;
|
|
208
|
+
enumResolver?: EnumResolver;
|
|
209
|
+
prices?: TokenPrices;
|
|
210
|
+
/** Any other coercion options: `onInvalidField`, `maxRepairAttempts`, `maxInputChars`, … */
|
|
211
|
+
coerceOptions?: Partial<Omit<CoerceOptions, "schema" | "provider" | "bundle" | "enumResolver">>;
|
|
212
|
+
}
|
|
213
|
+
interface EvalCommandResult {
|
|
214
|
+
report?: EvalReport;
|
|
215
|
+
diff?: EvalDiff;
|
|
216
|
+
exitCode: number;
|
|
217
|
+
}
|
|
218
|
+
declare function evalCommand(options: EvalCommandOptions): Promise<EvalCommandResult>;
|
|
219
|
+
|
|
220
|
+
export { type CompilerConfig, type EvalCommandOptions, type EvalCommandResult, type EvalConfig, type ExtractOptions, type ExtractionContext, type ExtractionResult, type FieldAnnotation, type FieldScope, type SchemaAnnotation, createExtractionContext, emitSchemas, evalCommand, extractSchemas, parseConstrainDecorator, parseDescribeDecorator, parseSchemaDecorator, parseValuesFromDecorator, resolveFieldType, synthesizedSchemaId, visitClass };
|