Compare commits

...

35 Commits

Author SHA1 Message Date
Rainer Killinger
e934017a65 0.42.0 2021-02-16 14:04:40 +01:00
Rainer Killinger
88dbedd932 refactor: update dependenices 2021-02-15 10:57:25 +01:00
Rainer Killinger
8b1b3444fd refactor: align SCCreativeWork to schema.org spec 2021-02-15 10:37:43 +01:00
Rainer Killinger
d5f3d71a41 refactor: overhaul translator as mentioned in #118 2021-02-15 10:37:38 +01:00
wulkanat@gmail.com
cbcf9c9adb docs: update changelog 2021-02-08 14:59:21 +01:00
wulkanat@gmail.com
321e4f6f24 0.41.0 2021-02-08 14:59:14 +01:00
Wieland Schöbl
8510f11d7b fix: add date, numeric range filter to SCSearchFilter 2021-02-05 13:50:18 +01:00
wulkanat@gmail.com
68aa377fe2 docs: update changelog 2021-02-05 12:59:54 +01:00
wulkanat@gmail.com
29f2c77ecc 0.40.0 2021-02-05 12:59:47 +01:00
Wieland Schöbl
29bc00616e feat: add range filter, date sorting support 2021-02-02 15:07:49 +01:00
Rainer Killinger
02920af4a4 refactor: make SCDish additives translatable 2021-02-01 13:24:12 +00:00
Rainer Killinger
0c14b0f1a0 test: change SCSemester sample data acronym 2020-12-02 17:22:17 +01:00
Rainer Killinger
db0a239761 refactor: change SCSemester acronym pattern 2020-12-02 17:19:46 +01:00
Jovan Krunić
377f55bbbe docs: update changelog 2020-12-01 17:16:02 +01:00
Jovan Krunić
8d7a0e10c6 0.39.0 2020-12-01 17:16:01 +01:00
Rainer Killinger
4865f911d1 refactor: utilize null coalescing 2020-11-23 10:06:14 +01:00
Rainer Killinger
15ae5e0873 refactor: remove narrow property value translation 2020-11-23 10:06:14 +01:00
Rainer Killinger
a246bdea84 feat: extend property value translation retrival 2020-11-23 10:06:13 +01:00
Wieland Schöbl
8641bfc877 docs: add @inheritTags documentation 2020-11-11 11:40:36 +01:00
Michel Jonathan Schmitz
d34e66fbbc docs: update changelog 2020-11-02 09:06:11 +01:00
Michel Jonathan Schmitz
c6273a85d9 0.38.1 2020-11-02 08:57:41 +01:00
Michel Jonathan Schmitz
5558d29c2b ci: remove caching 2020-10-30 15:01:00 +01:00
Michel Jonathan Schmitz
69dfd1ae39 build: replace deprecated dependencies 2020-10-30 09:50:46 +01:00
Michel Jonathan Schmitz
4638bb3684 build: update dependencies 2020-10-30 09:50:46 +01:00
Michel Jonathan Schmitz
6c687c6004 docs: update changelog 2020-10-30 09:49:52 +01:00
Michel Jonathan Schmitz
0bf1301733 0.38.0 2020-10-30 09:46:46 +01:00
Wieland Schöbl
827ba47892 refactor: swap out jsonschema package for json-schema 2020-10-29 15:14:25 +01:00
wulkanat@gmail.com
d3b620a745 docs: update changelog 2020-09-23 06:09:23 +02:00
wulkanat@gmail.com
821834cfa0 0.37.0 2020-09-23 06:09:13 +02:00
Wieland Schöbl
c369c8520a fix: remove keyword tag from steps 2020-09-09 18:12:32 +02:00
Rainer Killinger
66075ef99b fix: remove redundant property declaration 2020-09-02 06:38:14 +00:00
Rainer Killinger
7a6333aa8f test: bump branch coverage limit 2020-08-31 13:52:41 +02:00
Rainer Killinger
e242a21e99 refactor: update dependencies, remove extraneous 2020-08-31 13:52:39 +02:00
Rainer Killinger
6fecd1e89d refactor: update ts-optchain dependency 2020-08-26 12:51:10 +02:00
Sebastian Lange
f6a93e668b docs: update changelog 2020-07-16 11:37:58 +02:00
27 changed files with 2371 additions and 2884 deletions

View File

@@ -1,10 +1,5 @@
image: registry.gitlab.com/openstapps/projectmanagement/node
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules
before_script:
- npm install

5
.mailmap Normal file
View File

@@ -0,0 +1,5 @@
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <git@killinger.co>
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <killinge@hrz.uni-frankfurt.de>
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <killinger@hrz.uni-frankfurt.de>
Wieland Schöbl <wulkanat@gmail.com> wulkanat@gmail.com <wulkanat@gmail.com>
Wieland Schöbl <wulkanat@gmail.com> Wieland Schöbl <wieland.schoebl@campus.tu-berlin.de>

View File

@@ -1,3 +1,57 @@
# [0.41.0](https://gitlab.com/openstapps/core/compare/v0.40.0...v0.41.0) (2021-02-08)
### Bug Fixes
* add date, numeric range filter to SCSearchFilter ([8510f11](https://gitlab.com/openstapps/core/commit/8510f11d7b4c62a6b239a70f47fe07e8cc86ab63))
# [0.40.0](https://gitlab.com/openstapps/core/compare/v0.39.0...v0.40.0) (2021-02-05)
### Features
* add range filter, date sorting support ([29bc006](https://gitlab.com/openstapps/core/commit/29bc00616e87a8d346d8c304fab2e3818921c75e))
# [0.39.0](https://gitlab.com/openstapps/core/compare/v0.38.1...v0.39.0) (2020-12-01)
### Features
* extend property value translation retrival ([a246bde](https://gitlab.com/openstapps/core/commit/a246bdea84e0ca390be6ab38723d637626db87d2))
## [0.38.1](https://gitlab.com/openstapps/core/compare/v0.38.0...v0.38.1) (2020-11-02)
# [0.38.0](https://gitlab.com/openstapps/core/compare/v0.37.0...v0.38.0) (2020-10-30)
# [0.37.0](https://gitlab.com/openstapps/core/compare/v0.36.0...v0.37.0) (2020-09-23)
### Bug Fixes
* remove keyword tag from steps ([c369c85](https://gitlab.com/openstapps/core/commit/c369c8520a2eed169555a35a50ce745c08e1f9da))
* remove redundant property declaration ([66075ef](https://gitlab.com/openstapps/core/commit/66075ef99b95198a9cd5c0a396603e089221bcd9))
# [0.36.0](https://gitlab.com/openstapps/core/compare/v0.35.0...v0.36.0) (2020-07-16)
### Features
* add function to get translated SCThingType ([fe7f1a5](https://gitlab.com/openstapps/core/commit/fe7f1a53ae46e052e23f1b39851f1547b5a8dded))
# [0.35.0](https://gitlab.com/openstapps/core/compare/v0.34.0...v0.35.0) (2020-05-13)

View File

@@ -35,16 +35,18 @@ node --require ts-node/register src/cli.ts routes PATH/TO/ROUTES.md
Annotations are used to add additional informations to fields, which are used to autogenerate mappings from the core objects.
External dependencies can not be covered by the annotations. Documentation about some of the annotations can be found in: [typedoc](https://typedoc.org/guides/doccomments/)
| annotation | description | parameters |
|-------------------|-------------------------------------------|---------------|
| annotation | description | parameters |
|-------------------|-------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
| `@aggregatable` | used for generating of aggregations of the field if the core schema is used to put data into a database/key-value store | whether the property is being used on the top type or across all types: `global` |
| `@float` | number field is interpreted as float | |
| `@indexable` | marks the type as indexable if the core schema is used to put data into a database/key-value store| |
| `@integer` | number field is interpreted as integer | |
| `@keyword` | string field is interpreted as keyword | |
| `@sortable` | field is sortable if the core schema is used to put data into a database/key-value store | sort method to be used: `ducet`, `price`, `distance` |
| `@text` | string field is interpreted as text | |
| `@validatable` | marks the type as validatable if the core schema is used to put data into a database/key-value store | |
| `@filterable` | non-object/nested field is filterable if the core schema is used to put data into a database/key-value store | |
| `@float` | number field is interpreted as float | |
| `@indexable` | marks the type as indexable if the core schema is used to put data into a database/key-value store | |
| `@integer` | number field is interpreted as integer | |
| `@keyword` | string field is interpreted as keyword | |
| `@sortable` | field is sortable if the core schema is used to put data into a database/key-value store. Fields are always sortable through generic sort, even without annotation. | sort method to be used: `ducet`, `price`, `distance` |
| `@text` | string field is interpreted as text | |
| `@date` | string field is interpreted as a date field | |
| `@validatable` | marks the type as validatable if the core schema is used to put data into a database/key-value store | |
| `@filterable` | non-object/nested field is filterable if the core schema is used to put data into a database/key-value store | |
| `@inheritTags` | inherit all tags from another field | `[SCThingType]::[field]` |
*Note: tags ignore casing, but for consistency they should use the variants proposed here.*

4518
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@openstapps/core",
"version": "0.36.0",
"version": "0.42.0",
"description": "StAppsCore - Generalized model of data",
"keywords": [
"Model",
@@ -25,56 +25,57 @@
"preversion": "npm run prepublishOnly",
"push": "git push && git push origin \"v$npm_package_version\"",
"schema": "node --max-old-space-size=8192 --stack-size=10240 ./node_modules/.bin/openstapps-core-tools schema src lib/schema",
"test": "nyc mocha --require ts-node/register --require source-map-support/register --ui mocha-typescript test/*.spec.ts",
"test": "nyc mocha --require ts-node/register --recursive 'test/*.spec.ts'",
"tslint": "tslint -p tsconfig.json -c tslint.json 'src/**/*.ts'"
},
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
"contributors": [
"Andreas Lehmann",
"Anselm Stordeur <anselmstordeur@gmail.com>",
"Axel Nieder-Vahrenholz",
"Benjamin Jöckel",
"Imran Hossain",
"Frank Nagel",
"Jovan Krunić <jovan.krunic@gmail.com>",
"Michel Jonathan Schmitz",
"Rainer Killinger <mail-openstapps@killinger.co>",
"Roman Klopsch",
"Sebastian Lange",
"Wieland Schöbl",
"Roman Klopsch"
"Wieland Schöbl"
],
"dependencies": {
"@openstapps/core-tools": "0.17.0",
"@types/geojson": "1.0.6",
"@types/json-patch": "0.0.30",
"@types/node": "10.17.14",
"@types/json-schema": "7.0.7",
"@types/node": "10.17.44",
"fast-clone": "1.5.13",
"http-status-codes": "1.4.0",
"fast-deep-equal": "3.1.3",
"http-status-codes": "2.1.4",
"json-patch": "0.7.0",
"jsonschema": "1.2.5",
"ts-optchain": "0.1.3"
"json-schema": "0.2.5",
"ts-optchain": "0.1.8"
},
"devDependencies": {
"@krlwlfrt/async-pool": "0.1.0",
"@openstapps/configuration": "0.23.0",
"@openstapps/core-tools": "0.14.0",
"@openstapps/logger": "0.4.0",
"@types/chai": "4.2.8",
"@types/rimraf": "2.0.3",
"chai": "4.2.0",
"commander": "2.20.0",
"@openstapps/configuration": "0.25.0",
"@openstapps/logger": "0.5.0",
"@testdeck/mocha": "0.1.2",
"@types/chai": "4.2.15",
"@types/rimraf": "3.0.0",
"chai": "4.3.0",
"conditional-type-checks": "1.0.5",
"conventional-changelog-cli": "2.0.31",
"mocha": "6.2.0",
"mocha-typescript": "1.1.17",
"nyc": "14.1.1",
"conventional-changelog-cli": "2.1.1",
"mocha": "8.3.0",
"nyc": "15.1.0",
"rimraf": "3.0.2",
"source-map-support": "0.5.13",
"ts-node": "8.6.2",
"tslint": "5.18.0",
"typedoc": "0.14.2",
"typescript": "3.5.3"
"source-map-support": "0.5.19",
"ts-node": "9.1.1",
"tslint": "6.1.3",
"typedoc": "0.18.0",
"typescript": "3.8.3"
},
"nyc": {
"all": true,
"branches": 85,
"branches": 90,
"check-coverage": true,
"exclude": [],
"extension": [

View File

@@ -18,6 +18,8 @@
*
* @pattern ^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$
* @see https://gist.github.com/philipashlock/8830168
*
* @date
*/
export type SCISO8601Date = string;
/* tslint:enable */

View File

@@ -12,8 +12,8 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {ValidationError} from '@openstapps/core-tools/lib/common';
import {BAD_REQUEST} from 'http-status-codes';
import {ValidationError} from 'jsonschema';
import {SCError} from '../error';
/**

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {OK} from 'http-status-codes';
import {Schema} from 'jsonschema';
import {JSONSchema7} from 'json-schema';
import {SCInternalServerErrorResponse} from '../errors/internal-server-error';
import {SCMethodNotAllowedErrorResponse} from '../errors/method-not-allowed';
import {SCNotFoundErrorResponse} from '../errors/not-found';
@@ -78,12 +78,12 @@ export interface SCPluginMetaData {
/**
* How the requests of the plugin looks like, a JSON schema for validation
*/
requestSchema: Schema;
requestSchema: JSONSchema7;
/**
* How the responses of the plugin looks like, a JSON schema for validation
*/
responseSchema: Schema;
responseSchema: JSONSchema7;
/**
* The desired route, for example /feedback.

View File

@@ -19,6 +19,7 @@ import {SCMap} from '../../general/map';
import {SCSearchAvailabilityFilter} from './filters/availability';
import {SCSearchBooleanFilter} from './filters/boolean';
import {SCSearchDistanceFilter} from './filters/distance';
import {SCSearchDateRangeFilter, SCSearchNumericRangeFilter} from './filters/range';
import {SCSearchValueFilter} from './filters/value';
/**
@@ -28,7 +29,9 @@ export type SCSearchFilterType =
'availability'
| 'boolean'
| 'distance'
| 'value';
| 'value'
| 'date range'
| 'numeric range';
/**
* Structure of a filter instruction
@@ -57,4 +60,6 @@ export type SCSearchFilter =
SCSearchAvailabilityFilter
| SCSearchBooleanFilter
| SCSearchDistanceFilter
| SCSearchValueFilter;
| SCSearchValueFilter
| SCSearchNumericRangeFilter
| SCSearchDateRangeFilter;

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2020 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCThingsField} from '../../../meta';
import {SCSearchAbstractFilter, SCSearchAbstractFilterArguments} from '../filter';
/**
* A date range filter
*
* Filter for documents with a date field that satisfies the given constraints
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-range-query.html#_date_format_in_range_queries
*/
export interface SCSearchDateRangeFilter extends SCSearchAbstractFilter<SCDateRangeFilterArguments> {
/**
* @see SCSearchAbstractFilter.type
*/
type: 'date range';
}
/**
* A distance filter
*
* Filter for documents with a numeric field that satisfies the given constraints
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-range-query.html#query-dsl-range-query
*/
export interface SCSearchNumericRangeFilter extends SCSearchAbstractFilter<SCNumericRangeFilterArguments> {
/**
* @see SCSearchAbstractFilter.type
*/
type: 'numeric range';
}
/**
* Additional arguments for date range filters
*
* Filter uses a plain string to allow for date math expressions
* @see https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/date-math-expressions.html
*/
export interface SCDateRangeFilterArguments extends SCRangeFilterArguments<string> {
/**
* Optional date format specifier
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-range-query.html#_date_format_in_range_queries
*/
format?: string;
/**
* Optional timezone specifier
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-range-query.html#_time_zone_in_range_queries
*/
timeZone?: string;
}
/**
* Additional arguments for numeric range filters
*/
export type SCNumericRangeFilterArguments = SCRangeFilterArguments<number>;
/**
* Additional arguments for range filters
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-range-query.html#query-dsl-range-query
*/
export interface SCRangeFilterArguments<T> extends SCSearchAbstractFilterArguments {
/**
* Bounds of the range
*/
bounds: Bounds<T>;
/**
* Field where the filter will be applied
*/
field: SCThingsField;
}
export interface Bounds<T> {
/**
* The lower bound
*/
lowerBound?: Bound<T>;
/**
* The upper bound
*/
upperBound?: Bound<T>;
}
export interface Bound<T> {
/**
* Limit of the bound
*/
limit: T;
/**
* Bound mode
*/
mode: 'inclusive' | 'exclusive';
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 StApps
* Copyright (C) 2019, 2020 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -16,6 +16,7 @@ import {SCMap} from '../../general/map';
import {SCThingsField} from '../../meta';
import {SCDistanceSort} from './sorts/distance';
import {SCDucetSort} from './sorts/ducet';
import {SCGenericSort} from './sorts/generic';
import {SCPriceSort} from './sorts/price';
/**
@@ -51,9 +52,9 @@ export interface SCSearchAbstractSortArguments extends SCMap<unknown> {
/**
* Type of a sort instruction
*/
export type SCSearchSortType = 'distance' | 'price' | 'ducet';
export type SCSearchSortType = 'distance' | 'price' | 'ducet' | 'generic';
/**
* A sort instruction
*/
export type SCSearchSort = SCDistanceSort | SCPriceSort | SCDucetSort;
export type SCSearchSort = SCDistanceSort | SCPriceSort | SCDucetSort | SCGenericSort;

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2020 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCSearchAbstractSort, SCSearchAbstractSortArguments} from '../sort';
/**
* Sort instruction for generic sort such as date
*/
export interface SCGenericSort extends SCSearchAbstractSort<SCSearchAbstractSortArguments> {
/**
* @see SCSearchAbstractSort.type
*/
type: 'generic';
}

View File

@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCLanguage, SCMetaTranslations, SCTranslations} from '../../general/i18n';
import {SCLanguageCode, SCMetaTranslations, SCTranslations} from '../../general/i18n';
import {SCISO8601Date} from '../../general/time';
import {SCOrganizationWithoutReferences} from '../organization';
import {SCPersonWithoutReferences} from '../person';
@@ -30,6 +30,12 @@ import {
*/
export interface SCCreativeWorkWithoutReferences
extends SCThingWithoutReferences, SCThingThatCanBeOfferedWithoutReferences {
/**
* Languages this creative work is available in
*/
availableLanguages?: SCLanguageCode[];
/**
* Date the creative work was published
*
@@ -38,9 +44,11 @@ export interface SCCreativeWorkWithoutReferences
datePublished?: SCISO8601Date;
/**
* List of languages this creative work is written/recorded/... in
* Languages this creative work is written/recorded/... in
*
* @filterable
*/
inLanguages?: SCLanguage[];
inLanguage?: SCLanguageCode;
/**
* Keywords of the creative work
@@ -103,9 +111,10 @@ export class SCCreativeWorkMeta
de: {
...SCThingMeta.getInstance<SCThingMeta>().fieldTranslations.de,
...SCThingThatCanBeOfferedMeta.getInstance().fieldTranslations.de,
authors: 'Authoren',
authors: 'Autoren',
availableLanguages: 'verfügbare Übersetzungen',
datePublished: 'Veröffentlichungsdatum',
inLanguages: 'verfügbare Übersetzungen',
inLanguage: 'Inhaltssprache',
keywords: 'Schlagwörter',
publishers: 'Verleger',
},
@@ -113,8 +122,9 @@ export class SCCreativeWorkMeta
...SCThingMeta.getInstance<SCThingMeta>().fieldTranslations.en,
...SCThingThatCanBeOfferedMeta.getInstance().fieldTranslations.en,
authors: 'authors',
availableLanguages: 'available languages',
datePublished: 'release date',
inLanguages: 'available Languages',
inLanguage: 'content language',
keywords: 'keywords',
publishers: 'publishers',
},

View File

@@ -41,15 +41,6 @@ export type SCBuildingCategories =
export interface SCBuildingWithoutReferences
extends SCThingWithCategoriesWithoutReferences<SCBuildingCategories, SCThingWithCategoriesSpecificValues>,
SCPlaceWithoutReferences {
/**
* Categories of a building
*
* @sortable ducet
* @aggregatable
* @filterable
*/
categories: SCBuildingCategories[];
/**
* List of floor names of the place
*

View File

@@ -43,15 +43,6 @@ export interface SCDishWithoutReferences
*/
additives?: string[];
/**
* Category of the dish
*
* @sortable ducet
* @aggregatable
* @filterable
*/
categories: SCDishCategories[];
/**
* Characteristics of the dish
*/
@@ -100,6 +91,13 @@ export interface SCDish
export interface SCDishTranslatableProperties
extends SCThingWithCategoriesTranslatableProperties, SCThingThatCanBeOfferedTranslatableProperties {
/**
* Additives of the dish
*
* @filterable
* @keyword
*/
additives?: string[];
/**
* Characteristics of the dish
*/

View File

@@ -29,7 +29,7 @@ export interface SCSemesterWithoutReferences
* The short name of the semester, using the given pattern.
*
* @filterable
* @pattern ^(WS|SS) [0-9]{4}(/[0-9]{2})?$
* @pattern ^(WS|SS|WiSe|SoSe) [0-9]{4}(/[0-9]{2})?$
* @keyword
*/
acronym: string;

View File

@@ -27,10 +27,6 @@ import {
*/
export interface SCSettingWithoutReferences
extends SCThingWithCategoriesWithoutReferences<SCSettingCategories, SCThingWithCategoriesSpecificValues> {
/**
* Categories of a setting
*/
categories: SCSettingCategories[];
/**
* The default value of a setting
*/

View File

@@ -29,8 +29,6 @@ export interface SCTourWithoutReferences
/**
* Steps of a tour
*
* @keyword
*/
steps: SCTourStep[];

View File

@@ -13,8 +13,9 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import clone = require('fast-clone');
import {Defined, OCType} from 'ts-optchain';
import {SCTranslations} from './general/i18n';
import equal = require('fast-deep-equal/es6');
import {Defined, TSOCType} from 'ts-optchain';
import {SCLanguageCode} from './general/i18n';
import {isThing} from './guards';
import {SCClasses} from './meta';
import {SCThing, SCThingType} from './things/abstract/thing';
@@ -27,13 +28,32 @@ const standardCacheSize = 200;
*/
export class SCThingTranslator {
/**
* Getter for language property
*/
get language(): SCLanguageCode {
return this._language;
}
/**
* Setter for language property. Also flushes translation cache
*
* @param language The language the translator instance will use from now on
*/
set language(language: SCLanguageCode) {
if (language !== this._language) {
this.cache.flush();
}
this._language = language;
}
/**
* Property representing the translators target language
*/
private _language: keyof SCTranslations<SCThing>;
private _language: SCLanguageCode;
/**
* Property representing the translators base language
* This means every translation is given for this language
* LRU cache containing already translated SCThings
*/
private readonly cache: LRUCache<SCThing>;
@@ -42,46 +62,33 @@ export class SCThingTranslator {
*/
private readonly metaClasses: typeof SCClasses;
/**
* LRU cache containing SCThings translations have been provided for
*/
private readonly sourceCache: LRUCache<SCThing>;
/**
* @example
* // returns translator instance for german
* new SCThingTranslator('de');
*/
constructor(language: keyof SCTranslations<SCThing>, cacheCapacity: number = standardCacheSize) {
constructor(language: SCLanguageCode, cacheCapacity: number = standardCacheSize) {
this.cache = new LRUCache(cacheCapacity);
this.sourceCache = new LRUCache(cacheCapacity);
this._language = language;
this.metaClasses = SCClasses;
}
/**
* Getter for language property
*/
get language(): keyof SCTranslations<SCThing> {
return this._language;
}
/**
* Setter for language property. Also flushes translation cache
*
* @param language The language the translator instance will use from now on
*/
set language(language: keyof SCTranslations<SCThing>) {
if (language !== this._language) {
this.cache.flush();
}
this._language = language;
}
/**
* Get field value translation recursively
*
* @param data The intermediate object / primitive returned by the Proxys get() method
* @returns an OCType<T> object allowing for access to translations or a translated value(s)
* @returns an TSOCType<T> object allowing for access to translations or a translated value(s)
*/
// tslint:disable-next-line:prefer-function-over-method
private deeptranslate<T>(data?: T): OCType<T> {
private deeptranslate<T>(data?: T): TSOCType<T> {
const proxy = new Proxy(
((defaultValue?: Defined<T>) => (data == null ? defaultValue : data)) as OCType<T>,
((defaultValue?: Defined<T>) => (data == null ? defaultValue : data)) as TSOCType<T>,
{
get: (target, key) => {
const obj: any = target();
@@ -101,8 +108,8 @@ export class SCThingTranslator {
* @param language The language the thing property values are translated to
* @returns The thing with all known meta values translated
*/
private getAllMetaFieldTranslations<T extends SCThing>(thingType: SCThingType,
language: keyof SCTranslations<T>): object | undefined {
private getAllMetaFieldTranslations(thingType: SCThingType,
language: SCLanguageCode): object | undefined {
const fieldTranslations = {};
const metaClass = this.getMetaClassInstance(thingType);
if (typeof metaClass === 'undefined') {
@@ -151,7 +158,7 @@ export class SCThingTranslator {
* @returns The thing with translated meta field values
*/
private replaceAvailableMetaFieldValueTranslations(instance: any,
language: keyof SCTranslations<any>): any {
language: SCLanguageCode): any {
const metaClass = this.getMetaClassInstance(instance.type);
if (typeof metaClass === 'undefined') {
return instance;
@@ -181,6 +188,60 @@ export class SCThingTranslator {
return instance;
}
/**
* Recursively translates the given object in-place
* Translated values overwrite current values (destructive)
*
* @param instance The thing / object that will be translated
* @returns The thing translated
*/
private translateThingInPlaceDestructively<T>(instance: T): T {
const targetLanguage = this.language;
let nextInstance = instance as any;
// Recursively call this function on all nested SCThings, arrays and objects
Object.keys(nextInstance)
.forEach((key) => {
if (
isThing(nextInstance[key]) ||
nextInstance[key] instanceof Array ||
nextInstance[key] instanceof Object) {
nextInstance[key] = this.translateThingInPlaceDestructively(nextInstance[key]);
}
});
// Spread variable translations given by the connector into thing
if (typeof nextInstance.translations?.[targetLanguage] !== 'undefined') {
nextInstance = {...nextInstance, ...nextInstance.translations![targetLanguage]} as T;
}
// Spread known translations from meta classes into (partly) translated thing
this.replaceAvailableMetaFieldValueTranslations(nextInstance, targetLanguage);
return nextInstance;
}
/**
* Recursively translates the given object in-place
* Translated values overwrite current values (destructive)
*
* @param instance The thing / object that will be translated
* @returns The thing translated
*/
public translate<T extends SCThing>(thing: T): T {
if (equal(this.sourceCache.get(thing), thing)) {
const cachedInstance = this.cache.get(thing);
if (typeof cachedInstance !== 'undefined') {
return cachedInstance as T;
}
}
const translatedInstance = this.translateThingInPlaceDestructively(clone(thing));
delete translatedInstance.translations;
this.cache.putObject(translatedInstance);
this.sourceCache.putObject(thing);
return translatedInstance as T;
}
/**
* Get field value translation recursively
* @example
@@ -189,23 +250,26 @@ export class SCThingTranslator {
* // or
* const dishTranslatedAccess = translator.translate(dish);
* dishTranslatedAccess.offers[0].inPlace.categories[1]();
* // undoing the OCType<T>
* // undoing the TSOCType<T>
* const dishAsBefore: SCDish = dishTranslatedAccess()!;
* @param data Top level object that gets passed through the recursion
* @returns an OCType<T> object allowing for access to translations or a translated value(s)
* @param thing Top level object that gets passed through the recursion
* @returns an TSOCType<T> object allowing for access to translations or a translated value(s)
*/
public translate<T extends SCThing>(data: T): OCType<T> {
public translatedAccess<T extends SCThing>(thing: T): TSOCType<T> {
return new Proxy(
((defaultValue?: Defined<T>) => (data == null ? defaultValue : data)) as OCType<T>,
((defaultValue?: Defined<T>) => (thing == null ? defaultValue : thing)) as TSOCType<T>,
{
get: (target, key) => {
const obj: any = target();
const objTranslatedFromCache = this.cache.get(data);
if (typeof objTranslatedFromCache !== 'undefined') {
return this.deeptranslate((objTranslatedFromCache as any)[key]);
if (equal(this.sourceCache.get(thing), thing)) {
const objTranslatedFromCache = this.cache.get(thing);
if (typeof objTranslatedFromCache !== 'undefined') {
return this.deeptranslate((objTranslatedFromCache as any)[key]);
}
}
const objTranslated = this.translateWholeThingDestructively(clone(obj));
const objTranslated = this.translateThingInPlaceDestructively(clone(obj));
this.cache.putObject(objTranslated);
this.sourceCache.putObject(thing);
return this.deeptranslate(objTranslated[key]);
},
@@ -219,71 +283,31 @@ export class SCThingTranslator {
* @example
* const translatedMetaDish = translator.translatedPropertyNames<SCCourseOfStudies>(SCThingType.CourseOfStudies);
* @param type The type whose property names will be translated
* @param language The language all property names will be translated to
* @returns An object with the properties of the SCThingType where the values are the known property tranlations
*/
public translatedPropertyNames<T extends SCThing>(type: SCThingType,
language?: keyof SCTranslations<T>): T | undefined {
const targetLanguage = (typeof language !== 'undefined') ? language : this.language;
return this.getAllMetaFieldTranslations(type, targetLanguage) as T;
public translatedPropertyNames<T extends SCThing>(type: SCThingType): T | undefined {
return this.getAllMetaFieldTranslations(type, this.language) as T;
}
/**
* Given a SCThingType this function will translate it
*
* @param type The type that will be translated
* @param language The language the type will be translated to
* @returns Known translation of type parameter
* Given a SCThingType and a corresponding property name it returns the known property value translation
* Access pattern to the meta object containing the translation can be thought of as type.field[key] with key being optional
* @example
* const singleValueTranslation = translator.translatedPropertyValue(SCThingType.Dish, 'categories', 'main dish');
* @param type The type for whose property values a translation is required
* @param field The property for which a translation is required
* @param key If specified tries to access the field with this key
* @returns Known translation for the property
*/
public translatedThingType<T extends unknown>(type: SCThingType,
language?: keyof SCTranslations<T>): string {
const targetLanguage = (typeof language !== 'undefined') ? language : this.language;
const metaClass = this.getMetaClassInstance(type);
public translatedPropertyValue(type: SCThingType,
field: string,
key?: string): string | undefined {
const fieldValueTranslations = this.getMetaClassInstance(type).fieldValueTranslations[this.language] ??
this.getMetaClassInstance(type).fieldValueTranslations.en;
const fieldTranslation = fieldValueTranslations?.[field];
if (typeof metaClass.fieldValueTranslations[targetLanguage] !== 'undefined' &&
typeof metaClass.fieldValueTranslations[targetLanguage].type !== 'undefined') {
return metaClass.fieldValueTranslations[targetLanguage].type as string ;
}
return type;
return fieldTranslation?.[key ?? ''] ?? key ?? fieldTranslation;
}
/**
* Recursively translates the given object in-place
* Translated values overwrite current values (destructive)
*
* @param instance The thing / object that will be translated
* @param language The language the thing / object is translated to
* @returns The thing translated
*/
public translateWholeThingDestructively(instance: any,
language?: keyof SCTranslations<any>): any {
const targetLanguage = (typeof language !== 'undefined') ? language : this.language;
let nextInstance = instance;
// Recursively call this function on all nested SCThings, arrays and objects
Object.keys(nextInstance)
.forEach((key) => {
if (
isThing((nextInstance as any)[key]) ||
nextInstance[key] instanceof Array ||
nextInstance[key] instanceof Object) {
nextInstance[key] = this.translateWholeThingDestructively(nextInstance[key], targetLanguage);
}
});
// Spread variable translations given by the connector into thing
if (typeof nextInstance.translations !== 'undefined') {
if (typeof nextInstance.translations![targetLanguage] !== 'undefined') {
nextInstance = {...nextInstance, ...nextInstance.translations![targetLanguage]} as typeof instance;
}
}
// Spread known translations from meta classes into (partly) translated thing
this.replaceAvailableMetaFieldValueTranslations(nextInstance, targetLanguage);
return nextInstance;
}
}
/**

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {slow, suite, test, timeout} from 'mocha-typescript';
import {slow, suite, test, timeout} from '@testdeck/mocha';
import {SCBulkResponse} from '../src/protocol/routes/bulk-request';
import {SCMultiSearchResponse} from '../src/protocol/routes/search-multi';
import {SCSearchResponse} from '../src/protocol/routes/search';

View File

@@ -21,12 +21,7 @@
"name": "Symposion Publishing"
}
],
"inLanguages": [
{
"name": "german",
"code": "de"
}
],
"inLanguage": "de",
"bookEdition": "2., überarb. u. erw. Aufl.",
"isbn": "3936608776",
"numberOfPages": 537,

View File

@@ -6,7 +6,7 @@
"address": "http://foo.com:1234",
"name": "Foo Plugin",
"requestSchema": {
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SCFooPluginRequest": {
"type": "object",
@@ -33,10 +33,10 @@
],
"additionalProperties": false,
"description": "User query",
"id": "https://core.stapps.tu-berlin.de/v0.18.0/lib/schema/SCFooPluginRequest.json"
"$id": "https://core.stapps.tu-berlin.de/v0.18.0/lib/schema/SCFooPluginRequest.json"
},
"responseSchema": {
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SCFooPluginResponse": {
"type": "object",
@@ -65,7 +65,7 @@
],
"additionalProperties": false,
"description": "A response to a query",
"id": "https://core.stapps.tu-berlin.de/v0.18.0/lib/schema/SCFooPluginResponse.json"
"$id": "https://core.stapps.tu-berlin.de/v0.18.0/lib/schema/SCFooPluginResponse.json"
},
"route": "/foo"
}

View File

@@ -4,9 +4,9 @@
"uid": "7cebbc3e-0a21-5371-ab0d-f7ba12f53dbd",
"type": "semester",
"name": "Sommersemester 2018",
"acronym": "SS 2018",
"acronym": "SoSe 2018",
"alternateNames": [
"SoSe 2018"
"Sommer 2018"
],
"startDate": "2018-04-01",
"endDate": "2018-09-30",

View File

@@ -13,7 +13,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expect} from 'chai';
import {slow, suite, test, timeout} from 'mocha-typescript';
import {slow, suite, test, timeout} from '@testdeck/mocha';
import {SCBulkRoute} from '../src/protocol/routes/bulk-request';
import {SCBulkAddRoute} from '../src/protocol/routes/bulk-add';
import {SCThingUpdateRoute} from '../src/protocol/routes/thing-update';

View File

@@ -18,7 +18,7 @@ import {Logger} from '@openstapps/logger';
import {fail} from 'assert';
import {expect} from 'chai';
import {mkdirSync} from 'fs';
import {slow, suite, test, timeout} from 'mocha-typescript';
import {slow, suite, test, timeout} from '@testdeck/mocha';
import {join, resolve} from 'path';
import {DeclarationReflection, ProjectReflection} from 'typedoc';
import {ArrayType, IntrinsicType, ReferenceType, StringLiteralType, Type, UnionType} from 'typedoc/dist/lib/models';

View File

@@ -14,8 +14,8 @@
*/
import {expect} from 'chai';
import clone = require('fast-clone');
import {slow, suite, test, timeout} from 'mocha-typescript';
import {SCThingOriginType, SCThingType} from '../src/things/abstract/thing';
import {slow, suite, test, timeout} from '@testdeck/mocha';
import {SCThingOriginType, SCThingType, SCThingRemoteOrigin} from '../src/things/abstract/thing';
import {SCBuildingWithoutReferences} from '../src/things/building';
import {SCDish, SCDishMeta} from '../src/things/dish';
import {SCSetting, SCSettingInputType} from '../src/things/setting';
@@ -105,137 +105,182 @@ const setting: SCSetting = {
};
const translator = new SCThingTranslator('de');
// tslint:disable-next-line:no-eval
const languageNonExistant = eval("'jp'");
const translatorEN = new SCThingTranslator('en');
// this will simulate a translator always utilizing the base language translations
const translatorWithFallback = new SCThingTranslator(languageNonExistant);
const translatorWithFallback = new SCThingTranslator('tt');
// tslint:disable:member-ordering TranslationSpecInplace
const translatedThingDE = translator.translate(dish);
const translatedThingFallback = translatorWithFallback.translate(dish);
// tslint:disable:max-line-length member-ordering newline-per-chained-call prefer-function-over-method completed-docs TranslationSpecInplace
@suite(timeout(10000), slow(5000))
export class TranslationSpecInplace {
@test
public directEnumSingleValue () {
expect(translator.translate(setting).inputType()).to.equal('einfache Auswahl');
public directEnumSingleValue() {
expect(translator.translatedAccess(setting).inputType()).to.equal('einfache Auswahl');
}
@test
public directStringLiteralType() {
expect(translator.translate(dish).type()).to.equal('Essen');
expect(translator.translatedAccess(dish).type()).to.equal('Essen');
expect(translatedThingDE.type).to.equal('Essen');
}
@test
public directStringProperty() {
expect(translator.translate(dish).name()).to.equal('de-dish-name');
expect(translator.translatedAccess(dish).name()).to.equal('de-dish-name');
expect(translatedThingDE.name).to.equal('de-dish-name');
}
@test
public directArrayOfString() {
expect(translator.translate(dish).characteristics()).to.deep
expect(translator.translatedAccess(dish).characteristics()).to.deep
.equal([{name: 'de-characteristic0'}, {name: 'de-characteristic1'}]);
expect(translatedThingDE.characteristics).to.deep
.equal([{name: 'de-characteristic0'}, {name: 'de-characteristic1'}]);
}
@test
public directArrayOfStringSubscript() {
expect(translator.translate(dish).characteristics[1]()).to.deep.equal({name: 'de-characteristic1'});
expect(translator.translatedAccess(dish).characteristics[1]()).to.deep.equal({name: 'de-characteristic1'});
expect(translatedThingDE.characteristics![1]).to.deep.equal({name: 'de-characteristic1'});
}
@test
public directMetaArrayOfString() {
expect(translator.translate(dish).categories()).to.deep.equal(['Hauptgericht', 'Nachtisch']);
expect(translator.translatedAccess(dish).categories()).to.deep.equal(['Hauptgericht', 'Nachtisch']);
expect(translatedThingDE.categories).to.deep.equal(['Hauptgericht', 'Nachtisch']);
}
@test
public directMetaArrayOfStringSubscript() {
expect(translator.translate(dish).categories[1]()).to.equal('Nachtisch');
expect(translator.translatedAccess(dish).categories[1]()).to.equal('Nachtisch');
expect(translatedThingDE.categories[1]).to.equal('Nachtisch');
}
@test
public nestedStringLiteralType() {
expect(translator.translate(dish).offers[0].inPlace.type()).to.equal('Gebäude');
expect(translator.translatedAccess(dish).offers[0].inPlace.type()).to.equal('Gebäude');
expect(translatedThingDE.offers![0].inPlace!.type).to.equal('Gebäude');
}
@test
public nestedStringProperty() {
expect(translator.translate(dish).offers[0].inPlace.name()).to.equal('de-space-name');
expect(translator.translatedAccess(dish).offers[0].inPlace.name()).to.equal('de-space-name');
expect(translatedThingDE.offers![0].inPlace!.name).to.equal('de-space-name');
}
@test
public nestedMetaArrayOfString() {
expect(translator.translate(dish).offers[0].inPlace.categories()).to.deep.equal(['Büro', 'Bildung']);
expect(translator.translatedAccess(dish).offers[0].inPlace.categories()).to.deep.equal(['Büro', 'Bildung']);
expect(translatedThingDE.offers![0].inPlace!.categories).to.deep.equal(['Büro', 'Bildung']);
}
@test
public nestedMetaArrayOfStringSubscript() {
expect(translator.translate(dish).offers[0].inPlace.categories[1]()).to.equal('Bildung');
expect(translator.translatedAccess(dish).offers[0].inPlace.categories[1]()).to.equal('Bildung');
expect(translatedThingDE.offers![0].inPlace!.categories[1]).to.equal('Bildung');
}
@test
public directStringLiteralTypeFallback() {
expect(translatorWithFallback.translate(dish).type()).to.equal('dish');
expect(translatorWithFallback.translatedAccess(dish).type()).to.equal('dish');
expect(translatedThingFallback.type).to.equal('dish');
}
@test
public directStringPropertyFallback() {
expect(translatorWithFallback.translate(dish).name()).to.equal('base-dish-name');
expect(translatorWithFallback.translatedAccess(dish).name()).to.equal('base-dish-name');
expect(translatedThingFallback.name).to.equal('base-dish-name');
}
@test
public directArrayOfStringSubscriptFallback() {
expect(translatorWithFallback.translate(dish).characteristics[1]())
expect(translatorWithFallback.translatedAccess(dish).characteristics[1]())
.to.deep.equal({name: 'base-characteristic1'});
expect(translatedThingFallback.characteristics![1])
.to.deep.equal({name: 'base-characteristic1'});
}
@test
public directMetaArrayOfStringFallback() {
expect(translatorWithFallback.translate(dish).categories()).to.deep.equal(['main dish', 'dessert']);
expect(translatorWithFallback.translatedAccess(dish).categories()).to.deep.equal(['main dish', 'dessert']);
expect(translatedThingFallback.categories).to.deep.equal(['main dish', 'dessert']);
}
@test
public directMetaArrayOfStringSubscriptFallback() {
expect(translatorWithFallback.translate(dish).categories[1]()).to.equal('dessert');
expect(translatorWithFallback.translatedAccess(dish).categories[1]()).to.equal('dessert');
expect(translatedThingFallback.categories[1]).to.equal('dessert');
}
@test
public nestedStringLiteralTypeFallback() {
expect(translatorWithFallback.translate(dish).offers[0].inPlace.type()).to.equal('building');
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.type()).to.equal('building');
expect(translatedThingFallback.offers![0].inPlace!.type).to.equal('building');
}
@test
public nestedStringPropertyFallback() {
expect(translatorWithFallback.translate(dish).offers[0].inPlace.name()).to.equal('base-space-name');
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.name()).to.equal('base-space-name');
expect(translatedThingFallback.offers![0].inPlace!.name).to.equal('base-space-name');
}
@test
public nestedMetaArrayOfStringFallback() {
expect(translatorWithFallback.translate(dish).offers[0].inPlace.categories())
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.categories())
.to.deep.equal(['office', 'education']);
expect(translatedThingFallback.offers![0].inPlace!.categories)
.to.deep.equal(['office', 'education']);
}
@test
public nestedMetaArrayOfStringSubscriptFallback() {
expect(translatorWithFallback.translate(dish).offers[0].inPlace.categories[1]()).to.equal('education');
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.categories[1]()).to.equal('education');
expect(translatedThingFallback.offers![0].inPlace!.categories[1]).to.equal('education');
}
@test
public directStringLiteralTypeUndefined() {
// tslint:disable-next-line:no-eval
const undefinedThing = eval('(x) => undefined;');
expect(translator.translate(undefinedThing())('defaultValue')).to.equal('defaultValue');
expect(translator.translate(dish).name('defaultValue')).to.not.equal('defaultValue');
expect(translator.translatedAccess(undefinedThing())('defaultValue')).to.equal('defaultValue');
expect(translator.translatedAccess(dish).name('defaultValue')).to.not.equal('defaultValue');
}
@test
public nestedMetaArrayOfStringSubscriptUndefined() {
expect(translator.translate(dish).offers[0].inPlace.categories[1234]('printer')).to.equal('printer');
expect(translator.translate(dish).offers[0].inPlace.categories[1]('printer')).to.not.equal('printer');
// tslint:disable-next-line: no-eval
const workingTranslation = eval('translator.translatedAccess(dish).offers[0].inPlace.categories[1](\'printer\');');
// tslint:disable-next-line: no-eval
const defaultValueTranslation = eval('translator.translatedAccess(dish).offers[0].inPlace.categories[1234](\'printer\');');
expect(defaultValueTranslation).to.equal('printer');
expect(workingTranslation).to.not.equal('printer');
}
@test
public reaccessWithChangedSourceOmitsLRUCache() {
const translatorDE = new SCThingTranslator('de');
const dishCopy = clone(dish);
const translatedDish = translatorDE.translatedAccess(dish);
const distructivelyTranslatedDish = translatorDE.translate(dish);
(dishCopy.origin as SCThingRemoteOrigin).name = 'tranlator.spec';
expect(translatorDE.translatedAccess(dishCopy)).not.to.deep.equal(translatedDish);
expect(translatorDE.translate(dishCopy)).not.to.equal(distructivelyTranslatedDish);
}
@test
public changingTranslatorLanguageFlushesItsLRUCache() {
const translatorDE = new SCThingTranslator('de');
expect(translatorDE.translate(dish).name()).to.equal('de-dish-name');
expect(translatorDE.translatedAccess(dish).name()).to.equal('de-dish-name');
expect(translatorDE.translate(dish).name).to.equal('de-dish-name');
translatorDE.language = 'en';
expect(translatorDE.translate(dish).name()).to.equal('base-dish-name');
expect(translatorDE.translatedAccess(dish).name()).to.equal('base-dish-name');
expect(translatorDE.translate(dish).name).to.equal('base-dish-name');
}
@test
@@ -245,7 +290,7 @@ export class TranslationSpecInplace {
for (let i = 0; i < 201; i++) {
const anotherDish = Object.assign({}, dish);
anotherDish.uid = String(i);
expect(translatorDE.translate(anotherDish).name()).to.equal('de-dish-name');
expect(translatorDE.translatedAccess(anotherDish).name()).to.equal('de-dish-name');
}
}
}
@@ -257,22 +302,32 @@ export class MetaTranslationSpec {
@test
public consistencyWithMetaClass() {
const dishMetaTranslationsDE = translator.translatedPropertyNames(dish.type);
const dishMetaTranslationsEN = translator.translatedPropertyNames(dish.type, 'en');
const dishMetaTranslationsEN = translatorEN.translatedPropertyNames(dish.type);
expect(dishMetaTranslationsEN).to.not.deep.equal(dishMetaTranslationsDE);
expect(dishMetaTranslationsDE).to.deep.equal(SCDishMeta.getInstance().fieldTranslations.de);
expect(dishMetaTranslationsEN).to.deep.equal(SCDishMeta.getInstance().fieldTranslations.en);
}
@test
public retrieveTranslatedThingType() {
const dishTypeDE = translator.translatedThingType(dish.type);
const dishTypeEN = translator.translatedThingType(dish.type, 'en');
const dishTypeBASE = translatorWithFallback.translatedThingType(dish.type);
public retrieveTranslatedPropertyValueType() {
const dishTypeDE = translator.translatedPropertyValue(dish.type, 'type');
const dishTypeEN = translatorEN.translatedPropertyValue(dish.type, 'type', undefined);
const dishTypeBASE = translatorWithFallback.translatedPropertyValue(dish.type, 'type');
expect(dishTypeDE).to.deep.equal(SCDishMeta.getInstance().fieldValueTranslations.de.type);
expect(dishTypeEN).to.deep.equal(SCDishMeta.getInstance().fieldValueTranslations.en.type);
expect(dishTypeBASE).to.deep.equal(SCDishMeta.getInstance().fieldValueTranslations.en.type);
}
@test
public retrieveTranslatedPropertyValueNested() {
const dishTypeDE = translator.translatedPropertyValue(dish.type, 'categories', 'main dish');
const dishTypeEN = translatorEN.translatedPropertyValue(dish.type, 'categories', 'main dish');
const dishTypeBASE = translatorWithFallback.translatedPropertyValue(dish.type, 'categories', 'main dish');
expect(dishTypeDE).to.deep.equal(SCDishMeta.getInstance<SCDishMeta>().fieldValueTranslations.de.categories['main dish']);
expect(dishTypeEN).to.deep.equal(dish.categories[0]);
expect(dishTypeBASE).to.deep.equal(dish.categories[0]);
}
@test
public thingWithoutMetaClass() {
const dishCopy = clone(dish);