@effect/language-service 0.28.0 → 0.28.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/index.js CHANGED
@@ -2859,6 +2859,47 @@ function make3(ts, typeChecker) {
2859
2859
  "TypeParser.scopeType",
2860
2860
  (type) => type
2861
2861
  );
2862
+ const promiseLike = cachedBy(
2863
+ function(type, atLocation) {
2864
+ const thenProperty = type.getProperty("then");
2865
+ if (!thenProperty) return typeParserIssue("not a promise - missing then property", type, atLocation);
2866
+ const thenType = typeChecker.getTypeOfSymbolAtLocation(thenProperty, atLocation);
2867
+ if (!thenType) return typeParserIssue("not a promise - missing then property", type, atLocation);
2868
+ for (const callSignature of thenType.getCallSignatures()) {
2869
+ const parameter = callSignature.parameters[0];
2870
+ if (!parameter) continue;
2871
+ const parameterType = callSignature.getTypeParameterAtPosition(0);
2872
+ if (!parameterType) continue;
2873
+ let callbackCallSignatures = [];
2874
+ let toTest = [parameterType];
2875
+ while (toTest.length > 0) {
2876
+ const type2 = toTest.shift();
2877
+ if (!type2) continue;
2878
+ const callSignatures = type2.getCallSignatures();
2879
+ callbackCallSignatures = callbackCallSignatures.concat(callSignatures);
2880
+ if (type2.isUnion()) {
2881
+ toTest = toTest.concat(type2.types);
2882
+ }
2883
+ }
2884
+ for (const callableType of callbackCallSignatures) {
2885
+ const callbackParameter = callableType.parameters[0];
2886
+ if (!callbackParameter) {
2887
+ continue;
2888
+ }
2889
+ const callbackParameterType = callableType.getTypeParameterAtPosition(0);
2890
+ if (!callbackParameterType) {
2891
+ continue;
2892
+ }
2893
+ return succeed({
2894
+ type: callbackParameterType
2895
+ });
2896
+ }
2897
+ }
2898
+ return typeParserIssue("not a promise", type, atLocation);
2899
+ },
2900
+ "TypeParser.promiseLike",
2901
+ (type) => type
2902
+ );
2862
2903
  return {
2863
2904
  effectType,
2864
2905
  strictEffectType,
@@ -2874,7 +2915,8 @@ function make3(ts, typeChecker) {
2874
2915
  contextTag,
2875
2916
  pipeableType,
2876
2917
  pipeCall,
2877
- scopeType
2918
+ scopeType,
2919
+ promiseLike
2878
2920
  };
2879
2921
  }
2880
2922
 
@@ -11083,6 +11125,273 @@ var wrapWithPipe = createRefactor({
11083
11125
  })
11084
11126
  });
11085
11127
 
11128
+ // src/refactors/writeTagClassAccessors.ts
11129
+ var writeTagClassAccessors = createRefactor({
11130
+ name: "writeTagClassAccessors",
11131
+ description: "Implement Service accessors",
11132
+ apply: fn("writeTagClassAccessors.apply")(function* (sourceFile, textRange) {
11133
+ const ts = yield* service(TypeScriptApi);
11134
+ const typeChecker = yield* service(TypeCheckerApi);
11135
+ const typeParser = yield* service(TypeParser);
11136
+ const effectIdentifier = pipe(
11137
+ yield* option(
11138
+ findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect")
11139
+ ),
11140
+ match({
11141
+ onNone: () => "Effect",
11142
+ onSome: (_) => _.text
11143
+ })
11144
+ );
11145
+ const createConstantProperty = (className, propertyName, type) => ts.factory.createPropertyDeclaration(
11146
+ [ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)],
11147
+ propertyName,
11148
+ void 0,
11149
+ type,
11150
+ ts.factory.createCallExpression(
11151
+ ts.factory.createPropertyAccessExpression(
11152
+ ts.factory.createIdentifier(effectIdentifier),
11153
+ "andThen"
11154
+ ),
11155
+ void 0,
11156
+ [
11157
+ ts.factory.createIdentifier(className.text),
11158
+ ts.factory.createArrowFunction(
11159
+ void 0,
11160
+ void 0,
11161
+ [ts.factory.createParameterDeclaration(
11162
+ void 0,
11163
+ void 0,
11164
+ "_"
11165
+ )],
11166
+ void 0,
11167
+ void 0,
11168
+ ts.factory.createPropertyAccessExpression(
11169
+ ts.factory.createIdentifier("_"),
11170
+ propertyName
11171
+ )
11172
+ )
11173
+ ]
11174
+ )
11175
+ );
11176
+ const createFunctionProperty = (className, propertyName, type, forceAny) => {
11177
+ const arrowBody = ts.factory.createCallExpression(
11178
+ ts.factory.createPropertyAccessExpression(
11179
+ ts.factory.createIdentifier(effectIdentifier),
11180
+ "andThen"
11181
+ ),
11182
+ void 0,
11183
+ [
11184
+ ts.factory.createIdentifier(className.text),
11185
+ ts.factory.createArrowFunction(
11186
+ void 0,
11187
+ void 0,
11188
+ [ts.factory.createParameterDeclaration(
11189
+ void 0,
11190
+ void 0,
11191
+ "_",
11192
+ void 0,
11193
+ forceAny ? ts.factory.createTypeReferenceNode("any") : void 0
11194
+ )],
11195
+ void 0,
11196
+ void 0,
11197
+ ts.factory.createCallExpression(
11198
+ ts.factory.createPropertyAccessExpression(
11199
+ ts.factory.createIdentifier("_"),
11200
+ propertyName
11201
+ ),
11202
+ void 0,
11203
+ [
11204
+ ts.factory.createSpreadElement(ts.factory.createIdentifier("args"))
11205
+ ]
11206
+ )
11207
+ )
11208
+ ]
11209
+ );
11210
+ return ts.factory.createPropertyDeclaration(
11211
+ [ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)],
11212
+ propertyName,
11213
+ void 0,
11214
+ type,
11215
+ ts.factory.createArrowFunction(
11216
+ void 0,
11217
+ void 0,
11218
+ [ts.factory.createParameterDeclaration(
11219
+ void 0,
11220
+ ts.factory.createToken(ts.SyntaxKind.DotDotDotToken),
11221
+ "args",
11222
+ void 0,
11223
+ forceAny ? ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode("any")) : void 0
11224
+ )],
11225
+ void 0,
11226
+ void 0,
11227
+ forceAny ? ts.factory.createAsExpression(arrowBody, ts.factory.createTypeReferenceNode("any")) : arrowBody
11228
+ )
11229
+ );
11230
+ };
11231
+ const generateReturnType = (type, atLocation, className) => pipe(
11232
+ typeParser.effectType(type, atLocation),
11233
+ flatMap2((returnedEffect) => {
11234
+ const contextType = returnedEffect.R.flags & ts.TypeFlags.Never ? ts.factory.createTypeReferenceNode(className.text) : ts.factory.createUnionTypeNode(
11235
+ [
11236
+ ts.factory.createTypeReferenceNode(className.text),
11237
+ typeChecker.typeToTypeNode(returnedEffect.R, atLocation, ts.NodeBuilderFlags.NoTruncation)
11238
+ ]
11239
+ );
11240
+ const successType = typeChecker.typeToTypeNode(
11241
+ returnedEffect.A,
11242
+ atLocation,
11243
+ ts.NodeBuilderFlags.NoTruncation
11244
+ );
11245
+ if (!successType) return fail("error generating success type");
11246
+ const failureType = typeChecker.typeToTypeNode(
11247
+ returnedEffect.E,
11248
+ atLocation,
11249
+ ts.NodeBuilderFlags.NoTruncation
11250
+ );
11251
+ if (!failureType) return fail("error generating failure type");
11252
+ const typeNode = ts.factory.createTypeReferenceNode(
11253
+ ts.factory.createQualifiedName(
11254
+ ts.factory.createIdentifier(effectIdentifier),
11255
+ ts.factory.createIdentifier("Effect")
11256
+ ),
11257
+ [successType, failureType, contextType]
11258
+ );
11259
+ return succeed(typeNode);
11260
+ }),
11261
+ orElse2(
11262
+ () => pipe(
11263
+ typeParser.promiseLike(type, atLocation),
11264
+ flatMap2(({ type: type2 }) => {
11265
+ const successType = typeChecker.typeToTypeNode(
11266
+ type2,
11267
+ atLocation,
11268
+ ts.NodeBuilderFlags.NoTruncation
11269
+ );
11270
+ if (!successType) return fail("error generating success type");
11271
+ return succeed(ts.factory.createTypeReferenceNode(
11272
+ ts.factory.createQualifiedName(
11273
+ ts.factory.createIdentifier(effectIdentifier),
11274
+ ts.factory.createIdentifier("Effect")
11275
+ ),
11276
+ [
11277
+ successType,
11278
+ ts.factory.createTypeReferenceNode(
11279
+ ts.factory.createQualifiedName(
11280
+ ts.factory.createIdentifier("Cause"),
11281
+ ts.factory.createIdentifier("UnknownException")
11282
+ )
11283
+ ),
11284
+ ts.factory.createTypeReferenceNode(className.text)
11285
+ ]
11286
+ ));
11287
+ })
11288
+ )
11289
+ ),
11290
+ orElse2(() => {
11291
+ const successType = typeChecker.typeToTypeNode(type, atLocation, ts.NodeBuilderFlags.NoTruncation);
11292
+ if (!successType) return fail("error generating success type");
11293
+ const typeNode = ts.factory.createTypeReferenceNode(
11294
+ ts.factory.createQualifiedName(
11295
+ ts.factory.createIdentifier(effectIdentifier),
11296
+ ts.factory.createIdentifier("Effect")
11297
+ ),
11298
+ [
11299
+ successType,
11300
+ ts.factory.createTypeReferenceNode("never"),
11301
+ ts.factory.createTypeReferenceNode(className.text)
11302
+ ]
11303
+ );
11304
+ return succeed(typeNode);
11305
+ })
11306
+ );
11307
+ const proxySignature = (signature, atLocation, className) => gen(function* () {
11308
+ const signatureDeclaration = typeChecker.signatureToSignatureDeclaration(
11309
+ signature,
11310
+ ts.SyntaxKind.FunctionType,
11311
+ atLocation,
11312
+ ts.NodeBuilderFlags.NoTruncation
11313
+ );
11314
+ if (!signatureDeclaration) return yield* fail("error generating signature");
11315
+ const returnType = yield* generateReturnType(signature.getReturnType(), atLocation, className);
11316
+ return ts.factory.createFunctionTypeNode(
11317
+ signatureDeclaration.typeParameters,
11318
+ signatureDeclaration.parameters,
11319
+ returnType
11320
+ );
11321
+ });
11322
+ const writeAccessors = fn("writeTagClassAccessors.writeAccessors")(
11323
+ function* (service2, className, atLocation) {
11324
+ const changeTracker = yield* service(ChangeTracker);
11325
+ const insertLocation = atLocation.members.length > 0 ? atLocation.members[0].pos : atLocation.getEnd() - 1;
11326
+ for (const property of typeChecker.getPropertiesOfType(service2)) {
11327
+ const servicePropertyType = typeChecker.getTypeOfSymbolAtLocation(property, atLocation);
11328
+ const callSignatures = [];
11329
+ let propertyDeclaration = void 0;
11330
+ for (const signature of servicePropertyType.getCallSignatures()) {
11331
+ yield* pipe(
11332
+ proxySignature(signature, atLocation, className),
11333
+ map4((sig) => {
11334
+ callSignatures.push(sig);
11335
+ }),
11336
+ ignore
11337
+ );
11338
+ }
11339
+ if (callSignatures.length === 0) {
11340
+ yield* pipe(
11341
+ generateReturnType(servicePropertyType, atLocation, className),
11342
+ map4((type) => {
11343
+ propertyDeclaration = createConstantProperty(className, property.getName(), type);
11344
+ }),
11345
+ ignore
11346
+ );
11347
+ } else {
11348
+ const allSignatures = ts.factory.createIntersectionTypeNode(callSignatures);
11349
+ const type = yield* simplifyTypeNode(allSignatures);
11350
+ propertyDeclaration = createFunctionProperty(className, property.getName(), type, callSignatures.length > 1);
11351
+ }
11352
+ if (propertyDeclaration) {
11353
+ const oldProperty = atLocation.members.filter(ts.isPropertyDeclaration).find((p) => {
11354
+ const symbol3 = typeChecker.getSymbolAtLocation(p.name);
11355
+ return symbol3?.getName() === property.getName();
11356
+ });
11357
+ if (oldProperty) {
11358
+ changeTracker.deleteRange(sourceFile, {
11359
+ pos: oldProperty.getStart(sourceFile),
11360
+ end: oldProperty.getEnd()
11361
+ });
11362
+ changeTracker.insertNodeAt(sourceFile, oldProperty.getStart(sourceFile), propertyDeclaration);
11363
+ } else {
11364
+ changeTracker.insertNodeAt(sourceFile, insertLocation, propertyDeclaration, { suffix: "\n" });
11365
+ }
11366
+ }
11367
+ }
11368
+ }
11369
+ );
11370
+ const writeTagClassAccessors2 = (node) => gen(function* () {
11371
+ if (!ts.isClassDeclaration(node)) return yield* fail(new RefactorNotApplicableError());
11372
+ if (!node.name) return yield* fail(new RefactorNotApplicableError());
11373
+ const classSym = typeChecker.getSymbolAtLocation(node.name);
11374
+ if (!classSym) return yield* fail(new RefactorNotApplicableError());
11375
+ const type = typeChecker.getTypeOfSymbol(classSym);
11376
+ const { Service } = yield* pipe(
11377
+ typeParser.contextTag(type, node),
11378
+ orElse2(() => fail(new RefactorNotApplicableError()))
11379
+ );
11380
+ return {
11381
+ kind: "refactor.rewrite.effect.writeTagClassAccessors",
11382
+ description: "Implement Service accessors",
11383
+ apply: pipe(
11384
+ writeAccessors(Service, node.name, node),
11385
+ provideService(TypeCheckerApi, typeChecker),
11386
+ provideService(TypeScriptApi, ts)
11387
+ )
11388
+ };
11389
+ });
11390
+ const parentNodes = yield* getAncestorNodesInRange(sourceFile, textRange);
11391
+ return yield* firstSuccessOf(parentNodes.map(writeTagClassAccessors2));
11392
+ })
11393
+ });
11394
+
11086
11395
  // src/refactors.ts
11087
11396
  var refactors = [
11088
11397
  asyncAwaitToGen,
@@ -11100,7 +11409,8 @@ var refactors = [
11100
11409
  wrapWithEffectGen,
11101
11410
  wrapWithPipe,
11102
11411
  effectGenToFn,
11103
- togglePipeStyle
11412
+ togglePipeStyle,
11413
+ writeTagClassAccessors
11104
11414
  ];
11105
11415
 
11106
11416
  // src/index.ts