@effect/language-service 0.83.1 → 0.84.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/index.js CHANGED
@@ -3775,6 +3775,25 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
3775
3775
  return typeChecker.getTypeAtLocation(node);
3776
3776
  }
3777
3777
  }
3778
+ function resolveToGlobalSymbol(symbol3) {
3779
+ if (symbol3.flags & ts.SymbolFlags.Alias) {
3780
+ symbol3 = typeChecker.getAliasedSymbol(symbol3);
3781
+ }
3782
+ let depth = 0;
3783
+ while (depth < 2 && symbol3.valueDeclaration && ts.isVariableDeclaration(symbol3.valueDeclaration)) {
3784
+ const initializer = symbol3.valueDeclaration.initializer;
3785
+ if (!initializer) break;
3786
+ let nextSymbol = typeChecker.getSymbolAtLocation(initializer);
3787
+ if (!nextSymbol) break;
3788
+ if (nextSymbol.flags & ts.SymbolFlags.Alias) {
3789
+ nextSymbol = typeChecker.getAliasedSymbol(nextSymbol);
3790
+ }
3791
+ if (nextSymbol === symbol3) break;
3792
+ symbol3 = nextSymbol;
3793
+ depth++;
3794
+ }
3795
+ return symbol3;
3796
+ }
3778
3797
  return {
3779
3798
  isUnion,
3780
3799
  isReadonlyArrayType,
@@ -3788,7 +3807,8 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
3788
3807
  expectedAndRealType,
3789
3808
  typeToSimplifiedTypeNode,
3790
3809
  isGlobalErrorType,
3791
- getTypeAtLocation
3810
+ getTypeAtLocation,
3811
+ resolveToGlobalSymbol
3792
3812
  };
3793
3813
  }
3794
3814
 
@@ -4476,7 +4496,11 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4476
4496
  }
4477
4497
  currentParent = nodeToCheck.parent;
4478
4498
  }
4479
- return { scopeNode, effectGen: effectGenResult };
4499
+ return {
4500
+ inEffect: effectGenResult !== void 0 && effectGenResult.body.statements.length > 0 && scopeNode === effectGenResult.generatorFunction,
4501
+ scopeNode,
4502
+ effectGen: effectGenResult
4503
+ };
4480
4504
  });
4481
4505
  const effectFn = cachedBy(
4482
4506
  function(node) {
@@ -8836,6 +8860,128 @@ var genericEffectServices = createDiagnostic({
8836
8860
  })
8837
8861
  });
8838
8862
 
8863
+ // src/diagnostics/globalConsoleInEffect.ts
8864
+ var consoleMethodAlternatives = {
8865
+ "log": "Effect.log or Logger",
8866
+ "warn": "Effect.logWarning or Logger",
8867
+ "error": "Effect.logError or Logger",
8868
+ "info": "Effect.logInfo or Logger",
8869
+ "debug": "Effect.logDebug or Logger",
8870
+ "trace": "Effect.logTrace or Logger"
8871
+ };
8872
+ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
8873
+ const ts = yield* service(TypeScriptApi);
8874
+ const typeChecker = yield* service(TypeCheckerApi);
8875
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
8876
+ const typeParser = yield* service(TypeParser);
8877
+ const consoleSymbol = typeChecker.resolveName("console", void 0, ts.SymbolFlags.Value, false);
8878
+ if (!consoleSymbol) return;
8879
+ const nodeToVisit = [];
8880
+ const appendNodeToVisit = (node) => {
8881
+ nodeToVisit.push(node);
8882
+ return void 0;
8883
+ };
8884
+ ts.forEachChild(sourceFile, appendNodeToVisit);
8885
+ while (nodeToVisit.length > 0) {
8886
+ const node = nodeToVisit.shift();
8887
+ ts.forEachChild(node, appendNodeToVisit);
8888
+ if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression)) continue;
8889
+ const method = ts.idText(node.expression.name);
8890
+ const alternative = consoleMethodAlternatives[method];
8891
+ if (!alternative) continue;
8892
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
8893
+ if (!symbol3) continue;
8894
+ if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== consoleSymbol) continue;
8895
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
8896
+ if (inEffect !== checkInEffect) continue;
8897
+ report({
8898
+ location: node,
8899
+ messageText: checkInEffect ? `Prefer using ${alternative} instead of console.${method} inside Effect generators.` : `Prefer using ${alternative} instead of console.${method}.`,
8900
+ fixes: []
8901
+ });
8902
+ }
8903
+ });
8904
+ var globalConsoleInEffect = createDiagnostic({
8905
+ name: "globalConsoleInEffect",
8906
+ code: 56,
8907
+ description: "Warns when using console methods inside Effect generators instead of Effect.log/Logger",
8908
+ group: "effectNative",
8909
+ severity: "off",
8910
+ fixable: false,
8911
+ supportedEffect: ["v3", "v4"],
8912
+ apply: makeGlobalConsoleApply(true)
8913
+ });
8914
+
8915
+ // src/diagnostics/globalConsole.ts
8916
+ var globalConsole = createDiagnostic({
8917
+ name: "globalConsole",
8918
+ code: 60,
8919
+ description: "Warns when using console methods outside Effect generators instead of Effect.log/Logger",
8920
+ group: "effectNative",
8921
+ severity: "off",
8922
+ fixable: false,
8923
+ supportedEffect: ["v3", "v4"],
8924
+ apply: makeGlobalConsoleApply(false)
8925
+ });
8926
+
8927
+ // src/diagnostics/globalDateInEffect.ts
8928
+ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
8929
+ const ts = yield* service(TypeScriptApi);
8930
+ const typeChecker = yield* service(TypeCheckerApi);
8931
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
8932
+ const typeParser = yield* service(TypeParser);
8933
+ const dateSymbol = typeChecker.resolveName("Date", void 0, ts.SymbolFlags.Value, false);
8934
+ if (!dateSymbol) return;
8935
+ const nodeToVisit = [];
8936
+ const appendNodeToVisit = (node) => {
8937
+ nodeToVisit.push(node);
8938
+ return void 0;
8939
+ };
8940
+ ts.forEachChild(sourceFile, appendNodeToVisit);
8941
+ while (nodeToVisit.length > 0) {
8942
+ const node = nodeToVisit.shift();
8943
+ ts.forEachChild(node, appendNodeToVisit);
8944
+ let messageText;
8945
+ let objectNode;
8946
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
8947
+ objectNode = node.expression.expression;
8948
+ messageText = checkInEffect ? "Prefer using Clock or DateTime from Effect instead of Date.now() inside Effect generators." : "Prefer using Clock or DateTime from Effect instead of Date.now().";
8949
+ } else if (ts.isNewExpression(node)) {
8950
+ objectNode = node.expression;
8951
+ messageText = checkInEffect ? "Prefer using DateTime from Effect instead of new Date() inside Effect generators." : "Prefer using DateTime from Effect instead of new Date().";
8952
+ }
8953
+ if (!messageText || !objectNode) continue;
8954
+ const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
8955
+ if (!symbol3) continue;
8956
+ if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== dateSymbol) continue;
8957
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
8958
+ if (inEffect !== checkInEffect) continue;
8959
+ report({ location: node, messageText, fixes: [] });
8960
+ }
8961
+ });
8962
+ var globalDateInEffect = createDiagnostic({
8963
+ name: "globalDateInEffect",
8964
+ code: 55,
8965
+ description: "Warns when using Date.now() or new Date() inside Effect generators instead of Clock/DateTime",
8966
+ group: "effectNative",
8967
+ severity: "off",
8968
+ fixable: false,
8969
+ supportedEffect: ["v3", "v4"],
8970
+ apply: makeGlobalDateApply(true)
8971
+ });
8972
+
8973
+ // src/diagnostics/globalDate.ts
8974
+ var globalDate = createDiagnostic({
8975
+ name: "globalDate",
8976
+ code: 59,
8977
+ description: "Warns when using Date.now() or new Date() outside Effect generators instead of Clock/DateTime",
8978
+ group: "effectNative",
8979
+ severity: "off",
8980
+ fixable: false,
8981
+ supportedEffect: ["v3", "v4"],
8982
+ apply: makeGlobalDateApply(false)
8983
+ });
8984
+
8839
8985
  // src/diagnostics/globalErrorInEffectCatch.ts
8840
8986
  var globalErrorInEffectCatch = createDiagnostic({
8841
8987
  name: "globalErrorInEffectCatch",
@@ -8955,46 +9101,186 @@ var globalErrorInEffectFailure = createDiagnostic({
8955
9101
  })
8956
9102
  });
8957
9103
 
9104
+ // src/diagnostics/globalFetchInEffect.ts
9105
+ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
9106
+ const ts = yield* service(TypeScriptApi);
9107
+ const typeChecker = yield* service(TypeCheckerApi);
9108
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9109
+ const typeParser = yield* service(TypeParser);
9110
+ const fetchSymbol = typeChecker.resolveName("fetch", void 0, ts.SymbolFlags.Value, false);
9111
+ if (!fetchSymbol) return;
9112
+ const effectVersion = typeParser.supportedEffect();
9113
+ const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
9114
+ const messageText = checkInEffect ? `Prefer using HttpClient from ${packageName} instead of the global 'fetch' function inside Effect generators.` : `Prefer using HttpClient from ${packageName} instead of the global 'fetch' function.`;
9115
+ const nodeToVisit = [];
9116
+ const appendNodeToVisit = (node) => {
9117
+ nodeToVisit.push(node);
9118
+ return void 0;
9119
+ };
9120
+ ts.forEachChild(sourceFile, appendNodeToVisit);
9121
+ while (nodeToVisit.length > 0) {
9122
+ const node = nodeToVisit.shift();
9123
+ if (ts.isCallExpression(node)) {
9124
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
9125
+ if (symbol3 && typeCheckerUtils.resolveToGlobalSymbol(symbol3) === fetchSymbol) {
9126
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
9127
+ if (inEffect === checkInEffect) {
9128
+ report({
9129
+ location: node.expression,
9130
+ messageText,
9131
+ fixes: []
9132
+ });
9133
+ }
9134
+ }
9135
+ }
9136
+ ts.forEachChild(node, appendNodeToVisit);
9137
+ }
9138
+ });
9139
+ var globalFetchInEffect = createDiagnostic({
9140
+ name: "globalFetchInEffect",
9141
+ code: 63,
9142
+ description: "Warns when using the global fetch function inside Effect generators instead of the Effect HTTP client",
9143
+ group: "effectNative",
9144
+ severity: "off",
9145
+ fixable: false,
9146
+ supportedEffect: ["v3", "v4"],
9147
+ apply: makeGlobalFetchApply(true)
9148
+ });
9149
+
8958
9150
  // src/diagnostics/globalFetch.ts
8959
9151
  var globalFetch = createDiagnostic({
8960
9152
  name: "globalFetch",
8961
9153
  code: 53,
8962
- description: "Warns when using the global fetch function instead of the Effect HTTP client",
9154
+ description: "Warns when using the global fetch function outside Effect generators instead of the Effect HTTP client",
8963
9155
  group: "effectNative",
8964
9156
  severity: "off",
8965
9157
  fixable: false,
8966
9158
  supportedEffect: ["v3", "v4"],
8967
- apply: fn("globalFetch.apply")(function* (sourceFile, report) {
8968
- const ts = yield* service(TypeScriptApi);
8969
- const typeChecker = yield* service(TypeCheckerApi);
8970
- const typeParser = yield* service(TypeParser);
8971
- const fetchSymbol = typeChecker.resolveName("fetch", void 0, ts.SymbolFlags.Value, false);
8972
- if (!fetchSymbol) return;
8973
- const effectVersion = typeParser.supportedEffect();
8974
- const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
8975
- const messageText = `Prefer using HttpClient from ${packageName} instead of the global 'fetch' function.`;
8976
- const nodeToVisit = [];
8977
- const appendNodeToVisit = (node) => {
8978
- nodeToVisit.push(node);
8979
- return void 0;
8980
- };
8981
- ts.forEachChild(sourceFile, appendNodeToVisit);
8982
- while (nodeToVisit.length > 0) {
8983
- const node = nodeToVisit.shift();
8984
- if (ts.isCallExpression(node)) {
8985
- const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
8986
- const resolvedSymbol = symbol3 && symbol3.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(symbol3) : symbol3;
8987
- if (resolvedSymbol === fetchSymbol) {
8988
- report({
8989
- location: node.expression,
8990
- messageText,
8991
- fixes: []
8992
- });
8993
- }
9159
+ apply: makeGlobalFetchApply(false)
9160
+ });
9161
+
9162
+ // src/diagnostics/globalRandomInEffect.ts
9163
+ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
9164
+ const ts = yield* service(TypeScriptApi);
9165
+ const typeChecker = yield* service(TypeCheckerApi);
9166
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9167
+ const typeParser = yield* service(TypeParser);
9168
+ const mathSymbol = typeChecker.resolveName("Math", void 0, ts.SymbolFlags.Value, false);
9169
+ if (!mathSymbol) return;
9170
+ const nodeToVisit = [];
9171
+ const appendNodeToVisit = (node) => {
9172
+ nodeToVisit.push(node);
9173
+ return void 0;
9174
+ };
9175
+ ts.forEachChild(sourceFile, appendNodeToVisit);
9176
+ while (nodeToVisit.length > 0) {
9177
+ const node = nodeToVisit.shift();
9178
+ ts.forEachChild(node, appendNodeToVisit);
9179
+ if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || ts.idText(node.expression.name) !== "random") continue;
9180
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
9181
+ if (!symbol3) continue;
9182
+ if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== mathSymbol) continue;
9183
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
9184
+ if (inEffect !== checkInEffect) continue;
9185
+ report({
9186
+ location: node,
9187
+ messageText: checkInEffect ? "Prefer using the Random service from Effect instead of Math.random() inside Effect generators." : "Prefer using the Random service from Effect instead of Math.random().",
9188
+ fixes: []
9189
+ });
9190
+ }
9191
+ });
9192
+ var globalRandomInEffect = createDiagnostic({
9193
+ name: "globalRandomInEffect",
9194
+ code: 57,
9195
+ description: "Warns when using Math.random() inside Effect generators instead of the Random service",
9196
+ group: "effectNative",
9197
+ severity: "off",
9198
+ fixable: false,
9199
+ supportedEffect: ["v3", "v4"],
9200
+ apply: makeGlobalRandomApply(true)
9201
+ });
9202
+
9203
+ // src/diagnostics/globalRandom.ts
9204
+ var globalRandom = createDiagnostic({
9205
+ name: "globalRandom",
9206
+ code: 61,
9207
+ description: "Warns when using Math.random() outside Effect generators instead of the Random service",
9208
+ group: "effectNative",
9209
+ severity: "off",
9210
+ fixable: false,
9211
+ supportedEffect: ["v3", "v4"],
9212
+ apply: makeGlobalRandomApply(false)
9213
+ });
9214
+
9215
+ // src/diagnostics/globalTimersInEffect.ts
9216
+ var timerAlternatives = {
9217
+ "setTimeout": {
9218
+ inEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout inside Effect generators.",
9219
+ outsideEffect: "Prefer using Effect.sleep or Schedule from Effect instead of setTimeout."
9220
+ },
9221
+ "setInterval": {
9222
+ inEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval inside Effect generators.",
9223
+ outsideEffect: "Prefer using Schedule or Effect.repeat from Effect instead of setInterval."
9224
+ }
9225
+ };
9226
+ var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
9227
+ const ts = yield* service(TypeScriptApi);
9228
+ const typeChecker = yield* service(TypeCheckerApi);
9229
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9230
+ const typeParser = yield* service(TypeParser);
9231
+ const globalSymbols = /* @__PURE__ */ new Map();
9232
+ for (const name of Object.keys(timerAlternatives)) {
9233
+ const symbol3 = typeChecker.resolveName(name, void 0, ts.SymbolFlags.Value, false);
9234
+ if (symbol3) globalSymbols.set(name, symbol3);
9235
+ }
9236
+ if (globalSymbols.size === 0) return;
9237
+ const nodeToVisit = [];
9238
+ const appendNodeToVisit = (node) => {
9239
+ nodeToVisit.push(node);
9240
+ return void 0;
9241
+ };
9242
+ ts.forEachChild(sourceFile, appendNodeToVisit);
9243
+ while (nodeToVisit.length > 0) {
9244
+ const node = nodeToVisit.shift();
9245
+ ts.forEachChild(node, appendNodeToVisit);
9246
+ if (!ts.isCallExpression(node)) continue;
9247
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
9248
+ if (!symbol3) continue;
9249
+ const resolvedSymbol = typeCheckerUtils.resolveToGlobalSymbol(symbol3);
9250
+ let messageText;
9251
+ for (const [name, symbol4] of globalSymbols) {
9252
+ if (resolvedSymbol === symbol4) {
9253
+ messageText = checkInEffect ? timerAlternatives[name].inEffect : timerAlternatives[name].outsideEffect;
9254
+ break;
8994
9255
  }
8995
- ts.forEachChild(node, appendNodeToVisit);
8996
9256
  }
8997
- })
9257
+ if (!messageText) continue;
9258
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
9259
+ if (inEffect !== checkInEffect) continue;
9260
+ report({ location: node, messageText, fixes: [] });
9261
+ }
9262
+ });
9263
+ var globalTimersInEffect = createDiagnostic({
9264
+ name: "globalTimersInEffect",
9265
+ code: 58,
9266
+ description: "Warns when using setTimeout/setInterval inside Effect generators instead of Effect.sleep/Schedule",
9267
+ group: "effectNative",
9268
+ severity: "off",
9269
+ fixable: false,
9270
+ supportedEffect: ["v3", "v4"],
9271
+ apply: makeGlobalTimersApply(true)
9272
+ });
9273
+
9274
+ // src/diagnostics/globalTimers.ts
9275
+ var globalTimers = createDiagnostic({
9276
+ name: "globalTimers",
9277
+ code: 62,
9278
+ description: "Warns when using setTimeout/setInterval outside Effect generators instead of Effect.sleep/Schedule",
9279
+ group: "effectNative",
9280
+ severity: "off",
9281
+ fixable: false,
9282
+ supportedEffect: ["v3", "v4"],
9283
+ apply: makeGlobalTimersApply(false)
8998
9284
  });
8999
9285
 
9000
9286
  // src/diagnostics/importFromBarrel.ts
@@ -10059,8 +10345,8 @@ var missingReturnYieldStar = createDiagnostic({
10059
10345
  if (!type) continue;
10060
10346
  const maybeEffect = yield* option(typeParser.effectYieldableType(type, unwrapped.expression));
10061
10347
  if (!(isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never)) continue;
10062
- const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
10063
- if (!effectGen || scopeNode && scopeNode !== effectGen.generatorFunction) continue;
10348
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
10349
+ if (!inEffect) continue;
10064
10350
  const fix = [{
10065
10351
  fixName: "missingReturnYieldStar_fix",
10066
10352
  description: "Add return statement",
@@ -11454,11 +11740,8 @@ var preferSchemaOverJson = createDiagnostic({
11454
11740
  });
11455
11741
  const jsonMethodInEffectGen = fn("preferSchemaOverJson.jsonMethodInEffectGen")(
11456
11742
  function* (jsonCall) {
11457
- const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(jsonCall);
11458
- if (!effectGen || effectGen.body.statements.length === 0) {
11459
- return yield* TypeParserIssue.issue;
11460
- }
11461
- if (scopeNode && scopeNode !== effectGen.generatorFunction) {
11743
+ const { inEffect } = yield* typeParser.findEnclosingScopes(jsonCall);
11744
+ if (!inEffect) {
11462
11745
  return yield* TypeParserIssue.issue;
11463
11746
  }
11464
11747
  return jsonCall;
@@ -11874,9 +12157,8 @@ var schemaSyncInEffect = createDiagnostic({
11874
12157
  option
11875
12158
  );
11876
12159
  if (isNone2(isSchemaSyncCall)) continue;
11877
- const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
11878
- if (!effectGen || effectGen.body.statements.length === 0) continue;
11879
- if (scopeNode && scopeNode !== effectGen.generatorFunction) continue;
12160
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
12161
+ if (!inEffect) continue;
11880
12162
  const nodeText = sourceFile.text.substring(
11881
12163
  ts.getTokenPosOfNode(node.expression, sourceFile),
11882
12164
  node.expression.end
@@ -12718,6 +13000,7 @@ var diagnostics = [
12718
13000
  unnecessaryPipe,
12719
13001
  genericEffectServices,
12720
13002
  globalFetch,
13003
+ globalFetchInEffect,
12721
13004
  returnEffectInGen,
12722
13005
  tryCatchInEffectGen,
12723
13006
  importFromBarrel,
@@ -12749,7 +13032,15 @@ var diagnostics = [
12749
13032
  preferSchemaOverJson,
12750
13033
  extendsNativeError,
12751
13034
  serviceNotAsClass,
12752
- nodeBuiltinImport
13035
+ nodeBuiltinImport,
13036
+ globalDate,
13037
+ globalDateInEffect,
13038
+ globalConsole,
13039
+ globalConsoleInEffect,
13040
+ globalRandom,
13041
+ globalRandomInEffect,
13042
+ globalTimers,
13043
+ globalTimersInEffect
12753
13044
  ];
12754
13045
 
12755
13046
  // src/completions/effectDiagnosticsComment.ts