Skip to content

Commit 15e1dfb

Browse files
authored
Dictionary allow only string as key lint (#4543)
* added dictionary rule eslint * fix taskid type * add test * address nit
1 parent 2db36bf commit 15e1dfb

File tree

10 files changed

+138
-35
lines changed

10 files changed

+138
-35
lines changed

output/openapi/elasticsearch-openapi.json

Lines changed: 1 addition & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

output/openapi/elasticsearch-serverless-openapi.json

Lines changed: 1 addition & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

output/schema/schema.json

Lines changed: 5 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

output/typescript/types.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

specification/_types/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export type SequenceNumber = long
126126

127127
export type PropertyName = string
128128
export type RelationName = string
129-
export type TaskId = string | integer
129+
export type TaskId = string
130130
/** @doc_id fuzziness */
131131
export type Fuzziness = string | integer
132132
/** @doc_id query-dsl-multi-term-rewrite */

specification/eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export default defineConfig({
3232
plugins: { 'es-spec-validator': validator },
3333
rules: {
3434
'es-spec-validator/single-key-dictionary-key-is-string': 'error',
35+
'es-spec-validator/dictionary-key-is-string': 'error',
3536
'es-spec-validator/invalid-node-types': 'warn'
3637
}
3738
})

validator/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ It is configured [in the specification directory](../specification/eslint.config
88
| Name | Description |
99
| - | - |
1010
| `single-key-dictionary-key-is-string` | `SingleKeyDictionary` keys must be strings. |
11+
| `dictionary-key-is-string` | `Dictionary` keys must be strings. |
1112
| `invalid-node-types` | The spec uses a subset of TypeScript, so some types, clauses and expressions are not allowed. |
1213

1314
## Usage

validator/eslint-plugin-es-spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
* under the License.
1818
*/
1919
import singleKeyDict from './rules/single-key-dictionary-key-is-string.js'
20+
import dict from './rules/dictionary-key-is-string.js'
2021
import invalidNodeTypes from './rules/invalid-node-types.js'
2122

2223
export default {
2324
rules: {
2425
'single-key-dictionary-key-is-string': singleKeyDict,
26+
'dictionary-key-is-string': dict,
2527
'invalid-node-types': invalidNodeTypes,
2628
}
2729
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
import { ESLintUtils } from '@typescript-eslint/utils';
20+
import ts from 'typescript'
21+
22+
const createRule = ESLintUtils.RuleCreator(name => `https://example.com/rule/${name}`)
23+
24+
export default createRule({
25+
name: 'dictionary-key-is-string',
26+
create(context) {
27+
return {
28+
TSTypeReference(node) {
29+
if (node.typeName.name === 'Dictionary') {
30+
const key = node.typeArguments.params[0]
31+
switch (key.type) {
32+
case 'TSTypeReference':
33+
// trace the reference to its original type definition
34+
const services = ESLintUtils.getParserServices(context)
35+
const type = services.getTypeAtLocation(key)
36+
37+
// check that the type is a string or an enum (enum members evaluate to strings)
38+
if (type.intrinsicName !== 'string' && !(type.symbol?.flags & ts.SymbolFlags.RegularEnum)) {
39+
context.report({ node, messageId: 'stringKey' })
40+
}
41+
break
42+
case 'TSStringKeyword':
43+
// type is string, skip
44+
break
45+
default:
46+
// unknown type!
47+
context.report({ node, messageId: 'stringKey' })
48+
break
49+
}
50+
}
51+
},
52+
}
53+
},
54+
meta: {
55+
docs: {
56+
description: 'Dictionary keys must be strings',
57+
},
58+
messages: {
59+
stringKey: "Dictionary's key must be a string"
60+
},
61+
type: 'suggestion',
62+
},
63+
defaultOptions: []
64+
})
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
import { RuleTester } from '@typescript-eslint/rule-tester'
20+
import rule from '../rules/dictionary-key-is-string.js'
21+
22+
const ruleTester = new RuleTester({
23+
languageOptions: {
24+
parserOptions: {
25+
projectService: {
26+
allowDefaultProject: ['*.ts*'],
27+
},
28+
tsconfigRootDir: import.meta.dirname,
29+
},
30+
},
31+
})
32+
33+
ruleTester.run('dictionary-key-is-string', rule, {
34+
valid: [
35+
`type MyDict = Dictionary<string, object>`,
36+
`type MyDict = Dictionary<string, any>`,
37+
`type MyDict = Dictionary<string, number>`,
38+
`enum MyEnum { foo, bar, baz }
39+
type MyDict = Dictionary<MyEnum, object>`,
40+
],
41+
invalid: [
42+
{
43+
code:
44+
`type MyKey = string | boolean
45+
type MyDict = Dictionary<MyKey, any>`,
46+
errors: [{ messageId: 'stringKey' }]
47+
},
48+
{
49+
code: `type MyDict = Dictionary<string | number, any>`,
50+
errors: [{ messageId: 'stringKey' }]
51+
},
52+
{
53+
code: `type MyDict = Dictionary<boolean, any>`,
54+
errors: [{ messageId: 'stringKey' }]
55+
},
56+
{
57+
code: `type MyDict = Dictionary<object, any>`,
58+
errors: [{ messageId: 'stringKey' }]
59+
}
60+
],
61+
})

0 commit comments

Comments
 (0)