@effect/language-service 0.42.0 → 0.43.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.42.0",
3
+ "version": "0.43.0",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "bin": {
package/transform.js CHANGED
@@ -1189,8 +1189,25 @@ var defaults = {
1189
1189
  barrelImportPackages: [],
1190
1190
  importAliases: {},
1191
1191
  renames: true,
1192
- noExternal: false
1192
+ noExternal: false,
1193
+ keyPatterns: [{
1194
+ target: "service",
1195
+ pattern: "default",
1196
+ skipLeadingPath: ["src/"]
1197
+ }]
1193
1198
  };
1199
+ function parseKeyPatterns(patterns) {
1200
+ const result = [];
1201
+ for (const entry of patterns) {
1202
+ if (!isObject(entry)) continue;
1203
+ result.push({
1204
+ target: hasProperty(entry, "target") && isString(entry.target) && ["service", "error"].includes(entry.target.toLowerCase()) ? entry.target.toLowerCase() : "service",
1205
+ pattern: hasProperty(entry, "pattern") && isString(entry.pattern) && ["package-identifier", "default"].includes(entry.pattern.toLowerCase()) ? entry.pattern.toLowerCase() : "default",
1206
+ skipLeadingPath: hasProperty(entry, "skipLeadingPath") && isArray(entry.skipLeadingPath) && entry.skipLeadingPath.every(isString) ? entry.skipLeadingPath : ["src/"]
1207
+ });
1208
+ }
1209
+ return result;
1210
+ }
1194
1211
  function parse(config) {
1195
1212
  return {
1196
1213
  refactors: isObject(config) && hasProperty(config, "refactors") && isBoolean(config.refactors) ? config.refactors : defaults.refactors,
@@ -1208,7 +1225,8 @@ function parse(config) {
1208
1225
  importAliases: isObject(config) && hasProperty(config, "importAliases") && isRecord(config.importAliases) ? map2(config.importAliases, (value) => String(value)) : defaults.importAliases,
1209
1226
  topLevelNamedReexports: isObject(config) && hasProperty(config, "topLevelNamedReexports") && isString(config.topLevelNamedReexports) && ["ignore", "follow"].includes(config.topLevelNamedReexports.toLowerCase()) ? config.topLevelNamedReexports.toLowerCase() : defaults.topLevelNamedReexports,
1210
1227
  renames: isObject(config) && hasProperty(config, "renames") && isBoolean(config.renames) ? config.renames : defaults.renames,
1211
- noExternal: isObject(config) && hasProperty(config, "noExternal") && isBoolean(config.noExternal) ? config.noExternal : defaults.noExternal
1228
+ noExternal: isObject(config) && hasProperty(config, "noExternal") && isBoolean(config.noExternal) ? config.noExternal : defaults.noExternal,
1229
+ keyPatterns: isObject(config) && hasProperty(config, "keyPatterns") && isArray(config.keyPatterns) ? parseKeyPatterns(config.keyPatterns) : defaults.keyPatterns
1212
1230
  };
1213
1231
  }
1214
1232
 
@@ -3462,6 +3480,126 @@ var classSelfMismatch = createDiagnostic({
3462
3480
  })
3463
3481
  });
3464
3482
 
3483
+ // src/core/KeyBuilder.ts
3484
+ var makeKeyBuilder = fn("KeyBuilder")(
3485
+ function* (sourceFile) {
3486
+ const ts = yield* service(TypeScriptApi);
3487
+ const tsUtils = yield* service(TypeScriptUtils);
3488
+ const program = yield* service(TypeScriptProgram);
3489
+ const options = yield* service(LanguageServicePluginOptions);
3490
+ const packageInfo = tsUtils.resolveModuleWithPackageInfoFromSourceFile(program, sourceFile);
3491
+ function createString2(classNameText, kind) {
3492
+ if (!packageInfo) return;
3493
+ for (const keyPattern of options.keyPatterns) {
3494
+ if (keyPattern.target !== kind) continue;
3495
+ if (keyPattern.pattern === "package-identifier") {
3496
+ return packageInfo.name + "/" + classNameText;
3497
+ }
3498
+ const dirPath = getDirectoryPath(ts, sourceFile.fileName);
3499
+ if (!dirPath.startsWith(packageInfo.packageDirectory)) return;
3500
+ let subDirectory = dirPath.slice(packageInfo.packageDirectory.length);
3501
+ if (subDirectory.startsWith("/")) subDirectory = subDirectory.slice(1);
3502
+ const lastIndex = sourceFile.fileName.lastIndexOf("/");
3503
+ let subModule = lastIndex === -1 ? "" : sourceFile.fileName.slice(lastIndex + 1);
3504
+ for (const extension of [".ts", ".tsx", ".js", ".jsx"]) {
3505
+ if (subModule.toLowerCase().endsWith(extension)) {
3506
+ subModule = subModule.slice(0, -extension.length);
3507
+ break;
3508
+ }
3509
+ }
3510
+ if (subModule.toLowerCase().endsWith("/index")) subModule = subModule.slice(0, -6);
3511
+ if (subModule.startsWith("/")) subModule = subModule.slice(1);
3512
+ for (const prefix of keyPattern.skipLeadingPath) {
3513
+ if (subDirectory.startsWith(prefix)) {
3514
+ subDirectory = subDirectory.slice(prefix.length);
3515
+ break;
3516
+ }
3517
+ }
3518
+ const parts = [packageInfo.name, subDirectory, subModule].concat(
3519
+ subModule.toLowerCase() === classNameText.toLowerCase() ? [] : [classNameText]
3520
+ );
3521
+ return parts.filter((_) => String(_).trim().length > 0).join("/");
3522
+ }
3523
+ }
3524
+ return {
3525
+ createString: createString2
3526
+ };
3527
+ }
3528
+ );
3529
+ var keyBuilderCache = /* @__PURE__ */ new Map();
3530
+ var getOrMakeKeyBuilder = fn("getOrMakeKeyBuilder")(function* (sourceFile) {
3531
+ const keyBuilder = keyBuilderCache.get(sourceFile.fileName) || (yield* makeKeyBuilder(sourceFile));
3532
+ keyBuilderCache.set(sourceFile.fileName, keyBuilder);
3533
+ return keyBuilder;
3534
+ });
3535
+ function createString(sourceFile, identifier, kind) {
3536
+ return map4(
3537
+ getOrMakeKeyBuilder(sourceFile),
3538
+ (identifierBuilder) => identifierBuilder.createString(identifier, kind)
3539
+ );
3540
+ }
3541
+
3542
+ // src/diagnostics/deterministicKeys.ts
3543
+ var deterministicKeys = createDiagnostic({
3544
+ name: "deterministicKeys",
3545
+ code: 25,
3546
+ severity: "off",
3547
+ apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
3548
+ const ts = yield* service(TypeScriptApi);
3549
+ const typeParser = yield* service(TypeParser);
3550
+ const nodeToVisit = [];
3551
+ const appendNodeToVisit = (node) => {
3552
+ nodeToVisit.push(node);
3553
+ return void 0;
3554
+ };
3555
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3556
+ while (nodeToVisit.length > 0) {
3557
+ const node = nodeToVisit.shift();
3558
+ if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
3559
+ const result = yield* pipe(
3560
+ pipe(
3561
+ typeParser.extendsEffectService(node),
3562
+ orElse2(() => typeParser.extendsContextTag(node)),
3563
+ orElse2(() => typeParser.extendsEffectTag(node)),
3564
+ map4(({ className, keyStringLiteral }) => ({ keyStringLiteral, className, target: "service" }))
3565
+ ),
3566
+ orElse2(
3567
+ () => pipe(
3568
+ typeParser.extendsDataTaggedError(node),
3569
+ orElse2(() => typeParser.extendsSchemaTaggedError(node)),
3570
+ map4(({ className, keyStringLiteral }) => ({ keyStringLiteral, className, target: "error" }))
3571
+ )
3572
+ ),
3573
+ orElse2(() => void_)
3574
+ );
3575
+ if (result && result.keyStringLiteral) {
3576
+ const { className, keyStringLiteral } = result;
3577
+ const classNameText = ts.idText(className);
3578
+ const expectedKey = yield* createString(sourceFile, classNameText, result.target);
3579
+ if (!expectedKey) return;
3580
+ const actualIdentifier = keyStringLiteral.text;
3581
+ if (actualIdentifier !== expectedKey) {
3582
+ report({
3583
+ location: keyStringLiteral,
3584
+ messageText: `Key should be '${expectedKey}'`,
3585
+ fixes: [{
3586
+ fixName: "deterministicKeys_fix",
3587
+ description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
3588
+ apply: gen(function* () {
3589
+ const changeTracker = yield* service(ChangeTracker);
3590
+ const newStringLiteral = ts.factory.createStringLiteral(expectedKey);
3591
+ changeTracker.replaceNode(sourceFile, keyStringLiteral, newStringLiteral);
3592
+ })
3593
+ }]
3594
+ });
3595
+ }
3596
+ }
3597
+ }
3598
+ ts.forEachChild(node, appendNodeToVisit);
3599
+ }
3600
+ })
3601
+ });
3602
+
3465
3603
  // src/diagnostics/duplicatePackage.ts
3466
3604
  var checkedPackagesCache = /* @__PURE__ */ new Map();
3467
3605
  var programResolvedCacheSize = /* @__PURE__ */ new Map();
@@ -5471,7 +5609,8 @@ var diagnostics = [
5471
5609
  outdatedEffectCodegen,
5472
5610
  overriddenSchemaConstructor,
5473
5611
  unsupportedServiceAccessors,
5474
- nonObjectEffectServiceType
5612
+ nonObjectEffectServiceType,
5613
+ deterministicKeys
5475
5614
  ];
5476
5615
 
5477
5616
  // src/transform.ts