From 19e6c331fd5ef32a4a44898bb02da8c9396cde77 Mon Sep 17 00:00:00 2001 From: Stefan Landgraf Date: Tue, 31 Dec 2024 12:27:09 +0100 Subject: [PATCH] tests green, linting works --- .github/ISSUE_TEMPLATE/bug_report.md | 23 ++ .github/ISSUE_TEMPLATE/feature_request.md | 11 + .github/ISSUE_TEMPLATE/question.md | 17 + eslint.config.mjs | 107 +++++- examples/swissrets-min.json | 30 ++ jest.config.js | 9 +- package-lock.json | 325 ++++++++++++++++++ package.json | 8 +- src/model/typescript/AdditionalOfferType.ts | 1 - src/model/typescript/Address.ts | 2 +- src/model/typescript/Category.ts | 1 - src/model/typescript/Deposit.ts | 2 +- src/model/typescript/Event.ts | 1 - src/model/typescript/Heating.ts | 4 +- .../typescript/JsonSchemaSwissRetsJson.ts | 5 +- src/model/typescript/Organization.ts | 4 +- src/model/typescript/Project.ts | 16 +- src/model/typescript/ProjectAttachment.ts | 8 +- src/model/typescript/ProjectAvailability.ts | 2 +- src/model/typescript/ProjectLocalization.ts | 2 +- src/model/typescript/ProjectPriceBuy.ts | 2 +- src/model/typescript/ProjectPriceRent.ts | 4 +- src/model/typescript/ProjectPrices.ts | 4 +- src/model/typescript/ProjectSeller.ts | 4 +- src/model/typescript/Property.ts | 31 +- src/model/typescript/PropertyAttachment.ts | 8 +- src/model/typescript/PropertyAvailability.ts | 2 +- .../typescript/PropertyCharacteristics.ts | 2 +- src/model/typescript/PropertyLocalization.ts | 4 +- src/model/typescript/PropertyPriceBuy.ts | 2 +- src/model/typescript/PropertyPriceRent.ts | 4 +- src/model/typescript/PropertyPrices.ts | 10 +- src/model/typescript/PropertySeller.ts | 5 +- src/model/typescript/Publisher.ts | 5 +- src/model/typescript/SwissRetsInventory.ts | 6 +- src/model/typescript/Unit.ts | 4 +- src/model/typescript/Utilization.ts | 1 - src/tests/schema-validation.spec.ts | 92 +++++ src/tests/schemaValidation.spec.ts | 10 - .../should-fail/availability-missing.json | 25 ++ src/tests/should-fail/empty.json | 1 - src/tests/should-fail/localization-empty.json | 25 ++ .../localization-lang-missing.json | 29 ++ .../should-fail/localization-missing.json | 24 ++ .../localization-title-missing.json | 29 ++ .../should-fail/property-id-missing.json | 29 ++ .../property-reference-id-missing.json | 29 ++ src/validator/typescript/custom-validation.ts | 10 +- src/validator/typescript/validator.ts | 14 +- tsconfig.json | 9 +- 50 files changed, 892 insertions(+), 110 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md create mode 100644 examples/swissrets-min.json create mode 100644 src/tests/schema-validation.spec.ts delete mode 100644 src/tests/schemaValidation.spec.ts create mode 100644 src/tests/should-fail/availability-missing.json delete mode 100644 src/tests/should-fail/empty.json create mode 100644 src/tests/should-fail/localization-empty.json create mode 100644 src/tests/should-fail/localization-lang-missing.json create mode 100644 src/tests/should-fail/localization-missing.json create mode 100644 src/tests/should-fail/localization-title-missing.json create mode 100644 src/tests/should-fail/property-id-missing.json create mode 100644 src/tests/should-fail/property-reference-id-missing.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..9901c0a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce / see the bug: +1. Go to '...' +2. Click on '....' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen / to see. + +**Videos / screenshots** +If applicable, add a video or screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..c38daec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,11 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Problem description** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]. How can others profit from the change. What's the main benefit. + +**Desired Solution** +A clear and concise description of what you want to happen. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..2fe9446 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,17 @@ +--- +name: Question +about: Ask something + +--- + +## Main topic + + + +- Technical understanding +- Missing documentation +- Contributing and community +- ... + +## Precise and short description of your question +_description_ diff --git a/eslint.config.mjs b/eslint.config.mjs index 2def383..bf9bb67 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,8 +1,111 @@ // @ts-check - +import eslint from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import jsonc from 'eslint-plugin-jsonc'; +import prettier from 'eslint-plugin-prettier'; +import prettierRecommended from 'eslint-plugin-prettier/recommended'; import tseslint from 'typescript-eslint'; export default tseslint.config( tseslint.configs.strict, tseslint.configs.recommended, -); \ No newline at end of file + + /***************************************************************************************** + * IGNORES + * --------------------------------------------------------------------------------------- + * GLOB patterns for files and directories to be ignored by ESLint completely. + * + * @see https://eslint.org/docs/latest/use/configure/ignore + *****************************************************************************************/ + { + ignores: ['**/.github/*', '**/node_modules/*', '**/dist/*', '**/package-lock.json'] + }, + + /***************************************************************************************** + * PROJECT CONFIGURATION + * --------------------------------------------------------------------------------------- + * These configurations are valid for all files, independent of their type. + * Type-specific adjustments are configured explicitly in specific sections individually. + * + * @see https://eslint.org/docs/latest/use/configure/plugins + * @see https://eslint.org/docs/latest/use/configure/parser + *****************************************************************************************/ + + // Default settings from prettier. + prettierRecommended, + + // Disable deprecated formatting rules. + // @see https://eslint.org/blog/2023/10/deprecating-formatting-rules/ + eslintConfigPrettier, + + // Default settings from eslint. + eslint.configs.recommended, + + // Default settings from TS. + ...tseslint.configs.recommended, + + // Default settings from jsonc. + ...jsonc.configs['flat/recommended-with-jsonc'], + + /***************************************************************************************** + * DEFAULT CONFIGURATION + * --------------------------------------------------------------------------------------- + * These rules and styles are valid for all code-files, independent of their type. + * Type-specific adjustments are configured explicitly in specific sections individually. + * + * @see https://eslint.org/docs/latest/use/configure/rules + *****************************************************************************************/ + { + plugins: { + prettier + }, + rules: { + // Prefer const over function. + 'func-style': ['error', 'expression'], + // Forbid relative imports. + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['./', '../'], + message: 'Relative imports are not allowed.' + } + ] + } + ], + // Disallow unused variables unless they are prefixed with "_" (e.g. _myVar). + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_' + } + ], + // Prettier configuration right here rather in a separate file. + // @see https://prettier.io/docs/en/options + 'prettier/prettier': [ + 'error', + { + singleQuote: true, + printWidth: 100, + trailingComma: 'none', + arrowParens: 'avoid' + } + ], + // Default 20. Enforce lower cyclomatic complexity. + complexity: ['error', 15], + // Default is 4. Enforce lower value for higher readability. + 'max-depth': ['error', 2], + // Default is 3. Allow 2 more parameters. + 'max-params': ['error', 5], + // Default is 10. Increase value explicitly. + 'max-statements': ['error', 25], + // Enforce the use of the shorthand syntax. + 'object-shorthand': 'error', + // Proper logger must be used instead of console.log. + 'no-console': 'error' + } + } +); diff --git a/examples/swissrets-min.json b/examples/swissrets-min.json new file mode 100644 index 0000000..d178aa1 --- /dev/null +++ b/examples/swissrets-min.json @@ -0,0 +1,30 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [ + { + "languageCode": "de", + "title": "Doppelhaushälfte" + } + ] + } + ] +} diff --git a/jest.config.js b/jest.config.js index 2561f85..b862385 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,9 +1,8 @@ -// jest.config.js -/** @type {import('ts-jest').JestConfigWithTsJest} */ +// eslint-disable-next-line no-undef module.exports = { preset: 'ts-jest', testMatch: ['**/*.spec.ts'], moduleNameMapper: { - '^src/(.*)$': '/src/$1', - }, -} \ No newline at end of file + '^src/(.*)$': '/src/$1' + } +}; diff --git a/package-lock.json b/package-lock.json index 95daaf9..9e1e9a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,10 @@ "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "eslint": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-jsonc": "^2.18.2", + "eslint-plugin-prettier": "^5.2.1", "jest": "^29.7.0", "ts-jest": "^29.2.5", "typescript": "^5.7.2", @@ -1185,6 +1189,19 @@ "node": ">= 8" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2317,6 +2334,197 @@ } } }, + "node_modules/eslint-compat-utils": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.4.tgz", + "integrity": "sha512-/u+GQt8NMfXO8w17QendT4gvO5acfxQsAKirAt0LVxDnr2N8YLCVbregaNc/Yhp7NM128DwCaRvr8PLDfeNkQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-json-compat-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/eslint-json-compat-utils/-/eslint-json-compat-utils-0.2.1.tgz", + "integrity": "sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.6.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": "*", + "jsonc-eslint-parser": "^2.4.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest": { + "version": "28.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.10.0.tgz", + "integrity": "sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsonc": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.18.2.tgz", + "integrity": "sha512-SDhJiSsWt3nItl/UuIv+ti4g3m4gpGkmnUJS9UWR3TrpyNsIcnJoBRD7Kof6cM4Rk3L0wrmY5Tm3z7ZPjR2uGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "eslint-compat-utils": "^0.6.0", + "eslint-json-compat-utils": "^0.2.1", + "espree": "^9.6.1", + "graphemer": "^1.4.0", + "jsonc-eslint-parser": "^2.0.4", + "natural-compare": "^1.4.0", + "synckit": "^0.6.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-jsonc/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsonc/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsonc/node_modules/synckit": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.6.2.tgz", + "integrity": "sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", @@ -2568,6 +2776,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -3863,6 +4078,69 @@ "node": ">=6" } }, + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/jsonc-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/jsonc-eslint-parser/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4329,6 +4607,36 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -4734,6 +5042,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", diff --git a/package.json b/package.json index a45a73c..c7fe763 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "doc": "docs" }, "scripts": { - "test:unit": "jest --config ./jest.config.js" + "test:unit": "jest --config ./jest.config.js", + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "repository": { "type": "git", @@ -31,6 +33,10 @@ "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "eslint": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-jest": "^28.10.0", + "eslint-plugin-jsonc": "^2.18.2", + "eslint-plugin-prettier": "^5.2.1", "jest": "^29.7.0", "ts-jest": "^29.2.5", "typescript": "^5.7.2", diff --git a/src/model/typescript/AdditionalOfferType.ts b/src/model/typescript/AdditionalOfferType.ts index a07d076..6ef7e94 100644 --- a/src/model/typescript/AdditionalOfferType.ts +++ b/src/model/typescript/AdditionalOfferType.ts @@ -1,4 +1,3 @@ - export enum AdditionalOfferType { ParkingCarport = 'parking-carport', ParkingDoubleGarage = 'parking-double-garage', diff --git a/src/model/typescript/Address.ts b/src/model/typescript/Address.ts index 5ae3a31..d8531cf 100644 --- a/src/model/typescript/Address.ts +++ b/src/model/typescript/Address.ts @@ -1,4 +1,4 @@ -import { Geo } from "./Geo"; +import { Geo } from 'src/model/typescript/Geo'; /** * Location of the property. diff --git a/src/model/typescript/Category.ts b/src/model/typescript/Category.ts index 487516b..a9ad440 100644 --- a/src/model/typescript/Category.ts +++ b/src/model/typescript/Category.ts @@ -1,4 +1,3 @@ - export enum Category { AdvertisingArea = 'advertising-area', AgriculturalLot = 'agricultural-lot', diff --git a/src/model/typescript/Deposit.ts b/src/model/typescript/Deposit.ts index c57faf2..2f09873 100644 --- a/src/model/typescript/Deposit.ts +++ b/src/model/typescript/Deposit.ts @@ -1,4 +1,4 @@ -import { DepositType } from "./DepositType"; +import { DepositType } from 'src/model/typescript/DepositType'; /** * Required amount of deposit. diff --git a/src/model/typescript/Event.ts b/src/model/typescript/Event.ts index 450803f..67db56f 100644 --- a/src/model/typescript/Event.ts +++ b/src/model/typescript/Event.ts @@ -1,4 +1,3 @@ - export interface Event { end: string; location?: string; diff --git a/src/model/typescript/Heating.ts b/src/model/typescript/Heating.ts index c54d603..fb53735 100644 --- a/src/model/typescript/Heating.ts +++ b/src/model/typescript/Heating.ts @@ -1,5 +1,5 @@ -import { HeatingDistribution } from "./HeatingDistribution"; -import { HeatingGeneration } from "./HeatingGeneration"; +import { HeatingDistribution } from 'src/model/typescript/HeatingDistribution'; +import { HeatingGeneration } from 'src/model/typescript/HeatingGeneration'; /** * The main heating system. diff --git a/src/model/typescript/JsonSchemaSwissRetsJson.ts b/src/model/typescript/JsonSchemaSwissRetsJson.ts index 918e11d..d81db46 100644 --- a/src/model/typescript/JsonSchemaSwissRetsJson.ts +++ b/src/model/typescript/JsonSchemaSwissRetsJson.ts @@ -1,6 +1,5 @@ -import { AdditionalOfferType } from "./AdditionalOfferType"; -import { Interval } from "./Interval"; - +import { AdditionalOfferType } from 'src/model/typescript/AdditionalOfferType'; +import { Interval } from 'src/model/typescript/Interval'; export interface JsonSchemaSwissRetsJson { interval?: Interval; diff --git a/src/model/typescript/Organization.ts b/src/model/typescript/Organization.ts index e3f4236..721a3e4 100644 --- a/src/model/typescript/Organization.ts +++ b/src/model/typescript/Organization.ts @@ -1,5 +1,5 @@ -import { Address } from "./Address"; -import { Website } from "./Website"; +import { Address } from 'src/model/typescript/Address'; +import { Website } from 'src/model/typescript/Website'; /** * The company selling diff --git a/src/model/typescript/Project.ts b/src/model/typescript/Project.ts index b40f9b6..5c5dbdc 100644 --- a/src/model/typescript/Project.ts +++ b/src/model/typescript/Project.ts @@ -1,11 +1,11 @@ -import { Unit } from "./Unit"; -import { ProjectSeller } from "./ProjectSeller"; -import { ProjectPrices } from "./ProjectPrices"; -import { ProjectLocalization } from "./ProjectLocalization"; -import { ConstructionStatus } from "./ConstructionStatus"; -import { ProjectCharacteristics } from "./ProjectCharacteristics"; -import { ProjectAvailability } from "./ProjectAvailability"; -import { Address } from "./Address"; +import { Address } from 'src/model/typescript/Address'; +import { ConstructionStatus } from 'src/model/typescript/ConstructionStatus'; +import { ProjectAvailability } from 'src/model/typescript/ProjectAvailability'; +import { ProjectCharacteristics } from 'src/model/typescript/ProjectCharacteristics'; +import { ProjectLocalization } from 'src/model/typescript/ProjectLocalization'; +import { ProjectPrices } from 'src/model/typescript/ProjectPrices'; +import { ProjectSeller } from 'src/model/typescript/ProjectSeller'; +import { Unit } from 'src/model/typescript/Unit'; /** * Building project container. diff --git a/src/model/typescript/ProjectAttachment.ts b/src/model/typescript/ProjectAttachment.ts index 823752d..8cdb1ee 100644 --- a/src/model/typescript/ProjectAttachment.ts +++ b/src/model/typescript/ProjectAttachment.ts @@ -1,7 +1,7 @@ -import { Logo } from "./Logo"; -import { Image } from "./Image"; -import { Document } from "./Document"; -import { Link } from "./Link"; +import { Document } from 'src/model/typescript/Document'; +import { Image } from 'src/model/typescript/Image'; +import { Link } from 'src/model/typescript/Link'; +import { Logo } from 'src/model/typescript/Logo'; /** * Sequence links, files, embeds and media. diff --git a/src/model/typescript/ProjectAvailability.ts b/src/model/typescript/ProjectAvailability.ts index 6d9b08f..62954e5 100644 --- a/src/model/typescript/ProjectAvailability.ts +++ b/src/model/typescript/ProjectAvailability.ts @@ -1,4 +1,4 @@ -import { State } from "./State"; +import { State } from 'src/model/typescript/State'; /** * Mutually exclusive lifecycle state. diff --git a/src/model/typescript/ProjectLocalization.ts b/src/model/typescript/ProjectLocalization.ts index cc15195..97563ff 100644 --- a/src/model/typescript/ProjectLocalization.ts +++ b/src/model/typescript/ProjectLocalization.ts @@ -1,4 +1,4 @@ -import { ProjectAttachment } from "./ProjectAttachment"; +import { ProjectAttachment } from 'src/model/typescript/ProjectAttachment'; /** * One for each language, a set of language specific content and texts. diff --git a/src/model/typescript/ProjectPriceBuy.ts b/src/model/typescript/ProjectPriceBuy.ts index c2c58a9..dc35dda 100644 --- a/src/model/typescript/ProjectPriceBuy.ts +++ b/src/model/typescript/ProjectPriceBuy.ts @@ -1,4 +1,4 @@ -import { Referring } from "./Referring"; +import { Referring } from 'src/model/typescript/Referring'; /** * One time buy prices. diff --git a/src/model/typescript/ProjectPriceRent.ts b/src/model/typescript/ProjectPriceRent.ts index 4d8a641..8ff7e31 100644 --- a/src/model/typescript/ProjectPriceRent.ts +++ b/src/model/typescript/ProjectPriceRent.ts @@ -1,5 +1,5 @@ -import { Interval } from "./Interval"; -import { Referring } from "./Referring"; +import { Interval } from 'src/model/typescript/Interval'; +import { Referring } from 'src/model/typescript/Referring'; /** * Recurring rental price. diff --git a/src/model/typescript/ProjectPrices.ts b/src/model/typescript/ProjectPrices.ts index 07027bc..37c1a87 100644 --- a/src/model/typescript/ProjectPrices.ts +++ b/src/model/typescript/ProjectPrices.ts @@ -1,5 +1,5 @@ -import { ProjectPriceRent } from "./ProjectPriceRent"; -import { ProjectPriceBuy } from "./ProjectPriceBuy"; +import { ProjectPriceBuy } from 'src/model/typescript/ProjectPriceBuy'; +import { ProjectPriceRent } from 'src/model/typescript/ProjectPriceRent'; /** * Price ranges for marketing purposes. diff --git a/src/model/typescript/ProjectSeller.ts b/src/model/typescript/ProjectSeller.ts index b48491b..6258114 100644 --- a/src/model/typescript/ProjectSeller.ts +++ b/src/model/typescript/ProjectSeller.ts @@ -1,5 +1,5 @@ -import { Organization } from "./Organization"; -import { Person } from "./Person"; +import { Organization } from 'src/model/typescript/Organization'; +import { Person } from 'src/model/typescript/Person'; /** * The owner or the owners substitute (for example a broker). diff --git a/src/model/typescript/Property.ts b/src/model/typescript/Property.ts index 447c3a5..6ca2e26 100644 --- a/src/model/typescript/Property.ts +++ b/src/model/typescript/Property.ts @@ -1,19 +1,18 @@ -import { Address } from "./Address"; -import { Development } from "./Development"; -import { ExternalReference } from "./ExternalReference"; -import { Heating } from "./Heating"; -import { PropertyLocalization } from "./PropertyLocalization"; -import { MinergieCertification } from "./MinergieCertification"; -import { PropertyPrices } from "./PropertyPrices"; -import { Publisher } from "./Publisher"; -import { PropertySeller } from "./PropertySeller"; -import { PropertyType } from "./PropertyType"; -import { Utilization } from "./Utilization"; -import { PropertyCharacteristics } from "./PropertyCharacteristics"; -import { Category } from "./Category"; -import { Bfs } from "./Bfs"; -import { PropertyAvailability } from "./PropertyAvailability"; - +import { Address } from 'src/model/typescript/Address'; +import { Bfs } from 'src/model/typescript/Bfs'; +import { Category } from 'src/model/typescript/Category'; +import { Development } from 'src/model/typescript/Development'; +import { ExternalReference } from 'src/model/typescript/ExternalReference'; +import { Heating } from 'src/model/typescript/Heating'; +import { MinergieCertification } from 'src/model/typescript/MinergieCertification'; +import { PropertyAvailability } from 'src/model/typescript/PropertyAvailability'; +import { PropertyCharacteristics } from 'src/model/typescript/PropertyCharacteristics'; +import { PropertyLocalization } from 'src/model/typescript/PropertyLocalization'; +import { PropertyPrices } from 'src/model/typescript/PropertyPrices'; +import { PropertySeller } from 'src/model/typescript/PropertySeller'; +import { PropertyType } from 'src/model/typescript/PropertyType'; +import { Publisher } from 'src/model/typescript/Publisher'; +import { Utilization } from 'src/model/typescript/Utilization'; export interface Property { /** diff --git a/src/model/typescript/PropertyAttachment.ts b/src/model/typescript/PropertyAttachment.ts index 7f93240..4f5cd38 100644 --- a/src/model/typescript/PropertyAttachment.ts +++ b/src/model/typescript/PropertyAttachment.ts @@ -1,7 +1,7 @@ -import { Document } from "./Document"; -import { Image } from "./Image"; -import { Link } from "./Link"; -import { Logo } from "./Logo"; +import { Document } from 'src/model/typescript/Document'; +import { Image } from 'src/model/typescript/Image'; +import { Link } from 'src/model/typescript/Link'; +import { Logo } from 'src/model/typescript/Logo'; /** * Sequence links, files, embeds and media. diff --git a/src/model/typescript/PropertyAvailability.ts b/src/model/typescript/PropertyAvailability.ts index 3ccab39..e736acd 100644 --- a/src/model/typescript/PropertyAvailability.ts +++ b/src/model/typescript/PropertyAvailability.ts @@ -1,4 +1,4 @@ -import { State } from "./State"; +import { State } from 'src/model/typescript/State'; /** * Mutually exclusive lifecycle state. diff --git a/src/model/typescript/PropertyCharacteristics.ts b/src/model/typescript/PropertyCharacteristics.ts index 51fd901..f60363b 100644 --- a/src/model/typescript/PropertyCharacteristics.ts +++ b/src/model/typescript/PropertyCharacteristics.ts @@ -1,4 +1,4 @@ -import { ApplicableType } from "./ApplicableType"; +import { ApplicableType } from 'src/model/typescript/ApplicableType'; /** * Main characteristics of properties diff --git a/src/model/typescript/PropertyLocalization.ts b/src/model/typescript/PropertyLocalization.ts index 5f23a6b..bdead65 100644 --- a/src/model/typescript/PropertyLocalization.ts +++ b/src/model/typescript/PropertyLocalization.ts @@ -1,5 +1,5 @@ -import { Event } from "./Event"; -import { PropertyAttachment } from "./PropertyAttachment"; +import { Event } from 'src/model/typescript/Event'; +import { PropertyAttachment } from 'src/model/typescript/PropertyAttachment'; /** * One for each language, a set of language specific content and texts. diff --git a/src/model/typescript/PropertyPriceBuy.ts b/src/model/typescript/PropertyPriceBuy.ts index efec523..dc7b2a6 100644 --- a/src/model/typescript/PropertyPriceBuy.ts +++ b/src/model/typescript/PropertyPriceBuy.ts @@ -1,4 +1,4 @@ -import { Referring } from "./Referring"; +import { Referring } from 'src/model/typescript/Referring'; /** * One time buy prices. diff --git a/src/model/typescript/PropertyPriceRent.ts b/src/model/typescript/PropertyPriceRent.ts index 4254375..46e8a5b 100644 --- a/src/model/typescript/PropertyPriceRent.ts +++ b/src/model/typescript/PropertyPriceRent.ts @@ -1,5 +1,5 @@ -import { Interval } from "./Interval"; -import { Referring } from "./Referring"; +import { Interval } from 'src/model/typescript/Interval'; +import { Referring } from 'src/model/typescript/Referring'; /** * Recurring rental price. diff --git a/src/model/typescript/PropertyPrices.ts b/src/model/typescript/PropertyPrices.ts index 7a4988a..13f63fd 100644 --- a/src/model/typescript/PropertyPrices.ts +++ b/src/model/typescript/PropertyPrices.ts @@ -1,8 +1,8 @@ -import { Auction } from "./Auction"; -import { Deposit } from "./Deposit"; -import { JsonSchemaSwissRetsJson } from "./JsonSchemaSwissRetsJson"; -import { PropertyPriceBuy } from "./PropertyPriceBuy"; -import { PropertyPriceRent } from "./PropertyPriceRent"; +import { Auction } from 'src/model/typescript/Auction'; +import { Deposit } from 'src/model/typescript/Deposit'; +import { JsonSchemaSwissRetsJson } from 'src/model/typescript/JsonSchemaSwissRetsJson'; +import { PropertyPriceBuy } from 'src/model/typescript/PropertyPriceBuy'; +import { PropertyPriceRent } from 'src/model/typescript/PropertyPriceRent'; /** * Sell, rent, deposit and auction prices. diff --git a/src/model/typescript/PropertySeller.ts b/src/model/typescript/PropertySeller.ts index e59365c..1e579cc 100644 --- a/src/model/typescript/PropertySeller.ts +++ b/src/model/typescript/PropertySeller.ts @@ -1,6 +1,5 @@ -import { Organization } from "./Organization"; -import { Person } from "./Person"; - +import { Organization } from 'src/model/typescript/Organization'; +import { Person } from 'src/model/typescript/Person'; export interface PropertySeller { /** diff --git a/src/model/typescript/Publisher.ts b/src/model/typescript/Publisher.ts index 67ad464..b18d5e9 100644 --- a/src/model/typescript/Publisher.ts +++ b/src/model/typescript/Publisher.ts @@ -1,6 +1,5 @@ -import { PublisherOption } from "./PublisherOption"; -import { PublisherPromotion } from "./PublisherPromotion"; - +import { PublisherOption } from 'src/model/typescript/PublisherOption'; +import { PublisherPromotion } from 'src/model/typescript/PublisherPromotion'; export interface Publisher { id: string; diff --git a/src/model/typescript/SwissRetsInventory.ts b/src/model/typescript/SwissRetsInventory.ts index 70fd5ef..e6f920b 100644 --- a/src/model/typescript/SwissRetsInventory.ts +++ b/src/model/typescript/SwissRetsInventory.ts @@ -1,6 +1,6 @@ -import { Property } from "./Property"; -import { Project } from "./Project"; -import { Generator } from "./Generator"; +import { Generator } from 'src/model/typescript/Generator'; +import { Project } from 'src/model/typescript/Project'; +import { Property } from 'src/model/typescript/Property'; /** * A product in the catalog diff --git a/src/model/typescript/Unit.ts b/src/model/typescript/Unit.ts index 9bde1d7..95ab88d 100644 --- a/src/model/typescript/Unit.ts +++ b/src/model/typescript/Unit.ts @@ -1,5 +1,5 @@ -import { UnitLocalization } from "./UnitLocalization"; -import { UnitCharacteristic } from "./UnitCharacteristic"; +import { UnitCharacteristic } from 'src/model/typescript/UnitCharacteristic'; +import { UnitLocalization } from 'src/model/typescript/UnitLocalization'; /** * A set of properties diff --git a/src/model/typescript/Utilization.ts b/src/model/typescript/Utilization.ts index c4f9be4..b0e100c 100644 --- a/src/model/typescript/Utilization.ts +++ b/src/model/typescript/Utilization.ts @@ -1,4 +1,3 @@ - export enum Utilization { Agricultural = 'agricultural', Commercial = 'commercial', diff --git a/src/tests/schema-validation.spec.ts b/src/tests/schema-validation.spec.ts new file mode 100644 index 0000000..b8a1fdc --- /dev/null +++ b/src/tests/schema-validation.spec.ts @@ -0,0 +1,92 @@ +import fs from 'fs'; +import path from 'path'; +import { ErrorDto, performSwissRetsSchemaValidation } from 'src/validator/typescript/validator'; + +const shouldFailPath = path.join(__dirname, 'should-fail'); +const shouldPassPath = path.join(__dirname, '..', '..', 'examples'); + +describe('Passing', () => { + it('should succeed for swissrets-full', () => { + const result = validatePassingFile('swissrets-full'); + expect(result.length).toEqual(0); + }); + + it('should succeed for swissrets-min', () => { + const result = validatePassingFile('swissrets-min'); + expect(result.length).toEqual(0); + }); +}); + +describe('Failing', () => { + it('should fail for fully invalid', () => { + const result = performSwissRetsSchemaValidation('{"foo": "bar"}'); + expect(result.length).toEqual(2); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'generator'"); + expect(result[1].keyword).toEqual('additionalProperties'); + expect(result[1].message).toEqual('must NOT have additional properties'); + }); + + it('should fail for availability-missing ', () => { + const result = validateFailingFile('availability-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'availability'"); + }); + + it('should fail for localization-lang-missing', () => { + const result = validateFailingFile('localization-lang-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'languageCode'"); + }); + + it('should fail for localization-title-missing', () => { + const result = validateFailingFile('localization-title-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'title'"); + }); + + it.skip('should fail for localization-empty', () => { + const result = validateFailingFile('localization-empty'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('TBD'); + expect(result[0].message).toEqual('TBD'); + }); + + it('should fail for localization-missing', () => { + const result = validateFailingFile('localization-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'localizations'"); + }); + + it('should fail for property-id-missing', () => { + const result = validateFailingFile('property-id-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'id'"); + }); + + it('should fail for property-reference-id-missing', () => { + const result = validateFailingFile('property-reference-id-missing'); + expect(result.length).toEqual(1); + expect(result[0].keyword).toEqual('required'); + expect(result[0].message).toEqual("must have required property 'referenceId'"); + }); +}); + +const validatePassingFile = (fileName: string): ErrorDto[] => { + const file = path.join(shouldPassPath, `${fileName}.json`); + const json = fs.readFileSync(file, { encoding: 'utf8' }); + const result = performSwissRetsSchemaValidation(json); + return result; +}; + +const validateFailingFile = (fileName: string): ErrorDto[] => { + const file = path.join(shouldFailPath, `${fileName}.json`); + const json = fs.readFileSync(file, { encoding: 'utf8' }); + const result = performSwissRetsSchemaValidation(json); + return result; +}; diff --git a/src/tests/schemaValidation.spec.ts b/src/tests/schemaValidation.spec.ts deleted file mode 100644 index b29f7bc..0000000 --- a/src/tests/schemaValidation.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { performSwissRetsSchemaValidation } from "../validator/typescript/validator"; - -it('should ', () => { - const result = performSwissRetsSchemaValidation('{"foo": "bar"}'); - expect(result.length).toEqual(2); - expect(result[0].keyword).toEqual('required'); - expect(result[0].message).toEqual("must have required property 'generator'"); - expect(result[1].keyword).toEqual('additionalProperties'); - expect(result[1].message).toEqual("must NOT have additional properties"); -}); \ No newline at end of file diff --git a/src/tests/should-fail/availability-missing.json b/src/tests/should-fail/availability-missing.json new file mode 100644 index 0000000..9bf462c --- /dev/null +++ b/src/tests/should-fail/availability-missing.json @@ -0,0 +1,25 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "localizations": [ + { + "languageCode": "de", + "title": "Doppelhaushälfte" + } + ] + } + ] +} diff --git a/src/tests/should-fail/empty.json b/src/tests/should-fail/empty.json deleted file mode 100644 index 9e26dfe..0000000 --- a/src/tests/should-fail/empty.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/src/tests/should-fail/localization-empty.json b/src/tests/should-fail/localization-empty.json new file mode 100644 index 0000000..ae2fc92 --- /dev/null +++ b/src/tests/should-fail/localization-empty.json @@ -0,0 +1,25 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [] + } + ] +} diff --git a/src/tests/should-fail/localization-lang-missing.json b/src/tests/should-fail/localization-lang-missing.json new file mode 100644 index 0000000..678e8e4 --- /dev/null +++ b/src/tests/should-fail/localization-lang-missing.json @@ -0,0 +1,29 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [ + { + "title": "Doppelhaushälfte" + } + ] + } + ] +} diff --git a/src/tests/should-fail/localization-missing.json b/src/tests/should-fail/localization-missing.json new file mode 100644 index 0000000..8a75702 --- /dev/null +++ b/src/tests/should-fail/localization-missing.json @@ -0,0 +1,24 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + } + } + ] +} diff --git a/src/tests/should-fail/localization-title-missing.json b/src/tests/should-fail/localization-title-missing.json new file mode 100644 index 0000000..399fe51 --- /dev/null +++ b/src/tests/should-fail/localization-title-missing.json @@ -0,0 +1,29 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [ + { + "languageCode": "de" + } + ] + } + ] +} diff --git a/src/tests/should-fail/property-id-missing.json b/src/tests/should-fail/property-id-missing.json new file mode 100644 index 0000000..3cca4fa --- /dev/null +++ b/src/tests/should-fail/property-id-missing.json @@ -0,0 +1,29 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "referenceId": "kj3kj3kj38ss", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [ + { + "languageCode": "de", + "title": "Doppelhaushälfte" + } + ] + } + ] +} diff --git a/src/tests/should-fail/property-reference-id-missing.json b/src/tests/should-fail/property-reference-id-missing.json new file mode 100644 index 0000000..1d742ad --- /dev/null +++ b/src/tests/should-fail/property-reference-id-missing.json @@ -0,0 +1,29 @@ +{ + "created": "2023-03-23T08:11:12Z", + "generator": { + "name": "CASAGATEWAY", + "version": "0.9" + }, + "properties": [ + { + "id": "amIuniqueOrAmI", + "type": "buy", + "address": { + "countryCode": "CH", + "locality": "Bern", + "postalCode": "3000" + }, + "availability": { + "state": "private", + "start": "2023-03-23T08:11:12Z", + "expiration": "2023-03-23T08:11:12Z" + }, + "localizations": [ + { + "languageCode": "de", + "title": "Doppelhaushälfte" + } + ] + } + ] +} diff --git a/src/validator/typescript/custom-validation.ts b/src/validator/typescript/custom-validation.ts index bff0eae..eabb1ab 100644 --- a/src/validator/typescript/custom-validation.ts +++ b/src/validator/typescript/custom-validation.ts @@ -7,7 +7,7 @@ export const allCustomValidators = (): KeywordDefinition[] => { const sameAsCustomValidator: KeywordDefinition = { keyword: 'sameAs', schema: false, - validate: function (value: unknown, root: unknown) { + validate(value: unknown, root: unknown) { // needed to add this because this custom validator takes precedence over the type check // @ts-expect-error - this is a custom validator if (!Array.isArray(root.rootData.projects)) { @@ -17,21 +17,21 @@ const sameAsCustomValidator: KeywordDefinition = { // @ts-expect-error - this is a custom validator return root.rootData.projects.some((obj: unknown) => // @ts-expect-error - this is a custom validator - obj.units?.some((item: unknown) => item.referenceId === value), + obj.units?.some((item: unknown) => item.referenceId === value) ); }, - errors: true, + errors: true }; const uniqueIdCustomValidator: KeywordDefinition = { keyword: 'uniqueId', schema: false, - validate: function (values: unknown) { + validate(values: unknown) { if (!values) { return false; } // @ts-expect-error - this is a custom validator return new Set(values.map((item: unknown) => item.referenceId)).size == values.length; }, - errors: true, + errors: true }; diff --git a/src/validator/typescript/validator.ts b/src/validator/typescript/validator.ts index fd8e305..02e5854 100644 --- a/src/validator/typescript/validator.ts +++ b/src/validator/typescript/validator.ts @@ -1,20 +1,21 @@ -import Ajv2020, { KeywordDefinition } from 'ajv/dist/2020'; import AjvFormats from 'ajv-formats'; +import Ajv2020, { KeywordDefinition } from 'ajv/dist/2020'; -import schema from '../../../schema/schema.json'; -import { allCustomValidators } from './custom-validation'; import { each } from 'lodash'; +import { allCustomValidators } from 'src/validator/typescript/custom-validation'; +// eslint-disable-next-line no-restricted-imports +import schema from '../../../schema/schema.json'; -export function performSwissRetsSchemaValidation(swissretsJson: string): ErrorDto[] { +export const performSwissRetsSchemaValidation = (swissretsJson: string): ErrorDto[] => { const ajv2020Instance = new Ajv2020({ allErrors: true, verbose: true }); AjvFormats(ajv2020Instance); each(allCustomValidators(), (item: KeywordDefinition) => ajv2020Instance.addKeyword(item)); - + ajv2020Instance.validate(schema, JSON.parse(swissretsJson)); return (ajv2020Instance.errors as unknown as ErrorDto[]) || []; -} +}; export interface ErrorDto, S = unknown> { keyword: K; @@ -48,4 +49,3 @@ interface _SchemaDto { $schema?: string; [x: string]: unknown; } - diff --git a/tsconfig.json b/tsconfig.json index 0b6aac5..47d6b1e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,9 +21,14 @@ "target": "es2022", // https://node.green/#ES2022 Node 18 supports all of es2022 // Completeness - "skipLibCheck": true // recommended + "skipLibCheck": true, // recommended + + // Modules + "paths": { + "src/*": ["./src/*"] + } }, // Top Level "include": ["src/**/*.ts", "global.d.ts"] -} \ No newline at end of file +}