eslint-plugin-traceability 1.8.0 → 1.8.2
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/CHANGELOG.md +5 -5
- package/README.md +28 -29
- package/SECURITY.md +135 -0
- package/lib/src/index.d.ts +6 -35
- package/lib/src/index.js +8 -5
- package/lib/src/maintenance/cli.js +12 -16
- package/lib/src/maintenance/detect.js +28 -1
- package/lib/src/rules/helpers/require-story-io.d.ts +2 -2
- package/lib/src/rules/helpers/require-story-io.js +13 -13
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +2 -2
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +3 -3
- package/lib/src/rules/helpers/valid-annotation-utils.d.ts +5 -0
- package/lib/src/rules/helpers/valid-annotation-utils.js +43 -5
- package/lib/src/rules/helpers/valid-implements-utils.d.ts +11 -11
- package/lib/src/rules/helpers/valid-implements-utils.js +11 -11
- package/lib/src/rules/helpers/valid-story-reference-helpers.js +19 -0
- package/lib/src/rules/prefer-implements-annotation.d.ts +7 -7
- package/lib/src/rules/prefer-implements-annotation.js +21 -21
- package/lib/src/rules/valid-annotation-format.js +50 -24
- package/lib/src/rules/valid-req-reference.js +9 -9
- package/lib/src/utils/annotation-checker.js +3 -1
- package/lib/src/utils/reqAnnotationDetection.d.ts +2 -2
- package/lib/src/utils/reqAnnotationDetection.js +28 -28
- package/lib/tests/config/flat-config-presets-integration.test.d.ts +1 -0
- package/lib/tests/config/flat-config-presets-integration.test.js +75 -0
- package/lib/tests/maintenance/batch.test.js +11 -11
- package/lib/tests/maintenance/cli.test.js +34 -27
- package/lib/tests/maintenance/report.test.js +7 -7
- package/lib/tests/plugin-default-export-and-configs.test.js +0 -2
- package/lib/tests/rules/prefer-implements-annotation.test.js +48 -15
- package/lib/tests/rules/require-branch-annotation.test.js +15 -36
- package/lib/tests/rules/require-req-annotation.test.js +31 -104
- package/lib/tests/rules/require-story-annotation.test.js +3 -3
- package/lib/tests/rules/require-story-io-behavior.test.js +2 -7
- package/lib/tests/rules/require-story-io.edgecases.test.js +2 -7
- package/lib/tests/rules/require-story-visitors-edgecases.test.js +8 -8
- package/lib/tests/rules/valid-annotation-format.test.js +23 -23
- package/lib/tests/rules/valid-req-reference.test.js +9 -9
- package/lib/tests/rules/valid-story-reference.test.js +4 -43
- package/lib/tests/utils/annotation-checker.test.js +2 -6
- package/lib/tests/utils/fsTestHelpers.d.ts +7 -0
- package/lib/tests/utils/fsTestHelpers.js +26 -0
- package/lib/tests/utils/ioTestHelpers.d.ts +7 -0
- package/lib/tests/utils/ioTestHelpers.js +24 -0
- package/lib/tests/utils/temp-dir-helpers.d.ts +14 -0
- package/lib/tests/utils/temp-dir-helpers.js +61 -0
- package/package.json +8 -7
- package/user-docs/api-reference.md +37 -20
- package/user-docs/eslint-9-setup-guide.md +89 -6
- package/user-docs/migration-guide.md +37 -21
- package/docs/ci-cd-pipeline.md +0 -224
- package/docs/cli-integration.md +0 -22
- package/docs/code-quality-refactor-opportunities-2025-12-03.md +0 -78
- package/docs/config-presets.md +0 -38
- package/docs/conventional-commits-guide.md +0 -185
- package/docs/custom-rules-development-guide.md +0 -659
- package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +0 -26
- package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +0 -111
- package/docs/decisions/002-jest-for-eslint-testing.accepted.md +0 -137
- package/docs/decisions/003-code-quality-ratcheting-plan.md +0 -48
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +0 -196
- package/docs/decisions/005-github-actions-validation-tooling.accepted.md +0 -144
- package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +0 -227
- package/docs/decisions/007-github-releases-over-changelog.accepted.md +0 -216
- package/docs/decisions/008-ci-audit-flags.accepted.md +0 -60
- package/docs/decisions/009-security-focused-lint-rules.accepted.md +0 -64
- package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +0 -184
- package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +0 -190
- package/docs/decisions/adr-accept-dev-dep-risk-glob.md +0 -40
- package/docs/decisions/adr-commit-branch-tests.md +0 -54
- package/docs/decisions/adr-maintenance-cli-interface.md +0 -140
- package/docs/decisions/adr-pre-push-parity.md +0 -112
- package/docs/decisions/code-quality-ratcheting-plan.md +0 -53
- package/docs/dependency-health.md +0 -238
- package/docs/eslint-9-setup-guide.md +0 -517
- package/docs/eslint-plugin-development-guide.md +0 -487
- package/docs/functionality-coverage-2025-12-03.md +0 -250
- package/docs/jest-testing-guide.md +0 -100
- package/docs/rules/prefer-implements-annotation.md +0 -219
- package/docs/rules/require-branch-annotation.md +0 -71
- package/docs/rules/require-req-annotation.md +0 -203
- package/docs/rules/require-story-annotation.md +0 -159
- package/docs/rules/valid-annotation-format.md +0 -418
- package/docs/rules/valid-req-reference.md +0 -153
- package/docs/rules/valid-story-reference.md +0 -120
- package/docs/security-incidents/2025-11-17-glob-cli-incident.md +0 -45
- package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +0 -45
- package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +0 -93
- package/docs/security-incidents/2025-11-18-tar-race-condition.md +0 -43
- package/docs/security-incidents/2025-12-03-dependency-health-review.md +0 -58
- package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +0 -104
- package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +0 -37
- package/docs/security-incidents/dependency-override-rationale.md +0 -57
- package/docs/security-incidents/dev-deps-high.json +0 -116
- package/docs/security-incidents/handling-procedure.md +0 -54
- package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +0 -92
- package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +0 -82
- package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +0 -112
- package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +0 -153
- package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +0 -138
- package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +0 -144
- package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +0 -163
- package/docs/stories/008.0-DEV-AUTO-FIX.story.md +0 -150
- package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +0 -117
- package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +0 -124
- package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +0 -149
- package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +0 -216
- package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +0 -236
- package/docs/stories/developer-story.map.md +0 -120
- package/docs/ts-jest-presets-guide.md +0 -548
|
@@ -14,7 +14,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
14
14
|
* @req REQ-TYPESCRIPT-SUPPORT - Verify TypeScript declarations are checked via shared annotation checker helper
|
|
15
15
|
*
|
|
16
16
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
17
|
-
* @req REQ-REQUIRE-ACCEPTS-IMPLEMENTS - Verify @
|
|
17
|
+
* @req REQ-REQUIRE-ACCEPTS-IMPLEMENTS - Verify @supports is accepted as satisfying requirement annotations
|
|
18
18
|
*/
|
|
19
19
|
const eslint_1 = require("eslint");
|
|
20
20
|
const require_req_annotation_1 = __importDefault(require("../../src/rules/require-req-annotation"));
|
|
@@ -25,6 +25,18 @@ const ruleTester = new eslint_1.RuleTester({
|
|
|
25
25
|
parserOptions: { ecmaVersion: 2022, sourceType: "module" },
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
|
+
/**
|
|
29
|
+
* Build a standard missingReq error object for a given function name.
|
|
30
|
+
*
|
|
31
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
32
|
+
* @req REQ-ANNOTATION-REQUIRED - Standardize missingReq error shape in tests
|
|
33
|
+
*/
|
|
34
|
+
function missingReq(functionName) {
|
|
35
|
+
return {
|
|
36
|
+
messageId: "missingReq",
|
|
37
|
+
data: { name: functionName, functionName },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
28
40
|
/**
|
|
29
41
|
* @trace Story 003.0-DEV-FUNCTION-ANNOTATIONS / REQ-TYPESCRIPT-SUPPORT
|
|
30
42
|
* Exercise the require-req-annotation rule's behavior on TSDeclareFunction and
|
|
@@ -50,22 +62,12 @@ const ruleTester = new eslint_1.RuleTester({
|
|
|
50
62
|
{
|
|
51
63
|
name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSDeclareFunction",
|
|
52
64
|
code: `declare function baz(): void;`,
|
|
53
|
-
errors: [
|
|
54
|
-
{
|
|
55
|
-
messageId: "missingReq",
|
|
56
|
-
data: { name: "baz", functionName: "baz" },
|
|
57
|
-
},
|
|
58
|
-
],
|
|
65
|
+
errors: [missingReq("baz")],
|
|
59
66
|
},
|
|
60
67
|
{
|
|
61
68
|
name: "[REQ-TYPESCRIPT-SUPPORT] missing @req on TSMethodSignature",
|
|
62
69
|
code: `interface I { method(): void; }`,
|
|
63
|
-
errors: [
|
|
64
|
-
{
|
|
65
|
-
messageId: "missingReq",
|
|
66
|
-
data: { name: "method", functionName: "method" },
|
|
67
|
-
},
|
|
68
|
-
],
|
|
70
|
+
errors: [missingReq("method")],
|
|
69
71
|
},
|
|
70
72
|
],
|
|
71
73
|
});
|
|
@@ -78,7 +80,7 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
|
|
|
78
80
|
},
|
|
79
81
|
{
|
|
80
82
|
name: "[REQ-REQUIRE-ACCEPTS-IMPLEMENTS] valid with only @implements annotation",
|
|
81
|
-
code: `/**\n * @
|
|
83
|
+
code: `/**\n * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction implOnly() {}`,
|
|
82
84
|
},
|
|
83
85
|
{
|
|
84
86
|
name: "[REQ-ANNOTATION-REQUIRED] valid with @story and @req annotations",
|
|
@@ -140,159 +142,84 @@ describe("Require Req Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)", (
|
|
|
140
142
|
{
|
|
141
143
|
name: "[REQ-ANNOTATION-REQUIRED][REQ-REQUIRE-ACCEPTS-IMPLEMENTS] missing @req on function without JSDoc remains invalid under multi-story support",
|
|
142
144
|
code: `function baz() {}`,
|
|
143
|
-
errors: [
|
|
144
|
-
{
|
|
145
|
-
messageId: "missingReq",
|
|
146
|
-
data: { name: "baz", functionName: "baz" },
|
|
147
|
-
},
|
|
148
|
-
],
|
|
145
|
+
errors: [missingReq("baz")],
|
|
149
146
|
},
|
|
150
147
|
{
|
|
151
148
|
name: "[REQ-ANNOTATION-REQUIRED] missing @req on function with only @story annotation",
|
|
152
149
|
code: `/**\n * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md\n */\nfunction qux() {}`,
|
|
153
|
-
errors: [
|
|
154
|
-
{
|
|
155
|
-
messageId: "missingReq",
|
|
156
|
-
data: { name: "qux", functionName: "qux" },
|
|
157
|
-
},
|
|
158
|
-
],
|
|
150
|
+
errors: [missingReq("qux")],
|
|
159
151
|
},
|
|
160
152
|
{
|
|
161
153
|
name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on FunctionExpression assigned to variable",
|
|
162
154
|
code: `const fn = function () {};`,
|
|
163
|
-
errors: [
|
|
164
|
-
{
|
|
165
|
-
messageId: "missingReq",
|
|
166
|
-
data: { name: "fn", functionName: "fn" },
|
|
167
|
-
},
|
|
168
|
-
],
|
|
155
|
+
errors: [missingReq("fn")],
|
|
169
156
|
},
|
|
170
157
|
{
|
|
171
158
|
name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on anonymous FunctionExpression (no variable name)",
|
|
172
159
|
code: `(function () {})();`,
|
|
173
|
-
errors: [
|
|
174
|
-
{
|
|
175
|
-
messageId: "missingReq",
|
|
176
|
-
data: { name: "(anonymous)", functionName: "(anonymous)" },
|
|
177
|
-
},
|
|
178
|
-
],
|
|
160
|
+
errors: [missingReq("(anonymous)")],
|
|
179
161
|
},
|
|
180
162
|
{
|
|
181
163
|
name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on MethodDefinition in class",
|
|
182
164
|
code: `class C {\n m() {}\n}`,
|
|
183
|
-
errors: [
|
|
184
|
-
{
|
|
185
|
-
messageId: "missingReq",
|
|
186
|
-
data: { name: "m", functionName: "m" },
|
|
187
|
-
},
|
|
188
|
-
],
|
|
165
|
+
errors: [missingReq("m")],
|
|
189
166
|
},
|
|
190
167
|
{
|
|
191
168
|
name: "[REQ-FUNCTION-DETECTION][Story 003.0] missing @req on MethodDefinition in object literal",
|
|
192
169
|
code: `const o = { m() {} };`,
|
|
193
|
-
errors: [
|
|
194
|
-
{
|
|
195
|
-
messageId: "missingReq",
|
|
196
|
-
data: { name: "m", functionName: "m" },
|
|
197
|
-
},
|
|
198
|
-
],
|
|
170
|
+
errors: [missingReq("m")],
|
|
199
171
|
},
|
|
200
172
|
(0, ts_language_options_1.withTsLanguageOptions)({
|
|
201
173
|
name: "[REQ-TYPESCRIPT-SUPPORT][REQ-FUNCTION-DETECTION][Story 003.0] missing @req on TS FunctionExpression in variable declarator",
|
|
202
174
|
code: `const fn = function () {};`,
|
|
203
|
-
errors: [
|
|
204
|
-
{
|
|
205
|
-
messageId: "missingReq",
|
|
206
|
-
data: { name: "fn", functionName: "fn" },
|
|
207
|
-
},
|
|
208
|
-
],
|
|
175
|
+
errors: [missingReq("fn")],
|
|
209
176
|
}),
|
|
210
177
|
(0, ts_language_options_1.withTsLanguageOptions)({
|
|
211
178
|
name: "[REQ-TYPESCRIPT-SUPPORT][REQ-FUNCTION-DETECTION][Story 003.0] missing @req on exported TS FunctionExpression in variable declarator",
|
|
212
179
|
code: `export const fn = function () {};`,
|
|
213
|
-
errors: [
|
|
214
|
-
{
|
|
215
|
-
messageId: "missingReq",
|
|
216
|
-
data: { name: "fn", functionName: "fn" },
|
|
217
|
-
},
|
|
218
|
-
],
|
|
180
|
+
errors: [missingReq("fn")],
|
|
219
181
|
}),
|
|
220
182
|
{
|
|
221
183
|
name: "[REQ-CONFIGURABLE-SCOPE][Story 003.0] FunctionDeclaration still reported when scope only includes FunctionDeclaration",
|
|
222
184
|
code: `function scoped() {}`,
|
|
223
185
|
options: [{ scope: ["FunctionDeclaration"] }],
|
|
224
|
-
errors: [
|
|
225
|
-
{
|
|
226
|
-
messageId: "missingReq",
|
|
227
|
-
data: { name: "scoped", functionName: "scoped" },
|
|
228
|
-
},
|
|
229
|
-
],
|
|
186
|
+
errors: [missingReq("scoped")],
|
|
230
187
|
},
|
|
231
188
|
{
|
|
232
189
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported function reported when exportPriority is 'exported'",
|
|
233
190
|
code: `export function exportedFn() {}`,
|
|
234
191
|
options: [{ exportPriority: "exported" }],
|
|
235
|
-
errors: [
|
|
236
|
-
{
|
|
237
|
-
messageId: "missingReq",
|
|
238
|
-
data: { name: "exportedFn", functionName: "exportedFn" },
|
|
239
|
-
},
|
|
240
|
-
],
|
|
192
|
+
errors: [missingReq("exportedFn")],
|
|
241
193
|
},
|
|
242
194
|
{
|
|
243
195
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported function reported when exportPriority is 'non-exported'",
|
|
244
196
|
code: `function nonExported() {}`,
|
|
245
197
|
options: [{ exportPriority: "non-exported" }],
|
|
246
|
-
errors: [
|
|
247
|
-
{
|
|
248
|
-
messageId: "missingReq",
|
|
249
|
-
data: { name: "nonExported", functionName: "nonExported" },
|
|
250
|
-
},
|
|
251
|
-
],
|
|
198
|
+
errors: [missingReq("nonExported")],
|
|
252
199
|
},
|
|
253
200
|
{
|
|
254
201
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported method reported when exportPriority is 'exported'",
|
|
255
202
|
code: `export class C {\n m() {}\n}`,
|
|
256
|
-
errors: [
|
|
257
|
-
{
|
|
258
|
-
messageId: "missingReq",
|
|
259
|
-
data: { name: "m", functionName: "m" },
|
|
260
|
-
},
|
|
261
|
-
],
|
|
203
|
+
errors: [missingReq("m")],
|
|
262
204
|
options: [{ exportPriority: "exported" }],
|
|
263
205
|
},
|
|
264
206
|
{
|
|
265
207
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported method reported when exportPriority is 'non-exported'",
|
|
266
208
|
code: `class C {\n m() {}\n}`,
|
|
267
|
-
errors: [
|
|
268
|
-
{
|
|
269
|
-
messageId: "missingReq",
|
|
270
|
-
data: { name: "m", functionName: "m" },
|
|
271
|
-
},
|
|
272
|
-
],
|
|
209
|
+
errors: [missingReq("m")],
|
|
273
210
|
options: [{ exportPriority: "non-exported" }],
|
|
274
211
|
},
|
|
275
212
|
{
|
|
276
213
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] exported FunctionExpression reported when exportPriority is 'exported'",
|
|
277
214
|
code: `export const fn = function () {};`,
|
|
278
215
|
options: [{ exportPriority: "exported" }],
|
|
279
|
-
errors: [
|
|
280
|
-
{
|
|
281
|
-
messageId: "missingReq",
|
|
282
|
-
data: { name: "fn", functionName: "fn" },
|
|
283
|
-
},
|
|
284
|
-
],
|
|
216
|
+
errors: [missingReq("fn")],
|
|
285
217
|
},
|
|
286
218
|
{
|
|
287
219
|
name: "[REQ-EXPORT-PRIORITY][Story 003.0] non-exported FunctionExpression reported when exportPriority is 'non-exported'",
|
|
288
220
|
code: `const fn = function () {};`,
|
|
289
221
|
options: [{ exportPriority: "non-exported" }],
|
|
290
|
-
errors: [
|
|
291
|
-
{
|
|
292
|
-
messageId: "missingReq",
|
|
293
|
-
data: { name: "fn", functionName: "fn" },
|
|
294
|
-
},
|
|
295
|
-
],
|
|
222
|
+
errors: [missingReq("fn")],
|
|
296
223
|
},
|
|
297
224
|
],
|
|
298
225
|
});
|
|
@@ -8,7 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
8
8
|
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
9
9
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
10
10
|
* @req REQ-ANNOTATION-REQUIRED - Verify require-story-annotation rule enforces @story annotation on functions
|
|
11
|
-
* @req REQ-REQUIRE-ACCEPTS-IMPLEMENTS - Verify @
|
|
11
|
+
* @req REQ-REQUIRE-ACCEPTS-IMPLEMENTS - Verify @supports annotation is accepted as satisfying story requirements
|
|
12
12
|
*/
|
|
13
13
|
const eslint_1 = require("eslint");
|
|
14
14
|
const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
|
|
@@ -25,7 +25,7 @@ describe("Require Story Annotation Rule (Story 003.0-DEV-FUNCTION-ANNOTATIONS)",
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
name: "[REQ-REQUIRE-ACCEPTS-IMPLEMENTS] valid with only @implements annotation",
|
|
28
|
-
code: `/**\n * @
|
|
28
|
+
code: `/**\n * @supports docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md REQ-ANNOTATION-REQUIRED\n */\nfunction implOnly() {}`,
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
name: "[REQ-ANNOTATION-REQUIRED] valid with line comment @story annotation",
|
|
@@ -65,7 +65,7 @@ declare function tsDecl(): void;`,
|
|
|
65
65
|
invalid: [
|
|
66
66
|
{
|
|
67
67
|
// Backward compatibility: plain unannotated functions remain invalid under multi-story support
|
|
68
|
-
name: "[REQ-ANNOTATION-REQUIRED][BACKCOMPAT] missing @story annotation on function with no @
|
|
68
|
+
name: "[REQ-ANNOTATION-REQUIRED][BACKCOMPAT] missing @story annotation on function with no @supports",
|
|
69
69
|
code: `function bar() {}`,
|
|
70
70
|
output: `/** @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md */\nfunction bar() {}`,
|
|
71
71
|
errors: [
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
const require_story_io_1 = require("../../src/rules/helpers/require-story-io");
|
|
9
|
+
const ioTestHelpers_1 = require("../utils/ioTestHelpers");
|
|
9
10
|
describe("Require Story IO helpers - additional behavior (Story 003.0)", () => {
|
|
10
11
|
test("parentChainHasStory returns false when sourceCode.getCommentsBefore is not a function", () => {
|
|
11
12
|
const fakeSource = {}; // no getCommentsBefore function
|
|
@@ -39,12 +40,6 @@ describe("Require Story IO helpers - additional behavior (Story 003.0)", () => {
|
|
|
39
40
|
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource, node)).toBe(false);
|
|
40
41
|
});
|
|
41
42
|
test("fallbackTextBeforeHasStory detects @story in text before node.range", () => {
|
|
42
|
-
|
|
43
|
-
const pre = `/* ${story} */\n`;
|
|
44
|
-
const rest = "function y() {}";
|
|
45
|
-
const full = pre + rest;
|
|
46
|
-
const fakeSource = { getText: () => full };
|
|
47
|
-
const node = { range: [full.indexOf("function"), full.length] };
|
|
48
|
-
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource, node)).toBe(true);
|
|
43
|
+
(0, ioTestHelpers_1.runFallbackTextBeforeHasStoryDetectsStoryTest)("@story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md", require_story_io_1.fallbackTextBeforeHasStory);
|
|
49
44
|
});
|
|
50
45
|
});
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
const require_story_io_1 = require("../../src/rules/helpers/require-story-io");
|
|
9
|
+
const ioTestHelpers_1 = require("../utils/ioTestHelpers");
|
|
9
10
|
describe("Require Story IO helpers - edge cases (Story 003.0)", () => {
|
|
10
11
|
test("linesBeforeHasStory returns false when source.lines missing or node.loc missing", () => {
|
|
11
12
|
const fakeSource = {};
|
|
@@ -24,13 +25,7 @@ describe("Require Story IO helpers - edge cases (Story 003.0)", () => {
|
|
|
24
25
|
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource2, node2)).toBe(false);
|
|
25
26
|
});
|
|
26
27
|
test("fallbackTextBeforeHasStory detects @story in text before node.range", () => {
|
|
27
|
-
|
|
28
|
-
const pre = `/* ${story} */\\n`;
|
|
29
|
-
const rest = "function x() {}";
|
|
30
|
-
const full = pre + rest;
|
|
31
|
-
const fakeSource = { getText: () => full };
|
|
32
|
-
const node = { range: [full.indexOf("function"), full.length] };
|
|
33
|
-
expect((0, require_story_io_1.fallbackTextBeforeHasStory)(fakeSource, node)).toBe(true);
|
|
28
|
+
(0, ioTestHelpers_1.runFallbackTextBeforeHasStoryDetectsStoryTest)(require_story_io_1.fallbackTextBeforeHasStory);
|
|
34
29
|
});
|
|
35
30
|
test("parentChainHasStory returns true when ancestor comments contain @story", () => {
|
|
36
31
|
const fakeSource = {
|
|
@@ -6,20 +6,20 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
const require_story_visitors_1 = require("../../src/rules/helpers/require-story-visitors");
|
|
9
|
+
const makeVisitors = () => {
|
|
10
|
+
const fakeContext = { getFilename: () => "file.ts" };
|
|
11
|
+
const fakeSource = { getText: () => "" };
|
|
12
|
+
const options = { shouldProcessNode: () => true };
|
|
13
|
+
return (0, require_story_visitors_1.buildVisitors)(fakeContext, fakeSource, options);
|
|
14
|
+
};
|
|
9
15
|
describe("Require Story Visitors - behavior (Story 003.0)", () => {
|
|
10
16
|
test("build visitors returns handlers for FunctionDeclaration and ArrowFunctionExpression", () => {
|
|
11
|
-
const
|
|
12
|
-
const fakeSource = { getText: () => "" };
|
|
13
|
-
const options = { shouldProcessNode: () => true };
|
|
14
|
-
const visitors = (0, require_story_visitors_1.buildVisitors)(fakeContext, fakeSource, options);
|
|
17
|
+
const visitors = makeVisitors();
|
|
15
18
|
expect(typeof visitors.FunctionDeclaration).toBe("function");
|
|
16
19
|
expect(typeof visitors.ArrowFunctionExpression).toBe("function");
|
|
17
20
|
});
|
|
18
21
|
test("FunctionDeclaration handler uses context.getFilename and doesn't throw when node lacks id", () => {
|
|
19
|
-
const
|
|
20
|
-
const fakeSource = { getText: () => "" };
|
|
21
|
-
const options = { shouldProcessNode: () => true };
|
|
22
|
-
const visitors = (0, require_story_visitors_1.buildVisitors)(fakeContext, fakeSource, options);
|
|
22
|
+
const visitors = makeVisitors();
|
|
23
23
|
const handler = visitors.FunctionDeclaration;
|
|
24
24
|
expect(() => handler({})).not.toThrow();
|
|
25
25
|
});
|
|
@@ -20,9 +20,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
20
20
|
* @req REQ-CONFIGURABLE-PATTERNS-FALLBACK - Invalid regex patterns fall back to default behavior without crashing
|
|
21
21
|
* Tests for: docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
22
22
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
23
|
-
* @req REQ-
|
|
24
|
-
* @req REQ-FORMAT-VALIDATION - Rule validates story and requirement formats inside @
|
|
25
|
-
* @req REQ-MIXED-SUPPORT - Rule supports mixed @story/@req/@
|
|
23
|
+
* @req REQ-SUPPORTS-PARSE - Rule parses @supports annotations with story and requirement references
|
|
24
|
+
* @req REQ-FORMAT-VALIDATION - Rule validates story and requirement formats inside @supports annotations
|
|
25
|
+
* @req REQ-MIXED-SUPPORT - Rule supports mixed @story/@req/@supports usage in the same comment
|
|
26
26
|
*/
|
|
27
27
|
const eslint_1 = require("eslint");
|
|
28
28
|
const valid_annotation_format_1 = __importDefault(require("../../src/rules/valid-annotation-format"));
|
|
@@ -174,24 +174,24 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
174
174
|
],
|
|
175
175
|
},
|
|
176
176
|
{
|
|
177
|
-
name: "[REQ-IMPLEMENTS-PARSE] valid single @
|
|
177
|
+
name: "[REQ-IMPLEMENTS-PARSE] valid single @supports with one story and one requirement (default patterns)",
|
|
178
178
|
code: `/**
|
|
179
|
-
* @
|
|
179
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-IMPLEMENTS-PARSE
|
|
180
180
|
*/`,
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
|
-
name: "[REQ-IMPLEMENTS-PARSE] valid multiple @
|
|
183
|
+
name: "[REQ-IMPLEMENTS-PARSE] valid multiple @supports lines with different stories and requirements",
|
|
184
184
|
code: `/**
|
|
185
|
-
* @
|
|
186
|
-
* @
|
|
185
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-IMPLEMENTS-PARSE REQ-FORMAT-VALIDATION
|
|
186
|
+
* @supports docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md REQ-FORMAT-SPECIFICATION
|
|
187
187
|
*/`,
|
|
188
188
|
},
|
|
189
189
|
{
|
|
190
|
-
name: "[REQ-MIXED-SUPPORT] valid mixed @story/@req/@
|
|
190
|
+
name: "[REQ-MIXED-SUPPORT] valid mixed @story/@req/@supports usage in same block comment",
|
|
191
191
|
code: `/**
|
|
192
192
|
* @story docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
193
193
|
* @req REQ-MIXED-SUPPORT
|
|
194
|
-
* @
|
|
194
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-IMPLEMENTS-PARSE REQ-FORMAT-VALIDATION REQ-MIXED-SUPPORT
|
|
195
195
|
*/`,
|
|
196
196
|
},
|
|
197
197
|
],
|
|
@@ -507,33 +507,33 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
507
507
|
],
|
|
508
508
|
},
|
|
509
509
|
makeInvalid({
|
|
510
|
-
name: "[REQ-
|
|
510
|
+
name: "[REQ-SUPPORTS-PARSE] @supports with no value is invalid",
|
|
511
511
|
code: `/**
|
|
512
|
-
* @
|
|
512
|
+
* @supports
|
|
513
513
|
*/`,
|
|
514
514
|
messageId: "invalidImplementsFormat",
|
|
515
|
-
details: 'Missing story path and requirement IDs for @
|
|
515
|
+
details: 'Missing story path and requirement IDs for @supports annotation. Expected a value like "docs/stories/005.0-DEV-EXAMPLE.story.md REQ-EXAMPLE".',
|
|
516
516
|
}),
|
|
517
517
|
makeInvalid({
|
|
518
|
-
name: "[REQ-
|
|
518
|
+
name: "[REQ-SUPPORTS-PARSE] @supports with only story path and no requirement IDs is invalid",
|
|
519
519
|
code: `/**
|
|
520
|
-
* @
|
|
520
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md
|
|
521
521
|
*/`,
|
|
522
522
|
messageId: "invalidImplementsFormat",
|
|
523
|
-
details: 'Missing requirement IDs for @
|
|
523
|
+
details: 'Missing requirement IDs for @supports annotation. Expected a value like "docs/stories/005.0-DEV-EXAMPLE.story.md REQ-EXAMPLE".',
|
|
524
524
|
}),
|
|
525
525
|
makeInvalid({
|
|
526
|
-
name: "[REQ-FORMAT-VALIDATION] @
|
|
526
|
+
name: "[REQ-FORMAT-VALIDATION] @supports with invalid story path format",
|
|
527
527
|
code: `/**
|
|
528
|
-
* @
|
|
528
|
+
* @supports invalid/path.txt REQ-IMPLEMENTS-PARSE
|
|
529
529
|
*/`,
|
|
530
530
|
messageId: "invalidImplementsFormat",
|
|
531
|
-
details: 'Invalid story path "invalid/path.txt" for @
|
|
531
|
+
details: 'Invalid story path "invalid/path.txt" for @supports annotation. Expected a path like "docs/stories/005.0-DEV-EXAMPLE.story.md".',
|
|
532
532
|
}),
|
|
533
533
|
{
|
|
534
|
-
name: "[REQ-FORMAT-VALIDATION] @
|
|
534
|
+
name: "[REQ-FORMAT-VALIDATION] @supports with invalid requirement ID format",
|
|
535
535
|
code: `/**
|
|
536
|
-
* @
|
|
536
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-VALID invalid-format
|
|
537
537
|
*/`,
|
|
538
538
|
errors: [
|
|
539
539
|
{
|
|
@@ -545,9 +545,9 @@ describe("Valid Annotation Format Rule (Story 005.0-DEV-ANNOTATION-VALIDATION)",
|
|
|
545
545
|
],
|
|
546
546
|
},
|
|
547
547
|
{
|
|
548
|
-
name: "[REQ-FORMAT-VALIDATION] @
|
|
548
|
+
name: "[REQ-FORMAT-VALIDATION] @supports with multiple requirement IDs where one is invalid",
|
|
549
549
|
code: `/**
|
|
550
|
-
* @
|
|
550
|
+
* @supports docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md REQ-VALID-1 REQ-VALID-2 bad-id
|
|
551
551
|
*/`,
|
|
552
552
|
errors: [
|
|
553
553
|
{
|
|
@@ -33,13 +33,13 @@ describe("Valid Req Reference Rule (Story 010.0-DEV-DEEP-VALIDATION)", () => {
|
|
|
33
33
|
// @req REQ-BULLET-LIST`,
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
|
-
name: "[REQ-DEEP-IMPLEMENTS] single
|
|
37
|
-
code: `// @
|
|
36
|
+
name: "[REQ-DEEP-IMPLEMENTS] single supports line with multiple requirements in multi-story fixture (see 010.2-DEV-MULTI-STORY-SUPPORT)",
|
|
37
|
+
code: `// @supports tests/fixtures/story_multi_a.md REQ-SHARED-ID REQ-ONLY-A`,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
|
-
name: "[REQ-DEEP-IMPLEMENTS] multi-story
|
|
41
|
-
code: `// @
|
|
42
|
-
// @
|
|
40
|
+
name: "[REQ-DEEP-IMPLEMENTS] multi-story supports with shared requirement IDs (see 010.2-DEV-MULTI-STORY-SUPPORT)",
|
|
41
|
+
code: `// @supports tests/fixtures/story_multi_a.md REQ-SHARED-ID REQ-ONLY-A
|
|
42
|
+
// @supports tests/fixtures/story_multi_b.md REQ-SHARED-ID REQ-ONLY-B`,
|
|
43
43
|
},
|
|
44
44
|
],
|
|
45
45
|
invalid: [
|
|
@@ -98,8 +98,8 @@ describe("Valid Req Reference Rule (Story 010.0-DEV-DEEP-VALIDATION)", () => {
|
|
|
98
98
|
],
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
|
-
name: "[REQ-DEEP-IMPLEMENTS] missing
|
|
102
|
-
code: `// @
|
|
101
|
+
name: "[REQ-DEEP-IMPLEMENTS] missing supports requirement in multi-story fixture (see 010.2-DEV-MULTI-STORY-SUPPORT)",
|
|
102
|
+
code: `// @supports tests/fixtures/story_multi_a.md REQ-NOT-IN-A`,
|
|
103
103
|
errors: [
|
|
104
104
|
{
|
|
105
105
|
messageId: "reqMissing",
|
|
@@ -111,8 +111,8 @@ describe("Valid Req Reference Rule (Story 010.0-DEV-DEEP-VALIDATION)", () => {
|
|
|
111
111
|
],
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
name: "[REQ-DEEP-IMPLEMENTS] disallow path traversal in
|
|
115
|
-
code: `// @
|
|
114
|
+
name: "[REQ-DEEP-IMPLEMENTS] disallow path traversal in supports story path (see 010.2-DEV-MULTI-STORY-SUPPORT)",
|
|
115
|
+
code: `// @supports ../tests/fixtures/story_multi_a.md REQ-SHARED-ID`,
|
|
116
116
|
errors: [
|
|
117
117
|
{
|
|
118
118
|
messageId: "invalidPath",
|
|
@@ -50,6 +50,7 @@ const eslint_1 = require("eslint");
|
|
|
50
50
|
const valid_story_reference_1 = __importDefault(require("../../src/rules/valid-story-reference"));
|
|
51
51
|
const storyReferenceUtils_1 = require("../../src/utils/storyReferenceUtils");
|
|
52
52
|
const path = __importStar(require("path"));
|
|
53
|
+
const fsTestHelpers_1 = require("../utils/fsTestHelpers");
|
|
53
54
|
const ruleTester = new eslint_1.RuleTester({
|
|
54
55
|
languageOptions: { parserOptions: { ecmaVersion: 2020 } },
|
|
55
56
|
});
|
|
@@ -223,19 +224,7 @@ describe("Valid Story Reference Rule Configuration and Boundaries (Story 006.0-D
|
|
|
223
224
|
});
|
|
224
225
|
it("[REQ-CONFIGURABLE-PATHS] uses storyDirectories when resolving relative paths (Story 006.0-DEV-FILE-VALIDATION)", () => {
|
|
225
226
|
const storyPath = pathModule.join(process.cwd(), "docs/stories/001.0-DEV-PLUGIN-SETUP.story.md");
|
|
226
|
-
|
|
227
|
-
const p = args[0];
|
|
228
|
-
return p === storyPath;
|
|
229
|
-
});
|
|
230
|
-
jest.spyOn(fs, "statSync").mockImplementation((...args) => {
|
|
231
|
-
const p = args[0];
|
|
232
|
-
if (p === storyPath) {
|
|
233
|
-
return {
|
|
234
|
-
isFile: () => true,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
throw Object.assign(new Error("ENOENT"), { code: "ENOENT" });
|
|
238
|
-
});
|
|
227
|
+
(0, fsTestHelpers_1.mockFsForExistingFile)(fs, storyPath);
|
|
239
228
|
const diagnostics = runRuleOnCode(`// @story 001.0-DEV-PLUGIN-SETUP.story.md`, [{ storyDirectories: ["docs/stories"] }]);
|
|
240
229
|
// When storyDirectories is configured, the underlying resolution should
|
|
241
230
|
// treat the path as valid; absence of errors is asserted via RuleTester
|
|
@@ -274,21 +263,7 @@ describe("Valid Story Reference Rule Configuration and Boundaries (Story 006.0-D
|
|
|
274
263
|
const pathModule = require("path");
|
|
275
264
|
const outsideDir = pathModule.resolve(pathModule.sep, "tmp", "outside");
|
|
276
265
|
const outsideFile = pathModule.join(outsideDir, "external-story.story.md");
|
|
277
|
-
|
|
278
|
-
const p = args[0];
|
|
279
|
-
return p === outsideFile;
|
|
280
|
-
});
|
|
281
|
-
jest.spyOn(fs, "statSync").mockImplementation((...args) => {
|
|
282
|
-
const p = args[0];
|
|
283
|
-
if (p === outsideFile) {
|
|
284
|
-
return {
|
|
285
|
-
isFile: () => true,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
const err = new Error("ENOENT");
|
|
289
|
-
err.code = "ENOENT";
|
|
290
|
-
throw err;
|
|
291
|
-
});
|
|
266
|
+
(0, fsTestHelpers_1.mockFsForExistingFile)(fs, outsideFile);
|
|
292
267
|
const diagnostics = runRuleOnCode(`// @story ${outsideFile}\n// @story docs/stories/006.0-DEV-FILE-VALIDATION.story.md`, [
|
|
293
268
|
{
|
|
294
269
|
allowAbsolutePaths: true,
|
|
@@ -308,21 +283,7 @@ describe("Valid Story Reference Rule Configuration and Boundaries (Story 006.0-D
|
|
|
308
283
|
const fs = require("fs");
|
|
309
284
|
const pathModule = require("path");
|
|
310
285
|
const storyPath = pathModule.join(process.cwd(), "docs/stories/developer-story.map.md");
|
|
311
|
-
|
|
312
|
-
const p = args[0];
|
|
313
|
-
return p === storyPath;
|
|
314
|
-
});
|
|
315
|
-
jest.spyOn(fs, "statSync").mockImplementation((...args) => {
|
|
316
|
-
const p = args[0];
|
|
317
|
-
if (p === storyPath) {
|
|
318
|
-
return {
|
|
319
|
-
isFile: () => true,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
const err = new Error("ENOENT");
|
|
323
|
-
err.code = "ENOENT";
|
|
324
|
-
throw err;
|
|
325
|
-
});
|
|
286
|
+
(0, fsTestHelpers_1.mockFsForExistingFile)(fs, storyPath);
|
|
326
287
|
const diagnostics = runRuleOnCode(`// @story docs/stories/developer-story.map.md\n// @story docs/stories/006.0-DEV-FILE-VALIDATION.story.md`, [
|
|
327
288
|
{
|
|
328
289
|
storyDirectories: ["docs/stories"],
|
|
@@ -11,10 +11,6 @@ const eslint_1 = require("eslint");
|
|
|
11
11
|
const annotation_checker_1 = require("../../src/utils/annotation-checker");
|
|
12
12
|
const ts_language_options_1 = require("./ts-language-options");
|
|
13
13
|
const ruleTester = new eslint_1.RuleTester();
|
|
14
|
-
const withTsAnnotationCheckerOptions = (test) => ({
|
|
15
|
-
...test,
|
|
16
|
-
languageOptions: ts_language_options_1.tsRuleTesterLanguageOptions,
|
|
17
|
-
});
|
|
18
14
|
/**
|
|
19
15
|
* Shared helper for running tests that exercise the annotation-checker logic
|
|
20
16
|
* for TypeScript constructs.
|
|
@@ -26,8 +22,8 @@ const withTsAnnotationCheckerOptions = (test) => ({
|
|
|
26
22
|
function runAnnotationCheckerTests(ruleName, config) {
|
|
27
23
|
const { rule, valid, invalid } = config;
|
|
28
24
|
ruleTester.run(ruleName, rule, {
|
|
29
|
-
valid: valid.map(
|
|
30
|
-
invalid: invalid.map(
|
|
25
|
+
valid: valid.map(ts_language_options_1.withTsLanguageOptions),
|
|
26
|
+
invalid: invalid.map(ts_language_options_1.withTsLanguageOptions),
|
|
31
27
|
});
|
|
32
28
|
}
|
|
33
29
|
const rule = {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filesystem mocking utilities for rule tests.
|
|
3
|
+
*
|
|
4
|
+
* @story docs/stories/006.0-DEV-FILE-VALIDATION.story.md
|
|
5
|
+
* @req REQ-TEST-UTILS-FS - Provide helpers to reduce duplication in fs-related tests
|
|
6
|
+
*/
|
|
7
|
+
export declare function mockFsForExistingFile(fs: typeof import("fs"), filePath: string): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mockFsForExistingFile = mockFsForExistingFile;
|
|
4
|
+
/**
|
|
5
|
+
* Shared filesystem mocking utilities for rule tests.
|
|
6
|
+
*
|
|
7
|
+
* @story docs/stories/006.0-DEV-FILE-VALIDATION.story.md
|
|
8
|
+
* @req REQ-TEST-UTILS-FS - Provide helpers to reduce duplication in fs-related tests
|
|
9
|
+
*/
|
|
10
|
+
function mockFsForExistingFile(fs, filePath) {
|
|
11
|
+
jest.spyOn(fs, "existsSync").mockImplementation((...args) => {
|
|
12
|
+
const p = args[0];
|
|
13
|
+
return p === filePath;
|
|
14
|
+
});
|
|
15
|
+
jest.spyOn(fs, "statSync").mockImplementation((...args) => {
|
|
16
|
+
const p = args[0];
|
|
17
|
+
if (p === filePath) {
|
|
18
|
+
return {
|
|
19
|
+
isFile: () => true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const err = new Error("ENOENT");
|
|
23
|
+
err.code = "ENOENT";
|
|
24
|
+
throw err;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared IO helper tests for require-story-io behavior.
|
|
3
|
+
*
|
|
4
|
+
* @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
|
|
5
|
+
* @req REQ-TEST-UTILS-IO - Provide reusable helpers for IO-related edge case tests
|
|
6
|
+
*/
|
|
7
|
+
export declare function runFallbackTextBeforeHasStoryDetectsStoryTest(storyAnnotationOrFallbackFn?: string | ((_source: any, _node: any) => boolean), maybeFallbackFn?: (_source: any, _node: any) => boolean): void;
|