Skip to content

Commit

Permalink
feat(config): add support for restrictionKeys
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieu-crouzet committed Dec 17, 2024
1 parent ebd320a commit 6e353c9
Show file tree
Hide file tree
Showing 13 changed files with 418 additions and 3 deletions.
6 changes: 6 additions & 0 deletions apps/showcase/eslint.local.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export default [
}
}
}
],
'@o3r/o3r-restriction-key-tags': [
'error',
{
supportedKeys: ['restriction_1', 'restriction 2']
}
]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export interface ConfigurationPresConfig extends Configuration {
* @o3rWidgetParam allDestinationsDifferent true
* @o3rWidgetParam atLeastOneDestinationAvailable true
* @o3rWidgetParam destinationPattern "[A-Z][a-zA-Z-' ]+"
* @o3rRestrictionKey restriction_1
* @o3rRestrictionKey "restriction 2"
*/
destinations: DestinationConfiguration[];
/**
Expand Down
64 changes: 64 additions & 0 deletions docs/linter/eslint-plugin/rules/o3r-restriction-key-tags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# @o3r/o3r-restriction-key-tags

Ensures that `@o3rRestrictionKey` are used with correct value.

**Warning** This rule must be configured to be used.

## How to use

```json
{
"@o3r/o3r-widget-tags": [
"error",
{
"supportedInterfaceNames": ["NestedConfiguration", "Configuration", "CustomConfigurationInterface"],
"supportedKeys": ["restriction_1", "restriction 2"]
}
]
}
```

## Valid code example

```typescript
export interface ConfigExample extends Configuration {
/**
* @o3rRestrictionKey restriction_1
*/
prop1: string;
/**
* @o3rRestrictionKey restriction_1
* @o3rRestrictionKey "restriction 2"
*/
prop2: string;
}
```

## Invalid code example

```typescript
export interface ConfigExample extends Configuration {
/**
* @o3rRestrictionKey restriction 2
*/
prop: string;
}
```

```typescript
export interface ConfigExample extends Configuration {
/**
* @o3rRestrictionKey unknownRestriction
*/
prop: string | number;
}
```

```typescript
export interface Example {
/**
* @o3rRestrictionKey restriction_1
*/
prop: string;
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ export class ComponentConfigExtractor {
const res: ConfigProperty = {
description: configDocInfo?.description || '',
category: configDocInfo?.category,
restrictionKeys: configDocInfo?.restrictionKeys,
label: configDocInfo?.label || name.replace(/([A-Z])/g, ' $1'),
name,
type: 'unknown',
Expand Down
2 changes: 2 additions & 0 deletions packages/@o3r/components/src/core/component.output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export interface ConfigProperty {
widget?: ConfigPropertyWidget;
/** If true, the CMS user must specify a value for the property */
required?: boolean;
/** Restriction keys */
restrictionKeys?: string[];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@
"items": {
"type": "string"
}
},
"restrictionKeys": {
"type": "array",
"description": "Restriction keys",
"items": {
"type": "string"
}
}
},
"allOf": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
'jsdoc/check-tag-names': [
'warn',
{
definedTags: ['note', 'title', 'o3rCategory', 'o3rCategories', 'o3rWidget', 'o3rWidgetParam', 'o3rRequired']
definedTags: ['note', 'title', 'o3rRestrictionKey', 'o3rCategory', 'o3rCategories', 'o3rWidget', 'o3rWidgetParam', 'o3rRequired']
}
],
'jsdoc/check-types': 'warn',
Expand Down
2 changes: 1 addition & 1 deletion packages/@o3r/eslint-config/src/rules/typescript/jsdoc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const config = [
'jsdoc/check-tag-names': [
'error',
{
definedTags: ['note', 'title', 'o3rCategory', 'o3rCategories', 'o3rWidget', 'o3rWidgetParam', 'o3rRequired']
definedTags: ['note', 'title', 'o3rRestrictionKey', 'o3rCategory', 'o3rCategories', 'o3rWidget', 'o3rWidgetParam', 'o3rRequired']
}
],
'jsdoc/no-defaults': 'off',
Expand Down
4 changes: 3 additions & 1 deletion packages/@o3r/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import matchingConfigurationName from './rules/typescript/matching-configuration
import noFolderImportForModule from './rules/typescript/no-folder-import-for-module/no-folder-import-for-module';
import noMultipleTypeConfigurationProperty from './rules/typescript/no-multiple-type-configuration-property/no-multiple-type-configuration-property';
import o3rCategoriesTags from './rules/typescript/o3r-categories-tags/o3r-categories-tags';
import o3rRestrictionKeyTags from './rules/typescript/o3r-restriction-key-tags/o3r-restriction-key-tags';
import o3rWidgetTags from './rules/typescript/o3r-widget-tags/o3r-widget-tags';
import yarnrcPackageExtensionHarmonize from './rules/yaml/yarnrc-package-extensions-harmonize/yarnrc-package-extensions-harmonize';

Expand All @@ -18,7 +19,8 @@ module.exports = {
'matching-configuration-name': matchingConfigurationName,
'yarnrc-package-extensions-harmonize': yarnrcPackageExtensionHarmonize,
'no-multiple-type-configuration-property': noMultipleTypeConfigurationProperty,
'o3r-categories-tags': o3rCategoriesTags
'o3r-categories-tags': o3rCategoriesTags,
'o3r-restriction-key-tags': o3rRestrictionKeyTags
},
configs: {
'@o3r/no-folder-import-for-module': 'error',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import o3rRestrictionKeyRule, {
O3rRestrictionKeyTagsRuleOption,
} from './o3r-restriction-key-tags';
const {
RuleTester
} = require('@typescript-eslint/rule-tester');

const ruleTester = new RuleTester();

const code = `
export interface Config extends Configuration {
/**
* @o3rRestrictionKey valid
* @o3rRestrictionKey valid_with_underscore
* @o3rRestrictionKey 'valid with space (single quote)'
* @o3rRestrictionKey "valid with space (double quote)"
* @o3rRestrictionKey '"valid" with double quote inside'
* @o3rRestrictionKey "'valid' with single quote inside"
* @o3rRestrictionKey valid_with_number_1
*/
prop: string;
}
`;

const supportedKeys = [
'valid',
'valid_with_underscore',
'valid with space',
'valid with space (single quote)',
'valid with space (double quote)',
'"valid" with double quote inside',
"'valid' with single quote inside",
'valid_with_number_1'
];

const options = [{ supportedKeys }] as const satisfies Readonly<[O3rRestrictionKeyTagsRuleOption]>;

const unknownKeys = [
`unknown_restriction`,
`"invalid quote'`,
`'another invalid quote"`,
`'unknown with single quote'`,
`"unknown with double quote"`
];

const getCodeFor = (key: string) => `
export interface Config extends Configuration {
/**
* @o3rRestrictionKey ${key}
*/
prop: string;
}
`;

const getSuggestionFor = (actualKey: string) => supportedKeys.map((supportedKey) => ({
messageId: 'suggestUseSupportedKey',
data: {
actualKey,
supportedKey
},
output: getCodeFor(/[^\w]/.test(supportedKey) ? `"${supportedKey}"` : supportedKey)
}));

ruleTester.run('o3r-restriction-key-tags', o3rRestrictionKeyRule, {
valid: [
{
code,
options
},
{
code: `
export interface Config extends Configuration {
/**
* Property without restriction
*/
prop: string;
}`,
options
}
],
invalid: [
{
code: getCodeFor('"at least one key provided"'),
options: [{}],
errors: [
{ messageId: 'noRestrictionKeyProvided' }
]
},
{
code: code.replace(' extends Configuration', ''),
options,
errors: [
{
messageId: 'notInConfigurationInterface'
}
]
},
{
code: getCodeFor('valid with space'),
options,
output: getCodeFor(`"valid with space"`),
errors: [
{
messageId: 'notWrapWithQuotes',
data: {
actualKey: 'valid with space'
},
suggestions: [{
messageId: 'suggestWrapWithQuotes',
data: {
actualKey: 'valid with space'
},
output: getCodeFor(`"valid with space"`)
}]
}
]
},
...unknownKeys.map((key) => ({
code: getCodeFor(key),
options,
errors: [{
messageId: 'notSupportedKey',
data: {
actualKey: key,
supportedKeys: supportedKeys.join(', ')
},
suggestions: getSuggestionFor(key)
}]
}))
]
});
Loading

0 comments on commit 6e353c9

Please sign in to comment.