Skip to content

Commit d6a5a40

Browse files
authored
lint: move rule docs and samples closer together (#2112)
The current split into `rules/` and `examples/` folders is a bit hard to grasp. Move the sample and docs for a rule in one folder, eliminating the `examples` folder. URLs change slightly: - `cds-lint/rules/foobar` (before) - `cds-lint/rules/foobar/` (now)
1 parent bc1cb06 commit d6a5a40

File tree

104 files changed

+187
-192
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+187
-192
lines changed

.github/eslint-plugin/index.js

100644100755
Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,15 @@
1010
import * as fs from 'node:fs'
1111
import * as path from 'node:path'
1212

13-
const RULES_BASE_PATH = path.join('tools', 'cds-lint', 'rules');
14-
const EXAMPLES_BASE_PATH = path.join('tools', 'cds-lint', 'examples');
13+
const RULES_BASE_PATH = path.join(import.meta.dirname, '../../tools/cds-lint/rules');
14+
const EXAMPLES_BASE_PATH = RULES_BASE_PATH
1515
const MENU_FILE_NAME = '_menu.md';
1616

1717
/**
1818
* Get a list of all rule description files.
1919
* @returns {string[]} An array of rule description file names.
2020
*/
21-
const getRuleDescriptionFiles = () =>
22-
fs.readdirSync(RULES_BASE_PATH)
23-
.filter(file => file.endsWith('.md'))
24-
.filter(file => !['index.md', MENU_FILE_NAME].includes(file))
25-
.sort()
21+
const getRuleDescriptionFiles = () => fs.globSync(path.join(RULES_BASE_PATH, '*/index.md')).sort()
2622

2723
/**
2824
* Generates the menu markdown file
@@ -33,12 +29,13 @@ const getRuleDescriptionFiles = () =>
3329
function generateMenuMarkdown () {
3430
const rules = getRuleDescriptionFiles();
3531
const menu = rules.map(rule => {
36-
const clean = rule.replace('.md', '');
37-
return `# [${clean}](${clean})`
32+
const folderPath = path.posix.dirname(path.relative(RULES_BASE_PATH, rule));
33+
const name = path.basename(folderPath);
34+
return `# [${name}](${folderPath}/)`
3835
}).join('\n');
39-
const menuFilePath = path.join(RULES_BASE_PATH, '_menu.md')
36+
const menuFilePath = path.join(RULES_BASE_PATH, MENU_FILE_NAME)
4037
fs.writeFileSync(menuFilePath, menu);
41-
console.info(`generated menu to ${menuFilePath}`)
38+
console.info(`generated menu to ${path.relative(process.cwd(), menuFilePath)}`);
4239
}
4340

4441
/**
@@ -52,11 +49,12 @@ function generateJsRuleStub (ruleName) {
5249
console.error('Please provide a rule name, e.g. "no-shared-handler-variables" as second argument');
5350
process.exit(1);
5451
}
55-
const stubFilePath = path.join(RULES_BASE_PATH, ruleName + '.md');
52+
const stubFilePath = path.join(RULES_BASE_PATH, ruleName, 'index.md');
5653
if (fs.existsSync(stubFilePath)) {
5754
console.error(`file ${stubFilePath} already exists, will not overwrite`);
5855
process.exit(2);
5956
}
57+
fs.mkdirSync(path.dirname(stubFilePath), { recursive: true });
6058
const stub = fs.readFileSync(path.join(import.meta.dirname, 'js-rule-stub.md'), 'utf-8').replaceAll('$RULE_NAME', ruleName);
6159
fs.writeFileSync(stubFilePath, stub);
6260
console.info(`generated stub to ${stubFilePath}`);

.github/eslint-plugin/js-rule-stub.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ status: released
33
---
44

55
<script setup>
6-
import PlaygroundBadge from '../components/PlaygroundBadge.vue'
6+
import PlaygroundBadge from '../../components/PlaygroundBadge.vue'
77
</script>
88

99
# $RULE_NAME
@@ -22,7 +22,7 @@ This rule was introduced in `@sap/eslint-plugin-cds x.y.z`.
2222
DESCRIPTION OF CORRECT EXAMPLE
2323

2424
::: code-group
25-
<<< ../examples/$RULE_NAME/correct/srv/admin-service.js#snippet{js:line-numbers} [srv/admin-service.js]
25+
<<< correct/srv/admin-service.js#snippet{js:line-numbers} [srv/admin-service.js]
2626
:::
2727
<PlaygroundBadge
2828
name="$RULE_NAME"
@@ -35,7 +35,7 @@ DESCRIPTION OF CORRECT EXAMPLE
3535
DESCRIPTION OF INCORRECT EXAMPLE
3636

3737
::: code-group
38-
<<< ../examples/$RULE_NAME/incorrect/srv/admin-service.js#snippet{js:line-numbers} [srv/admin-service.js]
38+
<<< incorrect/srv/admin-service.js#snippet{js:line-numbers} [srv/admin-service.js]
3939
:::
4040
<PlaygroundBadge
4141
name="$RULE_NAME"

tools/cds-lint/components/PlaygroundBadge.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ interface Props {
1111
withDefaults(defineProps<Props>(), { nolink: false })
1212
import { compress, prettyStringify } from './eslint-online-playground/utils';
1313
// @ts-ignore
14-
import { data } from '../examples/examples.data.ts';
14+
import { data } from '../rules/examples.data.ts';
1515
1616
const configFileName = "eslint.config.js";
1717
const packageJsonFileName = "package.json";
@@ -29,7 +29,7 @@ export default [
2929
3030
const defaultPackageJson = JSON.parse(data['package.json']);
3131
32-
const is_object = x => typeof x === 'object' && x !== null && !Array.isArray(x)
32+
const is_object = (x:any) => typeof x === 'object' && x !== null && !Array.isArray(x)
3333
function merge (o:any,...xs:any) {
3434
let v:any; for (let x of xs) for (let k in x)
3535
if (k === '__proto__' || k === 'constructor') continue //> avoid prototype pollution

tools/cds-lint/examples/no-shared-handler-variable/correct/srv/admin-service.js

Lines changed: 0 additions & 21 deletions
This file was deleted.

tools/cds-lint/examples/no-shared-handler-variable/incorrect/srv/admin-service.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

tools/cds-lint/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ To turn on lint checking in your VS Code Editor simply download the [ESLint exte
5858
CDS Lint seamlessly integrates with it. For _SAP Business Application Studio_ this comes preinstalled.
5959

6060
Now you can see lint reports also in your editor. You can see all rules [marked as **Editor default** here](./rules/). Any other (project-based) rules are not turned on by
61-
default but can be turned on via the `show` rule option. For example, if we want to show the [`valid-csv-header`](./rules/valid-csv-header) rule reports in the Editor, we would add the following to our ESLint
61+
default but can be turned on via the `show` rule option. For example, if we want to show the [`valid-csv-header`](./rules/valid-csv-header/) rule reports in the Editor, we would add the following to our ESLint
6262
`rules` configuration:
6363

6464
```json

tools/cds-lint/rules/_menu.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
# [assoc2many-ambiguous-key](assoc2many-ambiguous-key)
2-
# [auth-no-empty-restrictions](auth-no-empty-restrictions)
3-
# [auth-restrict-grant-service](auth-restrict-grant-service)
4-
# [auth-use-requires](auth-use-requires)
5-
# [auth-valid-restrict-grant](auth-valid-restrict-grant)
6-
# [auth-valid-restrict-keys](auth-valid-restrict-keys)
7-
# [auth-valid-restrict-to](auth-valid-restrict-to)
8-
# [auth-valid-restrict-where](auth-valid-restrict-where)
9-
# [case-sensitive-well-known-events](case-sensitive-well-known-events)
10-
# [extension-restrictions](extension-restrictions)
11-
# [latest-cds-version](latest-cds-version)
12-
# [no-cross-service-import](no-cross-service-import)
13-
# [no-db-keywords](no-db-keywords)
14-
# [no-deep-sap-cds-import](no-deep-sap-cds-import)
15-
# [no-dollar-prefixed-names](no-dollar-prefixed-names)
16-
# [no-java-keywords](no-java-keywords)
17-
# [no-join-on-draft](no-join-on-draft)
18-
# [no-shared-handler-variable](no-shared-handler-variable)
19-
# [sql-cast-suggestion](sql-cast-suggestion)
20-
# [sql-null-comparison](sql-null-comparison)
21-
# [start-elements-lowercase](start-elements-lowercase)
22-
# [start-entities-uppercase](start-entities-uppercase)
23-
# [use-cql-select-template-strings](use-cql-select-template-strings)
24-
# [valid-csv-header](valid-csv-header)
1+
# [assoc2many-ambiguous-key](assoc2many-ambiguous-key/)
2+
# [auth-no-empty-restrictions](auth-no-empty-restrictions/)
3+
# [auth-restrict-grant-service](auth-restrict-grant-service/)
4+
# [auth-use-requires](auth-use-requires/)
5+
# [auth-valid-restrict-grant](auth-valid-restrict-grant/)
6+
# [auth-valid-restrict-keys](auth-valid-restrict-keys/)
7+
# [auth-valid-restrict-to](auth-valid-restrict-to/)
8+
# [auth-valid-restrict-where](auth-valid-restrict-where/)
9+
# [case-sensitive-well-known-events](case-sensitive-well-known-events/)
10+
# [extension-restrictions](extension-restrictions/)
11+
# [latest-cds-version](latest-cds-version/)
12+
# [no-cross-service-import](no-cross-service-import/)
13+
# [no-db-keywords](no-db-keywords/)
14+
# [no-deep-sap-cds-import](no-deep-sap-cds-import/)
15+
# [no-dollar-prefixed-names](no-dollar-prefixed-names/)
16+
# [no-java-keywords](no-java-keywords/)
17+
# [no-join-on-draft](no-join-on-draft/)
18+
# [no-shared-handler-variable](no-shared-handler-variable/)
19+
# [sql-cast-suggestion](sql-cast-suggestion/)
20+
# [sql-null-comparison](sql-null-comparison/)
21+
# [start-elements-lowercase](start-elements-lowercase/)
22+
# [start-entities-uppercase](start-entities-uppercase/)
23+
# [use-cql-select-template-strings](use-cql-select-template-strings/)
24+
# [valid-csv-header](valid-csv-header/)

tools/cds-lint/rules/assoc2many-ambiguous-key.md renamed to tools/cds-lint/rules/assoc2many-ambiguous-key/index.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ status: released
77
---
88

99
<script setup>
10-
import PlaygroundBadge from '../components/PlaygroundBadge.vue'
10+
import PlaygroundBadge from '../../components/PlaygroundBadge.vue'
1111
</script>
1212

1313
# assoc2many-ambiguous-key
1414

1515
## Rule Details
1616

17-
An [association/composition to/of `MANY`](../../../cds/cdl#to-many-associations) that targets an entity without an `ON` condition is not allowed because it is an `n:1` relationship. Always specify an `ON` condition following the canonical expression pattern `<assoc>.<backlink> = $self`. The backlink can be any managed to-one association on the many side pointing back to the one side.
17+
An [association/composition to/of `MANY`](../../../../cds/cdl#to-many-associations) that targets an entity without an `ON` condition is not allowed because it is an `n:1` relationship. Always specify an `ON` condition following the canonical expression pattern `<assoc>.<backlink> = $self`. The backlink can be any managed to-one association on the many side pointing back to the one side.
1818

1919
## Examples
2020

@@ -23,7 +23,7 @@ An [association/composition to/of `MANY`](../../../cds/cdl#to-many-associations)
2323
In the following example, we define a unique association from `Authors` to `Books` with a well-defined `ON` condition and backlink, thus satisfying the rule's conditions:
2424

2525
::: code-group
26-
<<< ../examples/assoc2many-ambiguous-key/correct/db/schema.cds#snippet{cds:line-numbers} [db/schema.cds]
26+
<<< correct/db/schema.cds#snippet{cds:line-numbers} [db/schema.cds]
2727
:::
2828
<PlaygroundBadge
2929
name="assoc2many-ambiguous-key"
@@ -37,7 +37,7 @@ In the following example, we define a unique association from `Authors` to `Book
3737
If you extend this example by creating a view `AuthorView` with a key `ID` and the element `bookIDs` without an `ON` condition, the rule is triggered because the key is no longer unique and `bookIDs` leads to multiple entries:
3838

3939
::: code-group
40-
<<< ../examples/assoc2many-ambiguous-key/incorrect/db/schema.cds#snippet{cds:line-numbers} [db/schema.cds]
40+
<<< incorrect/db/schema.cds#snippet{cds:line-numbers} [db/schema.cds]
4141
:::
4242
<PlaygroundBadge
4343
name="assoc2many-ambiguous-key"

0 commit comments

Comments
 (0)