@effect/language-service 0.60.0 → 0.62.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/README.md +2 -0
- package/cli.js +692 -26
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +670 -2
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +706 -10
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +670 -2
- package/transform.js.map +1 -1
|
@@ -766,6 +766,10 @@ var isEmptyArray = (self) => self.length === 0;
|
|
|
766
766
|
var isEmptyReadonlyArray = isEmptyArray;
|
|
767
767
|
var isNonEmptyReadonlyArray = isNonEmptyArray;
|
|
768
768
|
var isOutOfBounds = (i, as) => i < 0 || i >= as.length;
|
|
769
|
+
var get = /* @__PURE__ */ dual(2, (self, index) => {
|
|
770
|
+
const i = Math.floor(index);
|
|
771
|
+
return isOutOfBounds(i, self) ? none2() : some2(self[i]);
|
|
772
|
+
});
|
|
769
773
|
var unsafeGet = /* @__PURE__ */ dual(2, (self, index) => {
|
|
770
774
|
const i = Math.floor(index);
|
|
771
775
|
if (isOutOfBounds(i, self)) {
|
|
@@ -773,6 +777,7 @@ var unsafeGet = /* @__PURE__ */ dual(2, (self, index) => {
|
|
|
773
777
|
}
|
|
774
778
|
return self[i];
|
|
775
779
|
});
|
|
780
|
+
var head = /* @__PURE__ */ get(0);
|
|
776
781
|
var headNonEmpty = /* @__PURE__ */ unsafeGet(0);
|
|
777
782
|
var tailNonEmpty = (self) => self.slice(1);
|
|
778
783
|
var reverse = (self) => Array.from(self).reverse();
|
|
@@ -836,6 +841,7 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
|
|
|
836
841
|
return [];
|
|
837
842
|
});
|
|
838
843
|
var dedupe = (self) => dedupeWith(self, equivalence());
|
|
844
|
+
var join = /* @__PURE__ */ dual(2, (self, sep) => fromIterable(self).join(sep));
|
|
839
845
|
|
|
840
846
|
// src/core/Nano.ts
|
|
841
847
|
var NanoTag = class {
|
|
@@ -2137,7 +2143,11 @@ var getEditsForCodegen = fn("LSP.getEditsForCodegen")(function* (codegens2, sour
|
|
|
2137
2143
|
service(ChangeTracker),
|
|
2138
2144
|
map4((changeTracker) => {
|
|
2139
2145
|
changeTracker.deleteRange(sourceFile, range);
|
|
2140
|
-
changeTracker.insertText(
|
|
2146
|
+
changeTracker.insertText(
|
|
2147
|
+
sourceFile,
|
|
2148
|
+
range.pos,
|
|
2149
|
+
edit.hash.length > 0 ? `${codegen.name}:${edit.hash}` : codegen.name
|
|
2150
|
+
);
|
|
2141
2151
|
})
|
|
2142
2152
|
);
|
|
2143
2153
|
return {
|
|
@@ -2188,6 +2198,9 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2188
2198
|
function isThisTypeParameter(type) {
|
|
2189
2199
|
return !!(type.flags & ts.TypeFlags.TypeParameter && type.isThisType);
|
|
2190
2200
|
}
|
|
2201
|
+
function isMissingIntrinsicType(type) {
|
|
2202
|
+
return (type.flags & ts.TypeFlags.Undefined) !== 0 && "debugIntrinsicName" in type && type.debugIntrinsicName === "missing";
|
|
2203
|
+
}
|
|
2191
2204
|
function getTypeParameterAtPosition(signature, pos) {
|
|
2192
2205
|
const type = typeChecker.getParameterType(signature, pos);
|
|
2193
2206
|
if (isIndexType(type) && isThisTypeParameter(type.type)) {
|
|
@@ -2492,6 +2505,7 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
2492
2505
|
}
|
|
2493
2506
|
return {
|
|
2494
2507
|
isUnion,
|
|
2508
|
+
isMissingIntrinsicType,
|
|
2495
2509
|
getTypeParameterAtPosition,
|
|
2496
2510
|
getMissingTypeEntriesInTargetType,
|
|
2497
2511
|
unrollUnionMembers,
|
|
@@ -5663,8 +5677,662 @@ var annotate = createCodegen({
|
|
|
5663
5677
|
})
|
|
5664
5678
|
});
|
|
5665
5679
|
|
|
5680
|
+
// src/utils/StructuralSchemaGen.ts
|
|
5681
|
+
var UnsupportedTypeError = class {
|
|
5682
|
+
constructor(type, reason) {
|
|
5683
|
+
this.type = type;
|
|
5684
|
+
this.reason = reason;
|
|
5685
|
+
}
|
|
5686
|
+
_tag = "@effect/language-service/UnsupportedTypeError";
|
|
5687
|
+
toString() {
|
|
5688
|
+
return `Unsupported type: ${this.reason}`;
|
|
5689
|
+
}
|
|
5690
|
+
};
|
|
5691
|
+
var StructuralSchemaGenContext = Tag("StructuralSchemaGenContext");
|
|
5692
|
+
var makeStructuralSchemaGenContext = fn("StructuralSchemaGen.makeContext")(
|
|
5693
|
+
function* (sourceFile, schemaIdentifier) {
|
|
5694
|
+
const ts = yield* service(TypeScriptApi);
|
|
5695
|
+
const program = yield* service(TypeScriptProgram);
|
|
5696
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
5697
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5698
|
+
const effectSchemaIdentifier = schemaIdentifier || "Schema";
|
|
5699
|
+
return identity({
|
|
5700
|
+
ts,
|
|
5701
|
+
program,
|
|
5702
|
+
typeChecker,
|
|
5703
|
+
typeCheckerUtils,
|
|
5704
|
+
sourceFile,
|
|
5705
|
+
createApiPropertyAccess: (apiName) => ts.factory.createPropertyAccessExpression(
|
|
5706
|
+
ts.factory.createIdentifier(effectSchemaIdentifier),
|
|
5707
|
+
apiName
|
|
5708
|
+
),
|
|
5709
|
+
createApiCall: (apiName, args2) => ts.factory.createCallExpression(
|
|
5710
|
+
ts.factory.createPropertyAccessExpression(
|
|
5711
|
+
ts.factory.createIdentifier(effectSchemaIdentifier),
|
|
5712
|
+
apiName
|
|
5713
|
+
),
|
|
5714
|
+
[],
|
|
5715
|
+
args2
|
|
5716
|
+
),
|
|
5717
|
+
hoistedSchemas: /* @__PURE__ */ new Map(),
|
|
5718
|
+
typeToStatementIndex: /* @__PURE__ */ new Map(),
|
|
5719
|
+
nameToType: /* @__PURE__ */ new Map(),
|
|
5720
|
+
usedGlobalIdentifiers: /* @__PURE__ */ new Map(),
|
|
5721
|
+
schemaStatements: [],
|
|
5722
|
+
rangesToDelete: []
|
|
5723
|
+
});
|
|
5724
|
+
}
|
|
5725
|
+
);
|
|
5726
|
+
var pushHoistedStatement = fn("StructuralSchemaGen.pushHoistedStatement")(
|
|
5727
|
+
function* (ctx, name, type, statement, createReference) {
|
|
5728
|
+
ctx.usedGlobalIdentifiers.set(name, (ctx.usedGlobalIdentifiers.get(name) || 0) + 1);
|
|
5729
|
+
ctx.schemaStatements.push(statement);
|
|
5730
|
+
ctx.typeToStatementIndex.set(type, ctx.schemaStatements.length - 1);
|
|
5731
|
+
ctx.hoistedSchemas.set(type, createReference);
|
|
5732
|
+
}
|
|
5733
|
+
);
|
|
5734
|
+
var pushHoistedVariableStatement = fn("StructuralSchemaGen.pushHoistedVariableStatement")(
|
|
5735
|
+
function* (ts, ctx, name, type, result) {
|
|
5736
|
+
return yield* pushHoistedStatement(
|
|
5737
|
+
ctx,
|
|
5738
|
+
name,
|
|
5739
|
+
type,
|
|
5740
|
+
ts.factory.createVariableStatement(
|
|
5741
|
+
void 0,
|
|
5742
|
+
ts.factory.createVariableDeclarationList(
|
|
5743
|
+
[ts.factory.createVariableDeclaration(ts.factory.createIdentifier(name), void 0, void 0, result)],
|
|
5744
|
+
ts.NodeFlags.Const
|
|
5745
|
+
)
|
|
5746
|
+
),
|
|
5747
|
+
() => ts.factory.createIdentifier(name)
|
|
5748
|
+
);
|
|
5749
|
+
}
|
|
5750
|
+
);
|
|
5751
|
+
var createProcessingContext = (maxDepth = 200) => ({
|
|
5752
|
+
depth: 0,
|
|
5753
|
+
maxDepth,
|
|
5754
|
+
hoistName: void 0
|
|
5755
|
+
});
|
|
5756
|
+
var processType = fn(
|
|
5757
|
+
"StructuralSchemaGen.processType"
|
|
5758
|
+
)(
|
|
5759
|
+
function* (type, context) {
|
|
5760
|
+
const processingContext = context || createProcessingContext();
|
|
5761
|
+
const { hoistedSchemas, nameToType, ts, typeChecker, usedGlobalIdentifiers } = yield* service(
|
|
5762
|
+
StructuralSchemaGenContext
|
|
5763
|
+
);
|
|
5764
|
+
if (processingContext.depth >= processingContext.maxDepth) {
|
|
5765
|
+
return yield* fail(new UnsupportedTypeError(type, "Maximum depth exceeded"));
|
|
5766
|
+
}
|
|
5767
|
+
let hoistName = fromIterable(nameToType.entries()).find(([_, existingType]) => existingType === type)?.[0];
|
|
5768
|
+
if (!hoistName && type && type.symbol && type.symbol.declarations && type.symbol.declarations.length === 1) {
|
|
5769
|
+
const declaration = type.symbol.declarations[0];
|
|
5770
|
+
if (ts.isInterfaceDeclaration(declaration)) {
|
|
5771
|
+
hoistName = ts.idText(declaration.name);
|
|
5772
|
+
} else if (declaration.parent && ts.isTypeAliasDeclaration(declaration.parent)) {
|
|
5773
|
+
hoistName = ts.idText(declaration.parent.name);
|
|
5774
|
+
}
|
|
5775
|
+
if (hoistName) {
|
|
5776
|
+
const existingType = nameToType.get(hoistName);
|
|
5777
|
+
const isSame = existingType && typeChecker.isTypeAssignableTo(type, existingType) && typeChecker.isTypeAssignableTo(existingType, type);
|
|
5778
|
+
if (!isSame) {
|
|
5779
|
+
const usedCount = usedGlobalIdentifiers.get(hoistName) || 0;
|
|
5780
|
+
hoistName = usedCount > 0 ? hoistName + "_" + usedCount : hoistName;
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
}
|
|
5784
|
+
const nestedContext = {
|
|
5785
|
+
...processingContext,
|
|
5786
|
+
depth: processingContext.depth + 1,
|
|
5787
|
+
hoistName
|
|
5788
|
+
};
|
|
5789
|
+
for (const [hoistedType, hoistedSchema] of hoistedSchemas.entries()) {
|
|
5790
|
+
if (hoistedType === type || typeChecker.isTypeAssignableTo(type, hoistedType) && typeChecker.isTypeAssignableTo(hoistedType, type)) {
|
|
5791
|
+
return hoistedSchema();
|
|
5792
|
+
}
|
|
5793
|
+
}
|
|
5794
|
+
const [schemaExpr, skipHoisting] = yield* processTypeImpl(type, nestedContext);
|
|
5795
|
+
if (!skipHoisting && hoistName) {
|
|
5796
|
+
const ctx = yield* service(StructuralSchemaGenContext);
|
|
5797
|
+
yield* pushHoistedVariableStatement(ts, ctx, hoistName, type, schemaExpr);
|
|
5798
|
+
return ctx.hoistedSchemas.get(type)();
|
|
5799
|
+
}
|
|
5800
|
+
return schemaExpr;
|
|
5801
|
+
}
|
|
5802
|
+
);
|
|
5803
|
+
var processTypeImpl = fn(
|
|
5804
|
+
"StructuralSchemaGen.processTypeImpl"
|
|
5805
|
+
)(
|
|
5806
|
+
function* (type, context) {
|
|
5807
|
+
const { createApiCall, createApiPropertyAccess, ts, typeChecker, typeCheckerUtils } = yield* service(
|
|
5808
|
+
StructuralSchemaGenContext
|
|
5809
|
+
);
|
|
5810
|
+
if (type.flags & ts.TypeFlags.String) {
|
|
5811
|
+
return [createApiPropertyAccess("String"), true];
|
|
5812
|
+
}
|
|
5813
|
+
if (type.flags & ts.TypeFlags.Number) {
|
|
5814
|
+
return [createApiPropertyAccess("Number"), true];
|
|
5815
|
+
}
|
|
5816
|
+
if (type.flags & ts.TypeFlags.Boolean) {
|
|
5817
|
+
return [createApiPropertyAccess("Boolean"), true];
|
|
5818
|
+
}
|
|
5819
|
+
if (type.flags & ts.TypeFlags.BigInt) {
|
|
5820
|
+
return [createApiPropertyAccess("BigInt"), true];
|
|
5821
|
+
}
|
|
5822
|
+
if (type.flags & ts.TypeFlags.Void) {
|
|
5823
|
+
return [createApiPropertyAccess("Void"), true];
|
|
5824
|
+
}
|
|
5825
|
+
if (type.flags & ts.TypeFlags.Undefined) {
|
|
5826
|
+
return [createApiPropertyAccess("Undefined"), true];
|
|
5827
|
+
}
|
|
5828
|
+
if (type.flags & ts.TypeFlags.Null) {
|
|
5829
|
+
return [createApiPropertyAccess("Null"), true];
|
|
5830
|
+
}
|
|
5831
|
+
if (type.flags & ts.TypeFlags.Never) {
|
|
5832
|
+
return [createApiPropertyAccess("Never"), true];
|
|
5833
|
+
}
|
|
5834
|
+
if (type.flags & ts.TypeFlags.Any) {
|
|
5835
|
+
return [createApiPropertyAccess("Any"), true];
|
|
5836
|
+
}
|
|
5837
|
+
if (type.flags & ts.TypeFlags.Unknown) {
|
|
5838
|
+
return [createApiPropertyAccess("Unknown"), true];
|
|
5839
|
+
}
|
|
5840
|
+
if (type.flags & ts.TypeFlags.StringLiteral) {
|
|
5841
|
+
const literalType = type;
|
|
5842
|
+
return [createApiCall("Literal", [ts.factory.createStringLiteral(literalType.value)]), true];
|
|
5843
|
+
}
|
|
5844
|
+
if (type.flags & ts.TypeFlags.NumberLiteral) {
|
|
5845
|
+
const literalType = type;
|
|
5846
|
+
return [createApiCall("Literal", [ts.factory.createNumericLiteral(literalType.value)]), true];
|
|
5847
|
+
}
|
|
5848
|
+
if (type.flags & ts.TypeFlags.BooleanLiteral) {
|
|
5849
|
+
const value = type.intrinsicName === "true";
|
|
5850
|
+
return [createApiCall("Literal", [value ? ts.factory.createTrue() : ts.factory.createFalse()]), true];
|
|
5851
|
+
}
|
|
5852
|
+
if (typeCheckerUtils.isUnion(type)) {
|
|
5853
|
+
return yield* processUnionType(type.types, context);
|
|
5854
|
+
}
|
|
5855
|
+
if (type.flags & ts.TypeFlags.Intersection) {
|
|
5856
|
+
return yield* processIntersectionType(type, context);
|
|
5857
|
+
}
|
|
5858
|
+
if (typeChecker.isArrayType(type)) {
|
|
5859
|
+
return yield* processArrayType(type, context);
|
|
5860
|
+
}
|
|
5861
|
+
if (typeChecker.isTupleType(type)) {
|
|
5862
|
+
return yield* processTupleType(type, context);
|
|
5863
|
+
}
|
|
5864
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
5865
|
+
const symbol3 = type.symbol || type.aliasSymbol;
|
|
5866
|
+
if (symbol3) {
|
|
5867
|
+
const typeName = typeChecker.symbolToString(symbol3);
|
|
5868
|
+
if (typeName === "Date") {
|
|
5869
|
+
return [createApiPropertyAccess("Date"), false];
|
|
5870
|
+
}
|
|
5871
|
+
if (typeName === "ReadonlyArray" || typeName === "Array") {
|
|
5872
|
+
return yield* processArrayType(type, context);
|
|
5873
|
+
}
|
|
5874
|
+
}
|
|
5875
|
+
const objectType = type;
|
|
5876
|
+
return yield* processObjectType(objectType, context);
|
|
5877
|
+
}
|
|
5878
|
+
return yield* fail(
|
|
5879
|
+
new UnsupportedTypeError(
|
|
5880
|
+
type,
|
|
5881
|
+
`Type with flags ${type.flags} is not supported`
|
|
5882
|
+
)
|
|
5883
|
+
);
|
|
5884
|
+
}
|
|
5885
|
+
);
|
|
5886
|
+
var processUnionType = fn(
|
|
5887
|
+
"StructuralSchemaGen.processUnionType"
|
|
5888
|
+
)(
|
|
5889
|
+
function* (types, context) {
|
|
5890
|
+
const { createApiCall, ts } = yield* service(StructuralSchemaGenContext);
|
|
5891
|
+
const allLiterals = types.every(
|
|
5892
|
+
(t) => t.flags & ts.TypeFlags.StringLiteral || t.flags & ts.TypeFlags.NumberLiteral || t.flags & ts.TypeFlags.BooleanLiteral
|
|
5893
|
+
);
|
|
5894
|
+
if (allLiterals) {
|
|
5895
|
+
const literals = yield* all(
|
|
5896
|
+
...types.map((t) => processType(t, context))
|
|
5897
|
+
);
|
|
5898
|
+
const literalValues = literals.map((expr) => {
|
|
5899
|
+
if (ts.isCallExpression(expr) && expr.arguments.length > 0) {
|
|
5900
|
+
return expr.arguments[0];
|
|
5901
|
+
}
|
|
5902
|
+
return expr;
|
|
5903
|
+
}).filter((arg) => arg !== void 0);
|
|
5904
|
+
return [createApiCall("Literal", literalValues), false];
|
|
5905
|
+
}
|
|
5906
|
+
const members = yield* all(
|
|
5907
|
+
...types.map((t) => processType(t, context))
|
|
5908
|
+
);
|
|
5909
|
+
if (members.length === 1) {
|
|
5910
|
+
return [members[0], false];
|
|
5911
|
+
}
|
|
5912
|
+
return [createApiCall("Union", members), false];
|
|
5913
|
+
}
|
|
5914
|
+
);
|
|
5915
|
+
var processIntersectionType = fn(
|
|
5916
|
+
"StructuralSchemaGen.processIntersectionType"
|
|
5917
|
+
)(
|
|
5918
|
+
function* (type, context) {
|
|
5919
|
+
const { createApiCall, ts } = yield* service(StructuralSchemaGenContext);
|
|
5920
|
+
const [firstSchema, ...otherSchemas] = yield* all(
|
|
5921
|
+
...type.types.map((t) => processType(t, context))
|
|
5922
|
+
);
|
|
5923
|
+
if (otherSchemas.length === 0) {
|
|
5924
|
+
return [firstSchema, false];
|
|
5925
|
+
}
|
|
5926
|
+
return [
|
|
5927
|
+
ts.factory.createCallExpression(
|
|
5928
|
+
ts.factory.createPropertyAccessExpression(
|
|
5929
|
+
firstSchema,
|
|
5930
|
+
"pipe"
|
|
5931
|
+
),
|
|
5932
|
+
[],
|
|
5933
|
+
otherSchemas.map((schema) => createApiCall("extend", [schema]))
|
|
5934
|
+
),
|
|
5935
|
+
false
|
|
5936
|
+
];
|
|
5937
|
+
}
|
|
5938
|
+
);
|
|
5939
|
+
var processArrayType = fn(
|
|
5940
|
+
"StructuralSchemaGen.processArrayType"
|
|
5941
|
+
)(
|
|
5942
|
+
function* (type, context) {
|
|
5943
|
+
const { createApiCall, typeChecker } = yield* service(StructuralSchemaGenContext);
|
|
5944
|
+
const typeArgs = typeChecker.getTypeArguments(type);
|
|
5945
|
+
if (typeArgs.length === 0) {
|
|
5946
|
+
return yield* fail(new UnsupportedTypeError(type, "Array type has no type arguments"));
|
|
5947
|
+
}
|
|
5948
|
+
const elementSchema = yield* processType(typeArgs[0], context);
|
|
5949
|
+
return [createApiCall("Array", [elementSchema]), false];
|
|
5950
|
+
}
|
|
5951
|
+
);
|
|
5952
|
+
var processTupleType = fn(
|
|
5953
|
+
"StructuralSchemaGen.processTupleType"
|
|
5954
|
+
)(
|
|
5955
|
+
function* (type, context) {
|
|
5956
|
+
const { createApiCall, typeChecker } = yield* service(StructuralSchemaGenContext);
|
|
5957
|
+
const typeArgs = typeChecker.getTypeArguments(type);
|
|
5958
|
+
const elementSchemas = yield* all(
|
|
5959
|
+
...typeArgs.map((t) => processType(t, context))
|
|
5960
|
+
);
|
|
5961
|
+
return [createApiCall("Tuple", elementSchemas), false];
|
|
5962
|
+
}
|
|
5963
|
+
);
|
|
5964
|
+
var processObjectType = fn(
|
|
5965
|
+
"StructuralSchemaGen.processObjectType"
|
|
5966
|
+
)(
|
|
5967
|
+
function* (type, context) {
|
|
5968
|
+
const {
|
|
5969
|
+
createApiCall,
|
|
5970
|
+
createApiPropertyAccess,
|
|
5971
|
+
program,
|
|
5972
|
+
ts,
|
|
5973
|
+
typeChecker,
|
|
5974
|
+
typeCheckerUtils
|
|
5975
|
+
} = yield* service(
|
|
5976
|
+
StructuralSchemaGenContext
|
|
5977
|
+
);
|
|
5978
|
+
let hasRecords = false;
|
|
5979
|
+
const properties = typeChecker.getPropertiesOfType(type);
|
|
5980
|
+
const propertyAssignments = [];
|
|
5981
|
+
for (const property of properties) {
|
|
5982
|
+
const propertyName = typeChecker.symbolToString(property);
|
|
5983
|
+
const propertyType = typeChecker.getTypeOfSymbol(property);
|
|
5984
|
+
const isOptional = (property.flags & ts.SymbolFlags.Optional) !== 0;
|
|
5985
|
+
let schemaExpr;
|
|
5986
|
+
if (isOptional) {
|
|
5987
|
+
if (program.getCompilerOptions().exactOptionalPropertyTypes) {
|
|
5988
|
+
if (typeCheckerUtils.isUnion(propertyType)) {
|
|
5989
|
+
const typeWithoutMissing = propertyType.types.filter((t) => !typeCheckerUtils.isMissingIntrinsicType(t));
|
|
5990
|
+
const [result, _] = yield* processUnionType(typeWithoutMissing, context);
|
|
5991
|
+
schemaExpr = createApiCall("optionalWith", [
|
|
5992
|
+
result,
|
|
5993
|
+
ts.factory.createObjectLiteralExpression([
|
|
5994
|
+
ts.factory.createPropertyAssignment("exact", ts.factory.createTrue())
|
|
5995
|
+
])
|
|
5996
|
+
]);
|
|
5997
|
+
}
|
|
5998
|
+
} else {
|
|
5999
|
+
schemaExpr = yield* processType(propertyType, context);
|
|
6000
|
+
schemaExpr = createApiCall("optional", [schemaExpr]);
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
if (!schemaExpr) {
|
|
6004
|
+
schemaExpr = yield* processType(propertyType, context);
|
|
6005
|
+
}
|
|
6006
|
+
const propertyNameNode = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propertyName) ? ts.factory.createIdentifier(propertyName) : ts.factory.createStringLiteral(propertyName);
|
|
6007
|
+
propertyAssignments.push(
|
|
6008
|
+
ts.factory.createPropertyAssignment(
|
|
6009
|
+
propertyNameNode,
|
|
6010
|
+
schemaExpr
|
|
6011
|
+
)
|
|
6012
|
+
);
|
|
6013
|
+
}
|
|
6014
|
+
const indexInfos = typeChecker.getIndexInfosOfType(type);
|
|
6015
|
+
const args2 = [
|
|
6016
|
+
ts.factory.createObjectLiteralExpression(propertyAssignments, propertyAssignments.length > 0)
|
|
6017
|
+
];
|
|
6018
|
+
for (const indexInfo of indexInfos) {
|
|
6019
|
+
hasRecords = true;
|
|
6020
|
+
const keyType = indexInfo.keyType;
|
|
6021
|
+
const valueType = indexInfo.type;
|
|
6022
|
+
const keySchema = yield* processType(keyType, context);
|
|
6023
|
+
const valueSchema = yield* processType(valueType, context);
|
|
6024
|
+
args2.push(
|
|
6025
|
+
ts.factory.createObjectLiteralExpression([
|
|
6026
|
+
ts.factory.createPropertyAssignment("key", keySchema),
|
|
6027
|
+
ts.factory.createPropertyAssignment("value", valueSchema)
|
|
6028
|
+
])
|
|
6029
|
+
);
|
|
6030
|
+
}
|
|
6031
|
+
if (!hasRecords && context.hoistName) {
|
|
6032
|
+
const ctx = yield* service(StructuralSchemaGenContext);
|
|
6033
|
+
yield* pushHoistedStatement(
|
|
6034
|
+
ctx,
|
|
6035
|
+
context.hoistName,
|
|
6036
|
+
type,
|
|
6037
|
+
ts.factory.createClassDeclaration(
|
|
6038
|
+
void 0,
|
|
6039
|
+
ts.factory.createIdentifier(context.hoistName),
|
|
6040
|
+
[],
|
|
6041
|
+
[ts.factory.createHeritageClause(
|
|
6042
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
6043
|
+
[
|
|
6044
|
+
ts.factory.createExpressionWithTypeArguments(
|
|
6045
|
+
ts.factory.createCallExpression(
|
|
6046
|
+
ts.factory.createCallExpression(
|
|
6047
|
+
createApiPropertyAccess("Class"),
|
|
6048
|
+
[ts.factory.createTypeReferenceNode(
|
|
6049
|
+
context.hoistName
|
|
6050
|
+
)],
|
|
6051
|
+
[ts.factory.createStringLiteral(context.hoistName)]
|
|
6052
|
+
),
|
|
6053
|
+
[],
|
|
6054
|
+
args2
|
|
6055
|
+
),
|
|
6056
|
+
[]
|
|
6057
|
+
)
|
|
6058
|
+
]
|
|
6059
|
+
)],
|
|
6060
|
+
[]
|
|
6061
|
+
),
|
|
6062
|
+
() => ts.factory.createIdentifier(context.hoistName)
|
|
6063
|
+
);
|
|
6064
|
+
return [ctx.hoistedSchemas.get(type)(), true];
|
|
6065
|
+
}
|
|
6066
|
+
return [createApiCall("Struct", args2), propertyAssignments.length === 0];
|
|
6067
|
+
}
|
|
6068
|
+
);
|
|
6069
|
+
var findNodeToProcess = fn("StructuralSchemaGen.findNodeToProcess")(
|
|
6070
|
+
function* (sourceFile, textRange) {
|
|
6071
|
+
const ts = yield* service(TypeScriptApi);
|
|
6072
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
6073
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6074
|
+
return pipe(
|
|
6075
|
+
tsUtils.getAncestorNodesInRange(sourceFile, textRange),
|
|
6076
|
+
filter((node) => ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)),
|
|
6077
|
+
filter((node) => tsUtils.isNodeInRange(textRange)(node.name)),
|
|
6078
|
+
filter((node) => (node.typeParameters || []).length === 0),
|
|
6079
|
+
map3((node) => ({
|
|
6080
|
+
node,
|
|
6081
|
+
identifier: node.name,
|
|
6082
|
+
type: typeChecker.getTypeAtLocation(node.name),
|
|
6083
|
+
isExported: node.modifiers ? (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 : false
|
|
6084
|
+
})),
|
|
6085
|
+
filter(({ type }) => !!type),
|
|
6086
|
+
head
|
|
6087
|
+
);
|
|
6088
|
+
}
|
|
6089
|
+
);
|
|
6090
|
+
var process = fn("StructuralSchemaGen.process")(
|
|
6091
|
+
function* (sourceFile, scope, typeMap, isExported, handleCodegeneratedComments) {
|
|
6092
|
+
const ts = yield* service(TypeScriptApi);
|
|
6093
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
6094
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6095
|
+
const typeParser = yield* service(TypeParser);
|
|
6096
|
+
const schemaIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Schema") || "Schema";
|
|
6097
|
+
const ctx = yield* makeStructuralSchemaGenContext(sourceFile, schemaIdentifier);
|
|
6098
|
+
for (const [name, type] of typeMap.entries()) {
|
|
6099
|
+
ctx.nameToType.set(name, type);
|
|
6100
|
+
}
|
|
6101
|
+
if (handleCodegeneratedComments) {
|
|
6102
|
+
for (const declaration of sourceFile.statements) {
|
|
6103
|
+
const nodeText = sourceFile.text.slice(declaration.pos, declaration.end);
|
|
6104
|
+
if (!nodeText.toLowerCase().includes("@effect-schema-codegenerated")) continue;
|
|
6105
|
+
const interleavingRange = ctx.rangesToDelete.find(
|
|
6106
|
+
(range) => range.pos < declaration.end && range.end > declaration.pos
|
|
6107
|
+
);
|
|
6108
|
+
if (interleavingRange) {
|
|
6109
|
+
interleavingRange.pos = Math.min(interleavingRange.pos, declaration.pos);
|
|
6110
|
+
interleavingRange.end = Math.max(interleavingRange.end, declaration.end);
|
|
6111
|
+
} else {
|
|
6112
|
+
ctx.rangesToDelete.push({
|
|
6113
|
+
pos: declaration.pos,
|
|
6114
|
+
end: declaration.end
|
|
6115
|
+
});
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
for (const symbol3 of typeChecker.getSymbolsInScope(scope, ts.SymbolFlags.Value)) {
|
|
6120
|
+
const name = typeChecker.symbolToString(symbol3);
|
|
6121
|
+
ctx.usedGlobalIdentifiers.set(name, 1);
|
|
6122
|
+
const type = typeChecker.getTypeOfSymbolAtLocation(symbol3, sourceFile);
|
|
6123
|
+
if (type) {
|
|
6124
|
+
const schemaType = yield* pipe(
|
|
6125
|
+
typeParser.effectSchemaType(type, scope),
|
|
6126
|
+
orElse2(() => void_)
|
|
6127
|
+
);
|
|
6128
|
+
if (schemaType) {
|
|
6129
|
+
ctx.hoistedSchemas.set(
|
|
6130
|
+
schemaType.A,
|
|
6131
|
+
() => {
|
|
6132
|
+
const expression = typeChecker.symbolToExpression(
|
|
6133
|
+
symbol3,
|
|
6134
|
+
ts.SymbolFlags.Value,
|
|
6135
|
+
scope,
|
|
6136
|
+
ts.NodeBuilderFlags.NoTruncation
|
|
6137
|
+
);
|
|
6138
|
+
if (expression) {
|
|
6139
|
+
return expression;
|
|
6140
|
+
}
|
|
6141
|
+
return ts.factory.createIdentifier(name);
|
|
6142
|
+
}
|
|
6143
|
+
);
|
|
6144
|
+
}
|
|
6145
|
+
}
|
|
6146
|
+
}
|
|
6147
|
+
const results = yield* pipe(
|
|
6148
|
+
all(
|
|
6149
|
+
...fromIterable(ctx.nameToType.entries()).map(
|
|
6150
|
+
([name, type]) => pipe(
|
|
6151
|
+
processType(type),
|
|
6152
|
+
orElse2(
|
|
6153
|
+
(error) => succeed(ts.addSyntheticLeadingComment(
|
|
6154
|
+
ts.factory.createIdentifier(""),
|
|
6155
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
6156
|
+
" " + String(error) + " ",
|
|
6157
|
+
true
|
|
6158
|
+
))
|
|
6159
|
+
),
|
|
6160
|
+
map4((_) => ({ requestedName: name, type, result: _ }))
|
|
6161
|
+
)
|
|
6162
|
+
)
|
|
6163
|
+
),
|
|
6164
|
+
provideService(StructuralSchemaGenContext, ctx)
|
|
6165
|
+
);
|
|
6166
|
+
for (const { requestedName, result, type } of results) {
|
|
6167
|
+
const statementIndex = ctx.typeToStatementIndex.get(type);
|
|
6168
|
+
if (statementIndex !== void 0) continue;
|
|
6169
|
+
ctx.schemaStatements.push(ts.factory.createVariableStatement(
|
|
6170
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
6171
|
+
ts.factory.createVariableDeclarationList(
|
|
6172
|
+
[ts.factory.createVariableDeclaration(
|
|
6173
|
+
ts.factory.createIdentifier(requestedName),
|
|
6174
|
+
void 0,
|
|
6175
|
+
void 0,
|
|
6176
|
+
result
|
|
6177
|
+
)],
|
|
6178
|
+
ts.NodeFlags.Const
|
|
6179
|
+
)
|
|
6180
|
+
));
|
|
6181
|
+
ctx.typeToStatementIndex.set(type, ctx.schemaStatements.length - 1);
|
|
6182
|
+
}
|
|
6183
|
+
if (isExported) {
|
|
6184
|
+
const statementsToExport = pipe(
|
|
6185
|
+
fromIterable(ctx.nameToType),
|
|
6186
|
+
map3(([_, type]) => ctx.typeToStatementIndex.get(type)),
|
|
6187
|
+
filter((index) => index !== void 0),
|
|
6188
|
+
dedupe
|
|
6189
|
+
);
|
|
6190
|
+
for (let i = 0; i < ctx.schemaStatements.length; i++) {
|
|
6191
|
+
if (!statementsToExport.includes(i)) continue;
|
|
6192
|
+
const statement = ctx.schemaStatements[i];
|
|
6193
|
+
if (ts.isVariableStatement(statement)) {
|
|
6194
|
+
ctx.schemaStatements[i] = ts.factory.updateVariableStatement(
|
|
6195
|
+
statement,
|
|
6196
|
+
ts.factory.createModifiersFromModifierFlags(ts.ModifierFlags.Export),
|
|
6197
|
+
statement.declarationList
|
|
6198
|
+
);
|
|
6199
|
+
} else if (ts.isClassDeclaration(statement)) {
|
|
6200
|
+
ctx.schemaStatements[i] = ts.factory.updateClassDeclaration(
|
|
6201
|
+
statement,
|
|
6202
|
+
ts.factory.createModifiersFromModifierFlags(ts.ModifierFlags.Export),
|
|
6203
|
+
statement.name,
|
|
6204
|
+
statement.typeParameters,
|
|
6205
|
+
statement.heritageClauses,
|
|
6206
|
+
statement.members
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
if (handleCodegeneratedComments) {
|
|
6212
|
+
for (let i = 0; i < ctx.schemaStatements.length; i++) {
|
|
6213
|
+
const statement = ctx.schemaStatements[i];
|
|
6214
|
+
ctx.schemaStatements[i] = ts.addSyntheticLeadingComment(
|
|
6215
|
+
statement,
|
|
6216
|
+
ts.SyntaxKind.SingleLineCommentTrivia,
|
|
6217
|
+
" @effect-schema-codegenerated: This schema will be re-generated by the effect-schema-codegens command, remove this comment to disable re-generation.",
|
|
6218
|
+
true
|
|
6219
|
+
);
|
|
6220
|
+
}
|
|
6221
|
+
}
|
|
6222
|
+
return ctx;
|
|
6223
|
+
}
|
|
6224
|
+
);
|
|
6225
|
+
var applyAtNode = fn("StructuralSchemaGen.applyAtNode")(
|
|
6226
|
+
function* (sourceFile, node, identifier, type, isExported) {
|
|
6227
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6228
|
+
const ts = yield* service(TypeScriptApi);
|
|
6229
|
+
const ctx = yield* process(sourceFile, node, /* @__PURE__ */ new Map([[ts.idText(identifier), type]]), isExported, false);
|
|
6230
|
+
for (const statement of ctx.schemaStatements) {
|
|
6231
|
+
changeTracker.insertNodeAt(sourceFile, node.pos, statement, { prefix: "\n", suffix: "\n" });
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
);
|
|
6235
|
+
|
|
6236
|
+
// src/codegens/typeToSchema.ts
|
|
6237
|
+
var typeToSchema = createCodegen({
|
|
6238
|
+
name: "typeToSchema",
|
|
6239
|
+
apply: fn("typeToSchema.apply")(function* (sourceFile, textRange) {
|
|
6240
|
+
const ts = yield* service(TypeScriptApi);
|
|
6241
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
6242
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6243
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6244
|
+
const typeParser = yield* service(TypeParser);
|
|
6245
|
+
const program = yield* service(TypeScriptProgram);
|
|
6246
|
+
const inThisFile = yield* getCodegensForSourceFile([typeToSchema], sourceFile);
|
|
6247
|
+
if (inThisFile.length > 1) {
|
|
6248
|
+
return yield* fail(
|
|
6249
|
+
new CodegenNotApplicableError("the typeToSchema codegen can be used only once per file")
|
|
6250
|
+
);
|
|
6251
|
+
}
|
|
6252
|
+
const parse3 = (node) => gen(function* () {
|
|
6253
|
+
if (!ts.isTypeAliasDeclaration(node)) {
|
|
6254
|
+
return yield* fail(
|
|
6255
|
+
new CodegenNotApplicableError(
|
|
6256
|
+
"this codegen is applicable only to a type alias where each object member is a schema to generate. e.g. `type ToGenerate = { UserSchema: User, TodoSchema: Todo}`"
|
|
6257
|
+
)
|
|
6258
|
+
);
|
|
6259
|
+
}
|
|
6260
|
+
const type = typeChecker.getTypeAtLocation(node.name);
|
|
6261
|
+
if (!type) {
|
|
6262
|
+
return yield* fail(
|
|
6263
|
+
new CodegenNotApplicableError(
|
|
6264
|
+
"error getting the type to process"
|
|
6265
|
+
)
|
|
6266
|
+
);
|
|
6267
|
+
}
|
|
6268
|
+
const nameToType = /* @__PURE__ */ new Map();
|
|
6269
|
+
const typeProperties = typeChecker.getPropertiesOfType(type);
|
|
6270
|
+
for (const symProp of typeProperties) {
|
|
6271
|
+
const symName = ts.symbolName(symProp);
|
|
6272
|
+
const propType = typeChecker.getTypeOfSymbolAtLocation(symProp, node);
|
|
6273
|
+
if (propType) nameToType.set(symName, propType);
|
|
6274
|
+
}
|
|
6275
|
+
const hash2 = pipe(
|
|
6276
|
+
fromIterable(nameToType),
|
|
6277
|
+
map3(([name, type2]) => {
|
|
6278
|
+
const typeString = typeChecker.typeToString(
|
|
6279
|
+
type2,
|
|
6280
|
+
node,
|
|
6281
|
+
ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseStructuralFallback
|
|
6282
|
+
);
|
|
6283
|
+
return name + ": " + typeString;
|
|
6284
|
+
}),
|
|
6285
|
+
join("\n"),
|
|
6286
|
+
cyrb53
|
|
6287
|
+
);
|
|
6288
|
+
return {
|
|
6289
|
+
hash: hash2,
|
|
6290
|
+
nameToType
|
|
6291
|
+
};
|
|
6292
|
+
});
|
|
6293
|
+
const nodeAndCommentRange = tsUtils.findNodeWithLeadingCommentAtPosition(sourceFile, textRange.pos);
|
|
6294
|
+
if (!nodeAndCommentRange) {
|
|
6295
|
+
return yield* fail(new CodegenNotApplicableError("no node and comment range affected"));
|
|
6296
|
+
}
|
|
6297
|
+
return yield* pipe(
|
|
6298
|
+
parse3(nodeAndCommentRange.node),
|
|
6299
|
+
map4(
|
|
6300
|
+
(_) => ({
|
|
6301
|
+
hash: _.hash,
|
|
6302
|
+
description: "Generate Schemas from types",
|
|
6303
|
+
apply: pipe(
|
|
6304
|
+
gen(function* () {
|
|
6305
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6306
|
+
const ctx = yield* process(
|
|
6307
|
+
sourceFile,
|
|
6308
|
+
nodeAndCommentRange.node,
|
|
6309
|
+
_.nameToType,
|
|
6310
|
+
true,
|
|
6311
|
+
true
|
|
6312
|
+
);
|
|
6313
|
+
const pos = sourceFile.end;
|
|
6314
|
+
for (const range of ctx.rangesToDelete) {
|
|
6315
|
+
changeTracker.deleteRange(sourceFile, range);
|
|
6316
|
+
}
|
|
6317
|
+
for (const statement of ctx.schemaStatements) {
|
|
6318
|
+
changeTracker.insertNodeAt(sourceFile, pos, statement, { prefix: "\n", suffix: "\n" });
|
|
6319
|
+
}
|
|
6320
|
+
}),
|
|
6321
|
+
provideService(TypeScriptApi, ts),
|
|
6322
|
+
provideService(TypeScriptUtils, tsUtils),
|
|
6323
|
+
provideService(TypeCheckerApi, typeChecker),
|
|
6324
|
+
provideService(TypeCheckerUtils, typeCheckerUtils),
|
|
6325
|
+
provideService(TypeParser, typeParser),
|
|
6326
|
+
provideService(TypeScriptProgram, program)
|
|
6327
|
+
)
|
|
6328
|
+
})
|
|
6329
|
+
)
|
|
6330
|
+
);
|
|
6331
|
+
})
|
|
6332
|
+
});
|
|
6333
|
+
|
|
5666
6334
|
// src/codegens.ts
|
|
5667
|
-
var codegens = [accessors, annotate];
|
|
6335
|
+
var codegens = [accessors, annotate, typeToSchema];
|
|
5668
6336
|
|
|
5669
6337
|
// src/diagnostics/outdatedEffectCodegen.ts
|
|
5670
6338
|
var outdatedEffectCodegen = createDiagnostic({
|