@futdevpro/dynamo-eslint 1.14.25 → 1.14.27
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/.github/workflows/main.yml +5 -0
- package/build/configs/base.js +1 -0
- package/build/configs/base.js.map +1 -1
- package/build/plugin/index.d.ts +2 -0
- package/build/plugin/index.d.ts.map +1 -1
- package/build/plugin/index.js +3 -0
- package/build/plugin/index.js.map +1 -1
- package/build/plugin/rules/no-getter-logic.d.ts +4 -0
- package/build/plugin/rules/no-getter-logic.d.ts.map +1 -0
- package/build/plugin/rules/no-getter-logic.js +176 -0
- package/build/plugin/rules/no-getter-logic.js.map +1 -0
- package/build/plugin/rules/no-getter-logic.spec.d.ts +2 -0
- package/build/plugin/rules/no-getter-logic.spec.d.ts.map +1 -0
- package/build/plugin/rules/no-getter-logic.spec.js +461 -0
- package/build/plugin/rules/no-getter-logic.spec.js.map +1 -0
- package/build/plugin/rules/require-jsdoc-description.d.ts.map +1 -1
- package/build/plugin/rules/require-jsdoc-description.js +53 -10
- package/build/plugin/rules/require-jsdoc-description.js.map +1 -1
- package/build/plugin/rules/require-jsdoc-description.spec.js +94 -0
- package/build/plugin/rules/require-jsdoc-description.spec.js.map +1 -1
- package/futdevpro-dynamo-eslint-1.14.27.tgz +0 -0
- package/package.json +1 -1
- package/src/configs/base.ts +1 -0
- package/src/plugin/index.ts +3 -0
- package/src/plugin/rules/no-getter-logic.spec.ts +520 -0
- package/src/plugin/rules/no-getter-logic.ts +201 -0
- package/src/plugin/rules/require-jsdoc-description.spec.ts +111 -0
- package/src/plugin/rules/require-jsdoc-description.ts +61 -12
- package/futdevpro-dynamo-eslint-1.14.25.tgz +0 -0
|
@@ -539,4 +539,115 @@ describe('| require-jsdoc-description', () => {
|
|
|
539
539
|
|
|
540
540
|
rule.FunctionDeclaration(mockNode);
|
|
541
541
|
});
|
|
542
|
+
|
|
543
|
+
it('| should handle abstract class with multiline JSDoc', () => {
|
|
544
|
+
const mockContext = {
|
|
545
|
+
report: (options: any) => {
|
|
546
|
+
fail('Should not report when abstract class has multiline JSDoc');
|
|
547
|
+
},
|
|
548
|
+
options: [{ scope: 'public' }],
|
|
549
|
+
sourceCode: {
|
|
550
|
+
getCommentsBefore: () => [{
|
|
551
|
+
type: 'Block',
|
|
552
|
+
value: '* Abstract data service osztály a user műveletek kezeléséhez.\n* Kezeli a login, register, validation és egyéb user-rel kapcsolatos műveleteket.',
|
|
553
|
+
loc: { end: { line: 3 } },
|
|
554
|
+
}],
|
|
555
|
+
},
|
|
556
|
+
} as any;
|
|
557
|
+
|
|
558
|
+
const rule = requireJSDocRule.create(mockContext);
|
|
559
|
+
|
|
560
|
+
const mockNode = {
|
|
561
|
+
type: 'ClassDeclaration',
|
|
562
|
+
id: { name: 'FDPNTS_User_DataService' },
|
|
563
|
+
loc: { start: { line: 4 } },
|
|
564
|
+
parent: {
|
|
565
|
+
type: 'ExportNamedDeclaration',
|
|
566
|
+
},
|
|
567
|
+
} as any;
|
|
568
|
+
|
|
569
|
+
rule.ClassDeclaration(mockNode);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('| should handle multiline JSDoc with empty lines', () => {
|
|
573
|
+
const mockContext = {
|
|
574
|
+
report: (options: any) => {
|
|
575
|
+
fail('Should not report when JSDoc has multiline description with empty lines');
|
|
576
|
+
},
|
|
577
|
+
options: [{ scope: 'public' }],
|
|
578
|
+
sourceCode: {
|
|
579
|
+
getCommentsBefore: () => [{
|
|
580
|
+
type: 'Block',
|
|
581
|
+
value: '* This is a multiline description\n*\n* with empty lines in between\n* that should still be valid',
|
|
582
|
+
loc: { end: { line: 4 } },
|
|
583
|
+
}],
|
|
584
|
+
},
|
|
585
|
+
} as any;
|
|
586
|
+
|
|
587
|
+
const rule = requireJSDocRule.create(mockContext);
|
|
588
|
+
|
|
589
|
+
const mockNode = {
|
|
590
|
+
type: 'FunctionDeclaration',
|
|
591
|
+
id: { name: 'testFunction' },
|
|
592
|
+
loc: { start: { line: 5 } },
|
|
593
|
+
} as any;
|
|
594
|
+
|
|
595
|
+
rule.FunctionDeclaration(mockNode);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it('| should handle multiline JSDoc followed by @tags', () => {
|
|
599
|
+
const mockContext = {
|
|
600
|
+
report: (options: any) => {
|
|
601
|
+
fail('Should not report when JSDoc has description before @tags');
|
|
602
|
+
},
|
|
603
|
+
options: [{ scope: 'public' }],
|
|
604
|
+
sourceCode: {
|
|
605
|
+
getCommentsBefore: () => [{
|
|
606
|
+
type: 'Block',
|
|
607
|
+
value: '* This is a description\n* that spans multiple lines\n* @param {string} name The name parameter',
|
|
608
|
+
loc: { end: { line: 2 } },
|
|
609
|
+
}],
|
|
610
|
+
},
|
|
611
|
+
} as any;
|
|
612
|
+
|
|
613
|
+
const rule = requireJSDocRule.create(mockContext);
|
|
614
|
+
|
|
615
|
+
const mockNode = {
|
|
616
|
+
type: 'FunctionDeclaration',
|
|
617
|
+
id: { name: 'testFunction' },
|
|
618
|
+
loc: { start: { line: 3 } },
|
|
619
|
+
} as any;
|
|
620
|
+
|
|
621
|
+
rule.FunctionDeclaration(mockNode);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
it('| should report when abstract class is missing JSDoc', () => {
|
|
625
|
+
let reportCalled = false;
|
|
626
|
+
const mockContext = {
|
|
627
|
+
report: (options: any) => {
|
|
628
|
+
reportCalled = true;
|
|
629
|
+
expect(options.data.type).toBe('Class');
|
|
630
|
+
expect(options.data.name).toBe('AbstractClass');
|
|
631
|
+
},
|
|
632
|
+
options: [{ scope: 'public' }],
|
|
633
|
+
sourceCode: {
|
|
634
|
+
getCommentsBefore: () => [],
|
|
635
|
+
},
|
|
636
|
+
} as any;
|
|
637
|
+
|
|
638
|
+
const rule = requireJSDocRule.create(mockContext);
|
|
639
|
+
|
|
640
|
+
const mockNode = {
|
|
641
|
+
type: 'ClassDeclaration',
|
|
642
|
+
id: { name: 'AbstractClass' },
|
|
643
|
+
loc: { start: { line: 1 } },
|
|
644
|
+
parent: {
|
|
645
|
+
type: 'ExportNamedDeclaration',
|
|
646
|
+
},
|
|
647
|
+
} as any;
|
|
648
|
+
|
|
649
|
+
rule.ClassDeclaration(mockNode);
|
|
650
|
+
|
|
651
|
+
expect(reportCalled).toBe(true);
|
|
652
|
+
});
|
|
542
653
|
});
|
|
@@ -125,6 +125,7 @@ const rule: Rule.RuleModule = {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// JSDoc should be on the line immediately before (no blank lines)
|
|
128
|
+
// For multi-line comments, check if the last line of the comment is immediately before the node
|
|
128
129
|
return commentEnd === nodeStart - 1;
|
|
129
130
|
} catch (error) {
|
|
130
131
|
console.error('[require-jsdoc-description] Error in isJSDocOnPreviousLine:', error);
|
|
@@ -142,24 +143,27 @@ const rule: Rule.RuleModule = {
|
|
|
142
143
|
return '';
|
|
143
144
|
}
|
|
144
145
|
|
|
146
|
+
// The comment.value contains the text between /** and */
|
|
147
|
+
// It may start with * and include newlines with * at the beginning of each line
|
|
145
148
|
const lines = jsdocComment.value.split('\n');
|
|
146
149
|
let description = '';
|
|
147
150
|
|
|
148
151
|
for (const line of lines) {
|
|
149
|
-
// Remove leading
|
|
150
|
-
|
|
152
|
+
// Remove leading whitespace and * character (JSDoc format: " * text" or "* text")
|
|
153
|
+
// Handle both formats: " * text" and "* text" and " *text"
|
|
154
|
+
const cleanLine = line.replace(/^\s*\*+\s?/, '').trim();
|
|
151
155
|
|
|
152
|
-
// Skip empty lines
|
|
156
|
+
// Skip empty lines (after removing * and whitespace)
|
|
153
157
|
if (!cleanLine) {
|
|
154
158
|
continue;
|
|
155
159
|
}
|
|
156
160
|
|
|
157
|
-
// Stop at @tags
|
|
161
|
+
// Stop at @tags (JSDoc tags like @param, @returns, etc.)
|
|
158
162
|
if (cleanLine.startsWith('@')) {
|
|
159
163
|
break;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
// Add to description
|
|
166
|
+
// Add to description with space separator
|
|
163
167
|
if (description) {
|
|
164
168
|
description += ' ';
|
|
165
169
|
}
|
|
@@ -182,10 +186,18 @@ const rule: Rule.RuleModule = {
|
|
|
182
186
|
const comments = sourceCode.getCommentsBefore(node);
|
|
183
187
|
|
|
184
188
|
// Find JSDoc comment (/** ... */)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
comment.
|
|
188
|
-
|
|
189
|
+
// JSDoc comments are Block comments where the value (content between /** and */) starts with *
|
|
190
|
+
const jsdocComment = comments.find((comment: any) => {
|
|
191
|
+
if (comment.type !== 'Block') {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const value = comment.value || '';
|
|
196
|
+
|
|
197
|
+
// JSDoc comment value should start with * (the first character after /**)
|
|
198
|
+
// Handle cases where there might be whitespace before the *
|
|
199
|
+
return value.trim().startsWith('*');
|
|
200
|
+
});
|
|
189
201
|
|
|
190
202
|
if (!jsdocComment) {
|
|
191
203
|
return { hasJSDoc: false, isValid: false, isOnPreviousLine: false };
|
|
@@ -228,6 +240,39 @@ const rule: Rule.RuleModule = {
|
|
|
228
240
|
}
|
|
229
241
|
}
|
|
230
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Get node name location for error reporting
|
|
245
|
+
*/
|
|
246
|
+
function getNodeNameLoc(node: any): { start: { line: number; column: number }; end: { line: number; column: number } } | null {
|
|
247
|
+
try {
|
|
248
|
+
// For MethodDefinition, use key.loc
|
|
249
|
+
if (node.key && node.key.loc) {
|
|
250
|
+
return node.key.loc;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// For declarations with id (FunctionDeclaration, ClassDeclaration, etc.)
|
|
254
|
+
if (node.id && node.id.loc) {
|
|
255
|
+
return node.id.loc;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// For VariableDeclarator
|
|
259
|
+
if (node.id && node.id.loc) {
|
|
260
|
+
return node.id.loc;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Fallback to node location if name location not found
|
|
264
|
+
if (node.loc) {
|
|
265
|
+
return node.loc;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return null;
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.error('[require-jsdoc-description] Error in getNodeNameLoc:', error);
|
|
271
|
+
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
231
276
|
/**
|
|
232
277
|
* Get node type for error messages
|
|
233
278
|
*/
|
|
@@ -299,22 +344,26 @@ const rule: Rule.RuleModule = {
|
|
|
299
344
|
try {
|
|
300
345
|
const name = getNodeName(node);
|
|
301
346
|
const type = getNodeType(node);
|
|
347
|
+
const nameLoc = getNodeNameLoc(node);
|
|
348
|
+
|
|
349
|
+
// Fallback to node location if name location not found
|
|
350
|
+
const reportLoc = nameLoc || node.loc;
|
|
302
351
|
|
|
303
352
|
if (!jsdocResult.hasJSDoc) {
|
|
304
353
|
context.report({
|
|
305
|
-
|
|
354
|
+
loc: reportLoc,
|
|
306
355
|
messageId: 'missingJSDoc',
|
|
307
356
|
data: { type, name },
|
|
308
357
|
});
|
|
309
358
|
} else if (!jsdocResult.isOnPreviousLine) {
|
|
310
359
|
context.report({
|
|
311
|
-
|
|
360
|
+
loc: reportLoc,
|
|
312
361
|
messageId: 'invalidJSDocPosition',
|
|
313
362
|
data: { type, name },
|
|
314
363
|
});
|
|
315
364
|
} else if (!jsdocResult.isValid) {
|
|
316
365
|
context.report({
|
|
317
|
-
|
|
366
|
+
loc: reportLoc,
|
|
318
367
|
messageId: 'emptyJSDoc',
|
|
319
368
|
data: { type, name },
|
|
320
369
|
});
|
|
Binary file
|