Skip to content

Commit 683c88e

Browse files
committed
Add ESLint rule to restrict @codegen_exclude usage to Request.ts files
1 parent e114365 commit 683c88e

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed

specification/eslint.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default defineConfig([
3838
'es-spec-validator/no-native-types': 'error',
3939
'es-spec-validator/invalid-node-types': 'error',
4040
'es-spec-validator/no-generic-number': 'error',
41+
'es-spec-validator/codegen-exclude-on-request-only': 'error',
4142
'es-spec-validator/request-must-have-urls': 'error',
4243
'es-spec-validator/no-variants-on-responses': 'error',
4344
'es-spec-validator/no-inline-unions': 'error',
@@ -144,6 +145,7 @@ export default defineConfig([
144145
'behavior_meta',
145146
'class_serializer',
146147
'cluster_privileges',
148+
'codegen_exclude',
147149
'codegen_name',
148150
'codegen_names',
149151
'doc_id',

validator/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ It is configured [in the specification directory](../specification/eslint.config
1919
| `no-duplicate-type-names` | All types must be unique across class and enum definitions. |
2020
| `no-all-string-literal-unions | Unions consisting entirely of string literals (e.g., `"green" \| "yellow" \| "red"`) are not allowed, use enums instead. |
2121
| `jsdoc-endpoint-check` | Validates JSDoc on endpoints in the specification. Ensuring consistent formatting. Some errors can be fixed with `--fix`. |
22+
| `codegen-exclude-on-request-only` | Ensures `@codegen_exclude` is only used on request definitions located in namespaced `specification/` files (i.e. files. |
2223

2324
## Usage
2425

validator/eslint-plugin-es-spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import preferTaggedVariants from './rules/prefer-tagged-variants.js'
2828
import noDuplicateTypeNames from './rules/no-duplicate-type-names.js'
2929
import noAllStringLiteralUnions from './rules/no-all-string-literal-unions.js'
3030
import jsdocEndpointCheck from './rules/jsdoc-endpoint-check.js'
31+
import codegenExcludeOnRequestOnly from './rules/codegen-exclude-on-request-only.js'
3132

3233
export default {
3334
rules: {
@@ -42,6 +43,7 @@ export default {
4243
'prefer-tagged-variants': preferTaggedVariants,
4344
'no-duplicate-type-names': noDuplicateTypeNames,
4445
'no-all-string-literal-unions': noAllStringLiteralUnions,
45-
'jsdoc-endpoint-check': jsdocEndpointCheck
46+
'jsdoc-endpoint-check': jsdocEndpointCheck,
47+
'codegen-exclude-on-request-only': codegenExcludeOnRequestOnly
4648
}
4749
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { ESLintUtils } from '@typescript-eslint/utils'
21+
22+
export const codegenExcludeOnRequestOnly = ESLintUtils.RuleCreator.withoutDocs({
23+
name: 'codegen-exclude-on-request-only',
24+
meta: {
25+
type: 'problem',
26+
docs: {
27+
description: 'Ensures @codegen_exclude is only used on Request.ts files in specification/',
28+
recommended: 'error'
29+
},
30+
messages: {
31+
invalidUsage: '@codegen_exclude may only appear on Request definitions in specification/* (files named *Request.ts).'
32+
},
33+
schema: []
34+
},
35+
defaultOptions: [],
36+
create (context) {
37+
const sourceCode = context.getSourceCode()
38+
39+
function findCodegenExcludeComments () {
40+
return sourceCode.getAllComments().filter(c => c.type === 'Block' && c.value.startsWith('*') && /@codegen_exclude\b/.test(c.value))
41+
}
42+
43+
return {
44+
Program (node) {
45+
const filename = context.getFilename()
46+
const allowed = /[\\/]specification[\\/][^\\/]+[\\/].*Request\.ts$/.test(filename)
47+
const offending = findCodegenExcludeComments()
48+
for (const c of offending) {
49+
if (!allowed) {
50+
context.report({ loc: c.loc, messageId: 'invalidUsage' })
51+
}
52+
}
53+
}
54+
}
55+
}
56+
})
57+
58+
export default codegenExcludeOnRequestOnly
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { RuleTester } from '@typescript-eslint/rule-tester'
21+
import rule from '../rules/codegen-exclude-on-request-only.js'
22+
23+
const ruleTester = new RuleTester({
24+
languageOptions: {
25+
parserOptions: {
26+
projectService: {
27+
allowDefaultProject: ['*.ts*'],
28+
defaultProject: 'tsconfig.json'
29+
},
30+
tsconfigRootDir: new URL('../../specification/', import.meta.url).pathname
31+
}
32+
}
33+
})
34+
35+
ruleTester.run('codegen-exclude-on-request-only', rule, {
36+
valid: [
37+
{
38+
name: 'namespaced Request file with @codegen_exclude',
39+
filename: new URL('../../specification/ilm/put_lifecycle/PutLifecycleRequest.ts', import.meta.url).pathname,
40+
code: `
41+
/**
42+
* Some endpoint
43+
* @rest_spec_name ilm.put_lifecycle
44+
* @codegen_exclude
45+
*/
46+
export interface Request {}
47+
`
48+
},
49+
{
50+
name: 'request without tag in any file',
51+
filename: new URL('../../specification/ilm/put_lifecycle/PutLifecycleRequest.ts', import.meta.url).pathname,
52+
code: `
53+
export interface Request {}
54+
`
55+
}
56+
],
57+
invalid: [
58+
{
59+
name: 'non-namespaced file under specification with @codegen_exclude',
60+
filename: new URL('../../specification/SomeFile.ts', import.meta.url).pathname,
61+
code: `
62+
/**
63+
* @codegen_exclude
64+
*/
65+
export interface Something {}
66+
`,
67+
errors: [
68+
{ messageId: 'invalidUsage' }
69+
]
70+
},
71+
{
72+
name: 'namespaced Response file with @codegen_exclude',
73+
filename: new URL('../../specification/ilm/put_lifecycle/PutLifecycleResponse.ts', import.meta.url).pathname,
74+
code: `
75+
/**
76+
* @codegen_exclude
77+
*/
78+
export interface Response {}
79+
`,
80+
errors: [
81+
{ messageId: 'invalidUsage' }
82+
]
83+
}
84+
]
85+
})

0 commit comments

Comments
 (0)