@accordproject/concerto-linter 1.0.0

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.
Files changed (64) hide show
  1. package/.eslintignore +20 -0
  2. package/.eslintrc.yml +45 -0
  3. package/HEADER.md +2 -0
  4. package/README.md +207 -0
  5. package/default-ruleset/.eslintignore +20 -0
  6. package/default-ruleset/.eslintrc.yml +45 -0
  7. package/default-ruleset/README.md +300 -0
  8. package/default-ruleset/jest.config.js +7 -0
  9. package/default-ruleset/package.json +51 -0
  10. package/default-ruleset/src/abstract-must-subclassed.ts +29 -0
  11. package/default-ruleset/src/camel-case-properties.ts +35 -0
  12. package/default-ruleset/src/functions/check-length-validator.ts +52 -0
  13. package/default-ruleset/src/functions/find-abstract-declaration.ts +70 -0
  14. package/default-ruleset/src/functions/find-empty-declarations.ts +56 -0
  15. package/default-ruleset/src/namespace-version.ts +35 -0
  16. package/default-ruleset/src/no-empty-declarations.ts +31 -0
  17. package/default-ruleset/src/no-reserved-keywords.ts +43 -0
  18. package/default-ruleset/src/pascal-case-declarations.ts +35 -0
  19. package/default-ruleset/src/pascal-case-decorators.ts +38 -0
  20. package/default-ruleset/src/ruleset-main.ts +41 -0
  21. package/default-ruleset/src/string-length-validator.ts +32 -0
  22. package/default-ruleset/src/upper-snake-case-enum-const.ts +36 -0
  23. package/default-ruleset/test/fixtures/ENUM_Constans-invaild.cto +7 -0
  24. package/default-ruleset/test/fixtures/ENUM_Constans-vaild.cto +7 -0
  25. package/default-ruleset/test/fixtures/abstract-must-subclassed-invalid.cto +10 -0
  26. package/default-ruleset/test/fixtures/abstract-must-subclassed-valid.cto +18 -0
  27. package/default-ruleset/test/fixtures/declarations-valid-PascalCase.cto +21 -0
  28. package/default-ruleset/test/fixtures/declarations-violate-PascalCase.cto +22 -0
  29. package/default-ruleset/test/fixtures/decorators-valid-PascalCase.cto +8 -0
  30. package/default-ruleset/test/fixtures/decorators-violate-PascalCase.cto +8 -0
  31. package/default-ruleset/test/fixtures/namespace-invalid-version.cto +5 -0
  32. package/default-ruleset/test/fixtures/namespace-valid-version.cto +5 -0
  33. package/default-ruleset/test/fixtures/no-empty-declarations-invalid.cto +10 -0
  34. package/default-ruleset/test/fixtures/no-empty-declarations-valid.cto +16 -0
  35. package/default-ruleset/test/fixtures/no-reserved-keywords-invalid.cto +16 -0
  36. package/default-ruleset/test/fixtures/no-reserved-keywords-valid.cto +16 -0
  37. package/default-ruleset/test/fixtures/properties-valid-camelCase.cto +10 -0
  38. package/default-ruleset/test/fixtures/properties-violate-camelCase.cto +10 -0
  39. package/default-ruleset/test/fixtures/string-length-validator-invalid.cto +9 -0
  40. package/default-ruleset/test/fixtures/string-length-validator-valid.cto +10 -0
  41. package/default-ruleset/test/rules/abstract-must-subclassed.test.ts +33 -0
  42. package/default-ruleset/test/rules/namespace-version.test.ts +24 -0
  43. package/default-ruleset/test/rules/naming-ruleset.test.ts +133 -0
  44. package/default-ruleset/test/rules/no-empty-declarations.test.ts +33 -0
  45. package/default-ruleset/test/rules/no-reserved-keywords.test.ts +33 -0
  46. package/default-ruleset/test/rules/string-length-validator.test.ts +33 -0
  47. package/default-ruleset/test/test-rule.ts +30 -0
  48. package/default-ruleset/tsconfig.json +113 -0
  49. package/dist/config-loader.d.ts +6 -0
  50. package/dist/config-loader.js +52 -0
  51. package/dist/config-loader.js.map +1 -0
  52. package/dist/index.d.ts +32 -0
  53. package/dist/index.js +135 -0
  54. package/dist/index.js.map +1 -0
  55. package/jest.config.js +11 -0
  56. package/package.json +54 -0
  57. package/src/config-loader.ts +48 -0
  58. package/src/index.ts +173 -0
  59. package/test/unit/configLoader.test.ts +76 -0
  60. package/test/unit/formatResults.test.ts +149 -0
  61. package/test/unit/lintModel.test.ts +84 -0
  62. package/test/unit/loadRuleset.test.ts +64 -0
  63. package/tsconfig.build.json +4 -0
  64. package/tsconfig.json +113 -0
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@accordproject/concerto-linter-default-ruleset",
3
+ "version": "1.0.0",
4
+ "description": "Default ruleset for the Accord Project Concerto Linter",
5
+ "homepage": "https://github.com/accordproject/concerto",
6
+ "engines": {
7
+ "node": ">=18",
8
+ "npm": ">=10"
9
+ },
10
+ "main": "dist/ruleset-main.js",
11
+ "typings": "dist/ruleset-main.d.ts",
12
+ "scripts": {
13
+ "clean": "rimraf dist",
14
+ "prebuild": "npm-run-all clean",
15
+ "build": "tsc",
16
+ "pretest": "npm-run-all lint",
17
+ "lint": "eslint .",
18
+ "lint:fix": "eslint . --fix",
19
+ "test": "jest",
20
+ "test:watch": "jest --watchAll"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/accordproject/concerto.git",
25
+ "directory": "packages/concerto-linter/default-ruleset"
26
+ },
27
+ "keywords": [
28
+ "concerto",
29
+ "linter",
30
+ "spectral",
31
+ "default-ruleset"
32
+ ],
33
+ "author": "accordproject.org",
34
+ "license": "Apache-2.0",
35
+ "dependencies": {
36
+ "@accordproject/concerto-core": "3.21.0",
37
+ "@stoplight/spectral-core": "1.20.0",
38
+ "@stoplight/spectral-functions": "1.10.1",
39
+ "@stoplight/spectral-parsers": "1.0.5"
40
+ },
41
+ "devDependencies": {
42
+ "eslint": "8.57.1",
43
+ "@typescript-eslint/eslint-plugin": "^8.46.2",
44
+ "@typescript-eslint/parser": "^8.46.2",
45
+ "npm-run-all": "^4.1.5",
46
+ "rimraf": "^6.0.1",
47
+ "typescript": "5.7.2",
48
+ "jest": "^29.7.0",
49
+ "ts-jest": "^29.2.5"
50
+ }
51
+ }
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+ import { hasConcreteSubclass } from './functions/find-abstract-declaration';
15
+
16
+ /**
17
+ * Rule: Abstract Must Be Subclassed
18
+ * ---------------------------------
19
+ * Ensures that every abstract declaration in the model has at least one concrete subclass.
20
+ * This helps prevent unused or orphaned abstract types, enforcing better model design.
21
+ */
22
+ export default {
23
+ given: '$.models[*]',
24
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
25
+ then: {
26
+ function: hasConcreteSubclass,
27
+ },
28
+ };
29
+
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { casing } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: Camel Case Properties
19
+ * ---------------------------
20
+ * Ensures that properties of type String, Double, Integer, Long, DateTime, and Boolean
21
+ * are named using camelCase. This promotes consistency and readability in property naming
22
+ * conventions across the model.
23
+ */
24
+ export default {
25
+ description: 'Properties of type String, Double, Integer, Long, DateTime, Boolean should be camelCase.',
26
+ given: '$.models[*].declarations[?(@.$class && @.$class != "concerto.metamodel@1.0.0.EnumDeclaration")].properties[*].name',
27
+ message: 'Property \'{{value}}\' should be camelCase (e.g. \'myProperty\')',
28
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
29
+ then: {
30
+ function: casing,
31
+ functionOptions: {
32
+ type: 'camel',
33
+ },
34
+ },
35
+ };
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import type { IFunction, IFunctionResult } from '@stoplight/spectral-core';
16
+
17
+ interface StringLengthValidator {
18
+ $class: 'concerto.metamodel@1.0.0.StringLengthValidator';
19
+ minLength: number;
20
+ maxLength: number;
21
+ }
22
+
23
+ interface StringObject {
24
+ name: string;
25
+ lengthValidator?: StringLengthValidator;
26
+ }
27
+
28
+ /**
29
+ * Checks if a String object has a length validator.
30
+ *
31
+ * @param {unknown} targetVal The AST node to check, expected to be a StringProperty or StringScalar object.
32
+ * @returns {IFunctionResult[] | void} An array of results indicating declarations that lack a length validator.
33
+ * @throws {Error} If the input is not a valid object.
34
+ */
35
+ export const checkLengthValidator: IFunction = (targetVal): IFunctionResult[] => {
36
+ // Validate that targetVal is a non-null object
37
+ if (targetVal === null || typeof targetVal !== 'object') {
38
+ throw new Error('Input must be a valid String AST object.');
39
+ }
40
+
41
+ const stringObject = targetVal as StringObject;
42
+ const results: IFunctionResult[] = [];
43
+
44
+ // Check for missing length validator
45
+ if (!stringObject.lengthValidator) {
46
+ results.push({
47
+ message: `String '${stringObject.name}' must have a length validator.`,
48
+ });
49
+ }
50
+
51
+ return results;
52
+ };
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import type { IFunction, IFunctionResult } from '@stoplight/spectral-core';
16
+
17
+ interface Declaration {
18
+ name: string;
19
+ isAbstract?: boolean;
20
+ superType?: { name: string };
21
+ }
22
+
23
+ interface Model {
24
+ declarations: Declaration[];
25
+ }
26
+
27
+ /**
28
+ * Checks if each abstract declaration in the model has at least one concrete subclass.
29
+ *
30
+ * Iterates through the model's declarations, collects all abstract types,
31
+ * and removes any abstract type that is extended by a concrete subclass.
32
+ * Returns a result for each abstract type without a concrete subclass.
33
+ *
34
+ * @param {unknown} targetVal The AST model object containing declarations.
35
+ * @returns {IFunctionResult[] | void} An array of results for abstract declarations lacking concrete subclasses.
36
+ * @throws {Error} If the input is not a valid model AST.
37
+ */
38
+ export const hasConcreteSubclass: IFunction = (
39
+ targetVal,
40
+ ): IFunctionResult[] | void => {
41
+ const results: IFunctionResult[] = [];
42
+
43
+ // Validate that targetVal is a non-null object
44
+ if (typeof targetVal !== 'object' || !targetVal || !Array.isArray((targetVal as Model).declarations)) {
45
+ throw new Error(`${targetVal} must be a valid AST for concerto model`);
46
+ }
47
+
48
+ const abstractNames = new Map<string, number>();
49
+ const allDeclarations = (targetVal as Model).declarations;
50
+
51
+ for (const [index, decl] of allDeclarations.entries()) {
52
+ if (decl && decl.isAbstract && typeof decl.name === 'string') {
53
+ abstractNames.set(decl.name, index);
54
+ }
55
+ }
56
+
57
+ for (const decl of allDeclarations) {
58
+ if (decl && !decl.isAbstract && decl.superType && typeof decl.superType.name === 'string') {
59
+ abstractNames.delete(decl.superType.name);
60
+ }
61
+ }
62
+ if (abstractNames.size > 0) {
63
+ for (const [abstractName] of abstractNames) {
64
+ results.push({
65
+ message: `Abstract declaration '${abstractName}' must have concrete subclasses`,
66
+ });
67
+ }
68
+ }
69
+ return results;
70
+ };
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import type { IFunction, IFunctionResult } from '@stoplight/spectral-core';
16
+
17
+ interface Declaration {
18
+ name: string;
19
+ properties?: unknown[];
20
+ }
21
+
22
+ /**
23
+ * Finds and reports empty Concerto Declarations (i.e., declarations with no properties).
24
+ *
25
+ * @param {unknown} targetVal The AST node to check, expected to be a Concerto Declaration object.
26
+ * @returns {IFunctionResult[]} An array of results indicating declarations that are empty.
27
+ * @throws {Error} If the input is not a valid object.
28
+ */
29
+ export const findEmptyDeclarations: IFunction = (
30
+ targetVal,
31
+ ): IFunctionResult[] => {
32
+ const results: IFunctionResult[] = [];
33
+
34
+ // Validate that targetVal is a non-null object
35
+ if (typeof targetVal !== 'object' || targetVal === null) {
36
+ throw new Error('Value must be a valid AST object for a Concerto Declaration.');
37
+ }
38
+
39
+ // Ensure targetVal is a Declaration with a 'properties' field (not a scalar)
40
+ if (!(targetVal as Declaration).properties)
41
+ {
42
+ return results;
43
+ }
44
+
45
+ const declaration = targetVal as Declaration;
46
+ const properties = declaration.properties;
47
+
48
+ // If 'properties' is missing, not an array, or empty, report an error
49
+ if (!Array.isArray(properties) || properties.length === 0) {
50
+ results.push({
51
+ message: `Declaration '${declaration.name}' should not be empty and must declare at least one property.`,
52
+ });
53
+ }
54
+
55
+ return results;
56
+ };
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { pattern } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: Namespace Should Specify a Version
19
+ * ----------------------------------------
20
+ * Ensures that the namespace declaration in the model includes a version number.
21
+ * This rule enforces semantic versioning in namespaces, promoting clarity and compatibility management.
22
+ */
23
+ export default {
24
+ description: 'namespace should specify a version.',
25
+ given: '$.models[0].namespace',
26
+ message: 'namespace \'{{value}}\' should specify a version.',
27
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
28
+ then: {
29
+ function: pattern,
30
+ functionOptions: {
31
+ match: /@\d+\.\d+\.\d+/,
32
+ },
33
+ },
34
+ };
35
+
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { findEmptyDeclarations } from './functions/find-empty-declarations';
16
+
17
+ /**
18
+ * Rule: No Empty Declarations
19
+ * ---------------------------
20
+ * Detects and reports any model declarations that are empty.
21
+ * This rule helps maintain model integrity by ensuring that all declarations contain meaningful content,
22
+ * preventing the inclusion of unused or placeholder declarations in the model.
23
+ */
24
+ export default {
25
+ given: '$.models[*].declarations[*]',
26
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
27
+ then: {
28
+ function: findEmptyDeclarations
29
+ },
30
+ };
31
+
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { pattern } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: No Reserved Keywords with Declarations, Properties, and Decorators
19
+ *
20
+ * This rule enforces that names used for declarations, properties, and decorators
21
+ * in Concerto models do not use reserved keywords. Reserved keywords are language-specific
22
+ * terms that may cause conflicts or unexpected behavior if used as identifiers.
23
+ * If a name matches any of the reserved keywords (case-insensitive), the linter will
24
+ * report an error to prevent its usage.
25
+ */
26
+ export default {
27
+ description: 'Names should not be reserved words.',
28
+ given: [
29
+ '$.models[*].declarations[*].name',
30
+ '$.models[*].declarations[*].properties[*].name',
31
+ '$.models[*].decorators[*].name',
32
+ '$.models[*].declarations[*].decorators[*].name',
33
+ '$.models[*].declarations[*].properties[*].decorators[*].name'
34
+ ],
35
+ message: 'Name "{{value}}" is a reserved keyword.',
36
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
37
+ then: {
38
+ function: pattern,
39
+ functionOptions: {
40
+ notMatch: '/^(String|Double|Integer|Long|DateTime|Boolean|scalar|concept|enum|asset|participant|transaction|event|map|optional|length|regex|range|default)$/i'
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { casing } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: Pascal Case Declarations
19
+ * ------------------------------
20
+ * Ensures that declaration names (scalar, enum, concept, asset, participant, transaction, event)
21
+ * follow PascalCase naming convention (e.g., 'MyDeclaration').
22
+ * This promotes consistency and readability across model declarations.
23
+ */
24
+ export default {
25
+ description: 'Declaration names (scalar, enum, concept, asset, participant, transaction, event) should be PascalCase.',
26
+ given: '$.models[*].declarations[*].name',
27
+ message: 'Declaration \'{{value}}\' should be PascalCase (e.g. \'MyDeclaration\')',
28
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
29
+ then: {
30
+ function: casing,
31
+ functionOptions: {
32
+ type: 'pascal',
33
+ },
34
+ },
35
+ };
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { casing } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: Pascal Case Decorators
19
+ * ------------------------------
20
+ * Ensures that decorator names follow PascalCase naming convention (e.g., 'MyDecorator').
21
+ * This promotes consistency and readability across model decorators.
22
+ */
23
+ export default {
24
+ description: 'Decorators names should be PascalCase.',
25
+ given: [
26
+ '$.models[*].decorators[*].name',
27
+ '$.models[*].declarations[*].decorators[*].name',
28
+ '$.models[*].declarations[*].properties[*].decorators[*].name'
29
+ ],
30
+ message: 'Decorator \'{{value}}\' should be PascalCase (e.g. \'MyDecorator\')',
31
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
32
+ then: {
33
+ function: casing,
34
+ functionOptions: {
35
+ type: 'pascal',
36
+ },
37
+ },
38
+ };
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { RulesetDefinition } from '@stoplight/spectral-core';
16
+
17
+ import namespaceVersion from './namespace-version';
18
+ import pascalCaseDeclarations from './pascal-case-declarations';
19
+ import camelCaseProperties from './camel-case-properties';
20
+ import upperSnakeCaseEnumConst from './upper-snake-case-enum-const';
21
+ import pascalCaseDecorators from './pascal-case-decorators';
22
+ import stringLengthValidator from './string-length-validator';
23
+ import noReservedKeywords from './no-reserved-keywords';
24
+ import noEmptyDeclarations from './no-empty-declarations';
25
+ import abstractMustSubclassed from './abstract-must-subclassed';
26
+
27
+ const concertoRuleset: RulesetDefinition = {
28
+ rules: {
29
+ 'namespace-version': namespaceVersion,
30
+ 'no-reserved-keywords': noReservedKeywords,
31
+ 'pascal-case-declarations': pascalCaseDeclarations,
32
+ 'camel-case-properties': camelCaseProperties,
33
+ 'upper-snake-case-enum-constants': upperSnakeCaseEnumConst,
34
+ 'pascal-case-decorators': pascalCaseDecorators,
35
+ 'string-length-validator': stringLengthValidator,
36
+ 'no-empty-declarations': noEmptyDeclarations,
37
+ 'abstract-must-subclassed': abstractMustSubclassed,
38
+ }
39
+ };
40
+
41
+ export default concertoRuleset;
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { checkLengthValidator } from './functions/check-length-validator';
16
+
17
+ /**
18
+ * Rule: String Length
19
+ * ---------------------------
20
+ * Ensures that all string within the data model have a length validator applied.
21
+ * Which helps prevent inconsistent data length and ensure proper storage."
22
+ */
23
+ export default {
24
+ given: [
25
+ '$.models[*].declarations[?(@.$class=="concerto.metamodel@1.0.0.StringScalar")]',
26
+ '$.models[*].declarations[*].properties[?(@.$class=="concerto.metamodel@1.0.0.StringProperty")]'
27
+ ],
28
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
29
+ then: {
30
+ function: checkLengthValidator,
31
+ },
32
+ };
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { pattern } from '@stoplight/spectral-functions';
16
+
17
+ /**
18
+ * Rule: Enum Constants Must Use UPPER_SNAKE_CASE
19
+ * ----------------------------------------------
20
+ * Enforces that all enum constant names follow the UPPER_SNAKE_CASE convention.
21
+ * This rule checks each enum property name and reports an error if it does not match the required pattern.
22
+ * Ensures consistency and readability in enum naming across the model.
23
+ */
24
+ export default {
25
+
26
+ description: 'Enum constants must use UPPER_SNAKE_CASE.',
27
+ given: '$.models[*].declarations[?(@.$class == "concerto.metamodel@1.0.0.EnumDeclaration")].properties[*].name',
28
+ message: 'Enum constant \'{{value}}\' should be UPPER_SNAKE_CASE (e.g. \'MY_CONSTANT\')',
29
+ severity: 0, // 0 = error, 1 = warning, 2 = info, 3 = hint
30
+ then: {
31
+ function: pattern,
32
+ functionOptions: {
33
+ match: '^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$',
34
+ },
35
+ },
36
+ };
@@ -0,0 +1,7 @@
1
+ namespace org.example@1.0.0
2
+
3
+ enum MyCardSuit {
4
+ o Clubs
5
+ o DiamondsSuit
6
+ o hearts
7
+ }
@@ -0,0 +1,7 @@
1
+ namespace org.example@1.0.0
2
+
3
+ enum MyCardSuit {
4
+ o CLUBS
5
+ o DIAMONDS_SUIT
6
+ o HEARTS
7
+ }
@@ -0,0 +1,10 @@
1
+ namespace org.example@1.0.0
2
+
3
+ abstract concept Vehicle {
4
+ o String make
5
+ o String model
6
+ }
7
+
8
+ abstract asset Product {
9
+ o String productId
10
+ }
@@ -0,0 +1,18 @@
1
+ namespace org.example@1.0.0
2
+
3
+ abstract concept Vehicle {
4
+ o String make
5
+ o String model
6
+ }
7
+
8
+ concept Car extends Vehicle {
9
+ o Integer numberOfDoors
10
+ }
11
+
12
+ abstract asset Product {
13
+ o String productId
14
+ }
15
+
16
+ asset Electronics extends Product {
17
+ o String brand
18
+ }
@@ -0,0 +1,21 @@
1
+ namespace org.example@1.0.0
2
+
3
+ scalar SsnNumber extends String default="000-00-0000"
4
+
5
+ concept MyProduct {
6
+ }
7
+
8
+ asset PaymentOrder {
9
+ }
10
+
11
+ participant Customer {
12
+ }
13
+
14
+ transaction Order {
15
+ }
16
+
17
+ event LateDelivery {
18
+ }
19
+
20
+ enum Product {
21
+ }