react-native-nitro-logger 0.1.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.
Files changed (205) hide show
  1. package/LICENSE +20 -0
  2. package/NitroLogger.podspec +29 -0
  3. package/README.md +214 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +124 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  8. package/android/src/main/java/com/margelo/nitro/nitrologger/AndroidPlatformIo.kt +100 -0
  9. package/android/src/main/java/com/margelo/nitro/nitrologger/HybridFileSink.kt +292 -0
  10. package/android/src/main/java/com/margelo/nitro/nitrologger/HybridNativeConsoleSink.kt +23 -0
  11. package/android/src/main/java/com/margelo/nitro/nitrologger/LogFileWriter.kt +1328 -0
  12. package/android/src/main/java/com/margelo/nitro/nitrologger/LogRotationPolicy.kt +186 -0
  13. package/android/src/main/java/com/margelo/nitro/nitrologger/LogSecureFile.kt +80 -0
  14. package/android/src/main/java/com/margelo/nitro/nitrologger/LogWriterRegistry.kt +420 -0
  15. package/android/src/main/java/com/margelo/nitro/nitrologger/NativeConsoleWriter.kt +237 -0
  16. package/android/src/main/java/com/margelo/nitro/nitrologger/NitroLoggerPackage.kt +22 -0
  17. package/android/src/main/java/com/margelo/nitro/nitrologger/PlatformIo.kt +165 -0
  18. package/docs/PARITY.md +330 -0
  19. package/docs/PRIVACY.md +341 -0
  20. package/eslint-plugin/README.md +238 -0
  21. package/eslint-plugin/index.js +62 -0
  22. package/eslint-plugin/rules/literal-subsystem.js +102 -0
  23. package/eslint-plugin/rules/no-computed-metadata-key.js +174 -0
  24. package/eslint-plugin/rules/no-derived-correlation.js +171 -0
  25. package/eslint-plugin/rules/no-dynamic-message.js +60 -0
  26. package/eslint-plugin/shared.js +1948 -0
  27. package/ios/Gzip.swift +203 -0
  28. package/ios/HybridFileSink.swift +291 -0
  29. package/ios/HybridNativeConsoleSink.swift +20 -0
  30. package/ios/LogFileWriter.swift +1280 -0
  31. package/ios/LogSecureFile.swift +296 -0
  32. package/ios/LogWriterRegistry.swift +444 -0
  33. package/ios/NativeConsoleWriter.swift +180 -0
  34. package/lib/module/Logger.js +381 -0
  35. package/lib/module/Logger.js.map +1 -0
  36. package/lib/module/ScopedLogger.js +70 -0
  37. package/lib/module/ScopedLogger.js.map +1 -0
  38. package/lib/module/config.js +23 -0
  39. package/lib/module/config.js.map +1 -0
  40. package/lib/module/destinations/Batcher.js +647 -0
  41. package/lib/module/destinations/Batcher.js.map +1 -0
  42. package/lib/module/destinations/ConsoleDestination.js +51 -0
  43. package/lib/module/destinations/ConsoleDestination.js.map +1 -0
  44. package/lib/module/destinations/FileDestination.js +360 -0
  45. package/lib/module/destinations/FileDestination.js.map +1 -0
  46. package/lib/module/destinations/NativeConsoleDestination.js +170 -0
  47. package/lib/module/destinations/NativeConsoleDestination.js.map +1 -0
  48. package/lib/module/destinations/types.js +4 -0
  49. package/lib/module/destinations/types.js.map +1 -0
  50. package/lib/module/formatters/DefaultFormatter.js +136 -0
  51. package/lib/module/formatters/DefaultFormatter.js.map +1 -0
  52. package/lib/module/formatters/JsonLinesFormatter.js +162 -0
  53. package/lib/module/formatters/JsonLinesFormatter.js.map +1 -0
  54. package/lib/module/formatters/timestamp.js +15 -0
  55. package/lib/module/formatters/timestamp.js.map +1 -0
  56. package/lib/module/formatters/types.js +4 -0
  57. package/lib/module/formatters/types.js.map +1 -0
  58. package/lib/module/index.js +31 -0
  59. package/lib/module/index.js.map +1 -0
  60. package/lib/module/integrations/appState.js +81 -0
  61. package/lib/module/integrations/appState.js.map +1 -0
  62. package/lib/module/integrations/errorHandler.js +166 -0
  63. package/lib/module/integrations/errorHandler.js.map +1 -0
  64. package/lib/module/integrations/sanitizeError.js +238 -0
  65. package/lib/module/integrations/sanitizeError.js.map +1 -0
  66. package/lib/module/levels.js +35 -0
  67. package/lib/module/levels.js.map +1 -0
  68. package/lib/module/metadata.js +52 -0
  69. package/lib/module/metadata.js.map +1 -0
  70. package/lib/module/package.json +1 -0
  71. package/lib/module/privacy.js +349 -0
  72. package/lib/module/privacy.js.map +1 -0
  73. package/lib/module/specs/FileSink.nitro.js +4 -0
  74. package/lib/module/specs/FileSink.nitro.js.map +1 -0
  75. package/lib/module/specs/NativeConsoleSink.nitro.js +4 -0
  76. package/lib/module/specs/NativeConsoleSink.nitro.js.map +1 -0
  77. package/lib/module/types.js +4 -0
  78. package/lib/module/types.js.map +1 -0
  79. package/lib/module/utf8.js +42 -0
  80. package/lib/module/utf8.js.map +1 -0
  81. package/lib/typescript/package.json +1 -0
  82. package/lib/typescript/src/Logger.d.ts +122 -0
  83. package/lib/typescript/src/Logger.d.ts.map +1 -0
  84. package/lib/typescript/src/ScopedLogger.d.ts +36 -0
  85. package/lib/typescript/src/ScopedLogger.d.ts.map +1 -0
  86. package/lib/typescript/src/config.d.ts +12 -0
  87. package/lib/typescript/src/config.d.ts.map +1 -0
  88. package/lib/typescript/src/destinations/Batcher.d.ts +244 -0
  89. package/lib/typescript/src/destinations/Batcher.d.ts.map +1 -0
  90. package/lib/typescript/src/destinations/ConsoleDestination.d.ts +27 -0
  91. package/lib/typescript/src/destinations/ConsoleDestination.d.ts.map +1 -0
  92. package/lib/typescript/src/destinations/FileDestination.d.ts +200 -0
  93. package/lib/typescript/src/destinations/FileDestination.d.ts.map +1 -0
  94. package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts +86 -0
  95. package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts.map +1 -0
  96. package/lib/typescript/src/destinations/types.d.ts +19 -0
  97. package/lib/typescript/src/destinations/types.d.ts.map +1 -0
  98. package/lib/typescript/src/formatters/DefaultFormatter.d.ts +22 -0
  99. package/lib/typescript/src/formatters/DefaultFormatter.d.ts.map +1 -0
  100. package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts +73 -0
  101. package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts.map +1 -0
  102. package/lib/typescript/src/formatters/timestamp.d.ts +6 -0
  103. package/lib/typescript/src/formatters/timestamp.d.ts.map +1 -0
  104. package/lib/typescript/src/formatters/types.d.ts +27 -0
  105. package/lib/typescript/src/formatters/types.d.ts.map +1 -0
  106. package/lib/typescript/src/index.d.ts +34 -0
  107. package/lib/typescript/src/index.d.ts.map +1 -0
  108. package/lib/typescript/src/integrations/appState.d.ts +33 -0
  109. package/lib/typescript/src/integrations/appState.d.ts.map +1 -0
  110. package/lib/typescript/src/integrations/errorHandler.d.ts +55 -0
  111. package/lib/typescript/src/integrations/errorHandler.d.ts.map +1 -0
  112. package/lib/typescript/src/integrations/sanitizeError.d.ts +89 -0
  113. package/lib/typescript/src/integrations/sanitizeError.d.ts.map +1 -0
  114. package/lib/typescript/src/levels.d.ts +9 -0
  115. package/lib/typescript/src/levels.d.ts.map +1 -0
  116. package/lib/typescript/src/metadata.d.ts +23 -0
  117. package/lib/typescript/src/metadata.d.ts.map +1 -0
  118. package/lib/typescript/src/privacy.d.ts +103 -0
  119. package/lib/typescript/src/privacy.d.ts.map +1 -0
  120. package/lib/typescript/src/specs/FileSink.nitro.d.ts +131 -0
  121. package/lib/typescript/src/specs/FileSink.nitro.d.ts.map +1 -0
  122. package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts +21 -0
  123. package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts.map +1 -0
  124. package/lib/typescript/src/types.d.ts +37 -0
  125. package/lib/typescript/src/types.d.ts.map +1 -0
  126. package/lib/typescript/src/utf8.d.ts +15 -0
  127. package/lib/typescript/src/utf8.d.ts.map +1 -0
  128. package/nitro.json +33 -0
  129. package/nitrogen/generated/android/c++/JAppendResult.hpp +79 -0
  130. package/nitrogen/generated/android/c++/JClearOutcome.hpp +88 -0
  131. package/nitrogen/generated/android/c++/JFlushOutcome.hpp +81 -0
  132. package/nitrogen/generated/android/c++/JHybridFileSinkSpec.cpp +120 -0
  133. package/nitrogen/generated/android/c++/JHybridFileSinkSpec.hpp +69 -0
  134. package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.cpp +71 -0
  135. package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.hpp +64 -0
  136. package/nitrogen/generated/android/c++/JRejectReason.hpp +64 -0
  137. package/nitrogen/generated/android/c++/JRotationConfig.hpp +77 -0
  138. package/nitrogen/generated/android/c++/JSinkStatus.hpp +69 -0
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/AppendResult.kt +76 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/ClearOutcome.kt +66 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/FlushOutcome.kt +81 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridFileSinkSpec.kt +80 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridNativeConsoleSinkSpec.kt +58 -0
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RejectReason.kt +25 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RotationConfig.kt +76 -0
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/SinkStatus.kt +66 -0
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/nitrologgerOnLoad.kt +35 -0
  148. package/nitrogen/generated/android/nitrologger+autolinking.cmake +83 -0
  149. package/nitrogen/generated/android/nitrologger+autolinking.gradle +27 -0
  150. package/nitrogen/generated/android/nitrologgerOnLoad.cpp +70 -0
  151. package/nitrogen/generated/android/nitrologgerOnLoad.hpp +34 -0
  152. package/nitrogen/generated/ios/NitroLogger+autolinking.rb +62 -0
  153. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.cpp +50 -0
  154. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.hpp +216 -0
  155. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Umbrella.hpp +69 -0
  156. package/nitrogen/generated/ios/NitroLoggerAutolinking.mm +41 -0
  157. package/nitrogen/generated/ios/NitroLoggerAutolinking.swift +38 -0
  158. package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.cpp +11 -0
  159. package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.hpp +150 -0
  160. package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.cpp +11 -0
  161. package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.hpp +87 -0
  162. package/nitrogen/generated/ios/swift/AppendResult.swift +60 -0
  163. package/nitrogen/generated/ios/swift/ClearOutcome.swift +50 -0
  164. package/nitrogen/generated/ios/swift/FlushOutcome.swift +59 -0
  165. package/nitrogen/generated/ios/swift/HybridFileSinkSpec.swift +61 -0
  166. package/nitrogen/generated/ios/swift/HybridFileSinkSpec_cxx.swift +227 -0
  167. package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec.swift +56 -0
  168. package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec_cxx.swift +148 -0
  169. package/nitrogen/generated/ios/swift/RejectReason.swift +48 -0
  170. package/nitrogen/generated/ios/swift/RotationConfig.swift +93 -0
  171. package/nitrogen/generated/ios/swift/SinkStatus.swift +44 -0
  172. package/nitrogen/generated/shared/c++/AppendResult.hpp +105 -0
  173. package/nitrogen/generated/shared/c++/ClearOutcome.hpp +96 -0
  174. package/nitrogen/generated/shared/c++/FlushOutcome.hpp +107 -0
  175. package/nitrogen/generated/shared/c++/HybridFileSinkSpec.cpp +28 -0
  176. package/nitrogen/generated/shared/c++/HybridFileSinkSpec.hpp +84 -0
  177. package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.cpp +22 -0
  178. package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.hpp +64 -0
  179. package/nitrogen/generated/shared/c++/RejectReason.hpp +84 -0
  180. package/nitrogen/generated/shared/c++/RotationConfig.hpp +103 -0
  181. package/nitrogen/generated/shared/c++/SinkStatus.hpp +95 -0
  182. package/package.json +151 -0
  183. package/src/Logger.ts +417 -0
  184. package/src/ScopedLogger.ts +94 -0
  185. package/src/config.ts +25 -0
  186. package/src/destinations/Batcher.ts +805 -0
  187. package/src/destinations/ConsoleDestination.ts +60 -0
  188. package/src/destinations/FileDestination.ts +473 -0
  189. package/src/destinations/NativeConsoleDestination.ts +220 -0
  190. package/src/destinations/types.ts +19 -0
  191. package/src/formatters/DefaultFormatter.ts +150 -0
  192. package/src/formatters/JsonLinesFormatter.ts +195 -0
  193. package/src/formatters/timestamp.ts +12 -0
  194. package/src/formatters/types.ts +29 -0
  195. package/src/index.tsx +106 -0
  196. package/src/integrations/appState.ts +111 -0
  197. package/src/integrations/errorHandler.ts +223 -0
  198. package/src/integrations/sanitizeError.ts +287 -0
  199. package/src/levels.ts +35 -0
  200. package/src/metadata.ts +52 -0
  201. package/src/privacy.ts +389 -0
  202. package/src/specs/FileSink.nitro.ts +144 -0
  203. package/src/specs/NativeConsoleSink.nitro.ts +21 -0
  204. package/src/types.ts +45 -0
  205. package/src/utf8.ts +39 -0
@@ -0,0 +1,171 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ correlationArguments,
5
+ describeLogCall,
6
+ describeScopedCall,
7
+ isOmitted,
8
+ isTrustedLogger,
9
+ resolveVariable,
10
+ singleDef,
11
+ staticPropertyName,
12
+ unwrap,
13
+ } = require('../shared');
14
+
15
+ /**
16
+ * Correlation IDs are public by contract — they appear in every line of a
17
+ * scope — so they must be opaque and freshly random.
18
+ *
19
+ * The tempting shortcut is to reuse an identifier you already have: a
20
+ * patient ID, an MRN, a booking reference. That turns every log line in the
21
+ * scope into a re-identification key, and hashing does not fix it — a hash
22
+ * of a small identifier space is trivially reversible. This rule requires
23
+ * the ID to come from the logger's own `newCorrelationId()`.
24
+ *
25
+ * Provenance is checked, not spelling. A local
26
+ * `function newCorrelationId() { return patient.mrn }` produces exactly the
27
+ * leak the rule exists to prevent, so the generator has to be traceable to an
28
+ * import of the package that actually ships it.
29
+ */
30
+
31
+ /**
32
+ * Is this a call to the logger's `newCorrelationId`, and only that?
33
+ *
34
+ * Provenance must be exact here, not merely plausible. Everywhere else an
35
+ * ambiguous receiver widens what gets *checked*, which is safe; here it would
36
+ * widen what gets *trusted*, so `function f(logger) { Log.scoped(
37
+ * logger.newCorrelationId()) }` would launder any object's method into an
38
+ * approved ID generator. Only a receiver proven to be the Logger counts.
39
+ */
40
+ function isCorrelationIdCall(context, node) {
41
+ const call = unwrap(node);
42
+ if (!call || call.type !== 'CallExpression') return false;
43
+ const callee = unwrap(call.callee);
44
+ if (!callee) return false;
45
+
46
+ // `Log.newCorrelationId()` — receiver must BE the Logger, not resemble it.
47
+ if (callee.type === 'MemberExpression') {
48
+ return (
49
+ staticPropertyName(context, callee) === 'newCorrelationId' &&
50
+ isTrustedLogger(context, callee.object)
51
+ );
52
+ }
53
+
54
+ if (callee.type !== 'Identifier' || callee.name !== 'newCorrelationId') {
55
+ return false;
56
+ }
57
+
58
+ // A bare call is trustworthy only when destructured off the Logger. The
59
+ // package exposes no standalone `newCorrelationId`, so accepting an import
60
+ // of that name would trust `import { newCorrelationId } from
61
+ // './phi-helpers'` — a function that can return anything at all.
62
+ const def = singleDef(resolveVariable(context, callee));
63
+ if (!def || def.type !== 'Variable') return false;
64
+ if (def.node.id.type !== 'ObjectPattern') return false;
65
+ // Which property it was destructured FROM is the whole point:
66
+ // `const { patientId: newCorrelationId } = Log` renames PHI into the
67
+ // approved spelling.
68
+ const property = def.node.id.properties.find((p) => {
69
+ if (p.type !== 'Property') return false;
70
+ const target =
71
+ p.value.type === 'AssignmentPattern' ? p.value.left : p.value;
72
+ return target === def.name;
73
+ });
74
+ if (
75
+ !property ||
76
+ property.computed ||
77
+ property.key.type !== 'Identifier' ||
78
+ property.key.name !== 'newCorrelationId'
79
+ ) {
80
+ return false;
81
+ }
82
+ return isTrustedLogger(context, def.node.init);
83
+ }
84
+
85
+ module.exports = {
86
+ meta: {
87
+ type: 'problem',
88
+ docs: {
89
+ description:
90
+ 'require correlation IDs to come from newCorrelationId() rather than existing identifiers',
91
+ },
92
+ schema: [
93
+ {
94
+ type: 'object',
95
+ properties: {
96
+ loggerNames: { type: 'array', items: { type: 'string' } },
97
+ loggerModules: { type: 'array', items: { type: 'string' } },
98
+ singletonName: { type: 'string' },
99
+ },
100
+ additionalProperties: false,
101
+ },
102
+ ],
103
+ messages: {
104
+ derived:
105
+ 'Correlation IDs must come from newCorrelationId(). Deriving one from a record, patient, or session identifier makes every line in the scope a re-identification key — and hashing a small identifier space does not anonymize it.',
106
+ unanalyzable:
107
+ 'This correlation ID cannot be traced to newCorrelationId(). Pass the call directly, or a `const` initialized from it.',
108
+ },
109
+ },
110
+
111
+ create(context) {
112
+ function check(node) {
113
+ if (!node) return;
114
+ // `Log.scoped(undefined)` auto-generates, exactly like `Log.scoped()`.
115
+ if (isOmitted(context, node)) return;
116
+ if (isCorrelationIdCall(context, node)) return;
117
+
118
+ // Follow a single-definition const to its initializer, so the common
119
+ // `const id = Log.newCorrelationId()` stays legal.
120
+ const current = unwrap(node);
121
+ if (current && current.type === 'Identifier') {
122
+ const variable = resolveVariable(context, current);
123
+ const def = singleDef(variable);
124
+ if (
125
+ def &&
126
+ def.type === 'Variable' &&
127
+ def.parent?.kind === 'const' &&
128
+ isCorrelationIdCall(context, def.node.init)
129
+ ) {
130
+ return;
131
+ }
132
+ }
133
+
134
+ context.report({ node, messageId: 'derived' });
135
+ }
136
+
137
+ return {
138
+ CallExpression(node) {
139
+ const scoped = describeScopedCall(context, node);
140
+ if (scoped) {
141
+ if (scoped.spreadArgs) {
142
+ // `Log.scoped(...args)` — the correlation position is unknowable,
143
+ // and whatever lands there tags every line of the scope.
144
+ context.report({ node, messageId: 'unanalyzable' });
145
+ return;
146
+ }
147
+ // `scoped()` with no argument auto-generates — that is the
148
+ // encouraged form and needs no check.
149
+ if (scoped.args.length > 0) check(scoped.args[0]);
150
+ return;
151
+ }
152
+
153
+ const call = describeLogCall(context, node);
154
+ if (!call) return;
155
+ if (call.spreadArgs && (call.method === 'log' || call.opaqueMethod)) {
156
+ // `Log.log(...['m', { correlation: patientId }])` — the options
157
+ // object, and the correlation inside it, are out of reach.
158
+ context.report({ node, messageId: 'unanalyzable' });
159
+ return;
160
+ }
161
+ for (const result of correlationArguments(context, call)) {
162
+ if (result.kind === 'unanalyzable') {
163
+ context.report({ node: result.node, messageId: 'unanalyzable' });
164
+ } else {
165
+ check(result.node);
166
+ }
167
+ }
168
+ },
169
+ };
170
+ },
171
+ };
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ const { describeLogCall, isStaticMessage } = require('../shared');
4
+
5
+ /**
6
+ * The message is public by contract: the runtime cannot redact it, because
7
+ * it cannot tell a template's constant parts from its interpolated ones. So
8
+ * it has to be static at build time.
9
+ *
10
+ * `Log.info(\`patient ${id} admitted\`)` is the single most likely way PHI
11
+ * reaches a log file, and no amount of runtime validation catches it — by
12
+ * the time the logger sees the string, the interpolation already happened.
13
+ */
14
+ module.exports = {
15
+ meta: {
16
+ type: 'problem',
17
+ docs: {
18
+ description:
19
+ 'require log messages to be static strings, so interpolated data cannot reach a log line',
20
+ },
21
+ schema: [
22
+ {
23
+ type: 'object',
24
+ properties: {
25
+ loggerNames: { type: 'array', items: { type: 'string' } },
26
+ loggerModules: { type: 'array', items: { type: 'string' } },
27
+ singletonName: { type: 'string' },
28
+ },
29
+ additionalProperties: false,
30
+ },
31
+ ],
32
+ messages: {
33
+ dynamic:
34
+ 'Log messages must be a string literal or an approved constant. Interpolated or computed text cannot be redacted at runtime — put the varying part in metadata, where the privacy layer can see it.',
35
+ unanalyzable:
36
+ 'This call passes its arguments indirectly — a spread, an .apply(), or a partially applied .bind() — so the message position cannot be checked. Call the logging method directly.',
37
+ },
38
+ },
39
+
40
+ create(context) {
41
+ return {
42
+ CallExpression(node) {
43
+ const call = describeLogCall(context, node);
44
+ if (!call) return;
45
+
46
+ if (call.spreadArgs) {
47
+ context.report({ node, messageId: 'unanalyzable' });
48
+ return;
49
+ }
50
+ // A call with no arguments is someone else's error to report.
51
+ if (call.args.length === 0) return;
52
+
53
+ const message = call.args[0];
54
+ if (!isStaticMessage(context, message)) {
55
+ context.report({ node: message, messageId: 'dynamic' });
56
+ }
57
+ },
58
+ };
59
+ },
60
+ };