mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2025-12-25 15:46:17 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e934017a65 | ||
|
|
88dbedd932 | ||
|
|
8b1b3444fd | ||
|
|
d5f3d71a41 | ||
|
|
cbcf9c9adb | ||
|
|
321e4f6f24 | ||
|
|
8510f11d7b | ||
|
|
68aa377fe2 | ||
|
|
29f2c77ecc | ||
|
|
29bc00616e | ||
|
|
02920af4a4 | ||
|
|
0c14b0f1a0 | ||
|
|
db0a239761 | ||
|
|
377f55bbbe | ||
|
|
8d7a0e10c6 | ||
|
|
4865f911d1 | ||
|
|
15ae5e0873 | ||
|
|
a246bdea84 | ||
|
|
8641bfc877 | ||
|
|
d34e66fbbc | ||
|
|
c6273a85d9 | ||
|
|
5558d29c2b | ||
|
|
69dfd1ae39 | ||
|
|
4638bb3684 | ||
|
|
6c687c6004 | ||
|
|
0bf1301733 | ||
|
|
827ba47892 | ||
|
|
d3b620a745 | ||
|
|
821834cfa0 | ||
|
|
c369c8520a | ||
|
|
66075ef99b | ||
|
|
7a6333aa8f | ||
|
|
e242a21e99 | ||
|
|
6fecd1e89d | ||
|
|
f6a93e668b |
@@ -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
5
.mailmap
Normal 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>
|
||||
54
CHANGELOG.md
54
CHANGELOG.md
@@ -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)
|
||||
|
||||
|
||||
|
||||
24
README.md
24
README.md
@@ -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
4518
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
55
package.json
55
package.json
@@ -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": [
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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';
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
112
src/protocol/search/filters/range.ts
Normal file
112
src/protocol/search/filters/range.ts
Normal 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';
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
25
src/protocol/search/sorts/generic.ts
Normal file
25
src/protocol/search/sorts/generic.ts
Normal 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';
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,10 +27,6 @@ import {
|
||||
*/
|
||||
export interface SCSettingWithoutReferences
|
||||
extends SCThingWithCategoriesWithoutReferences<SCSettingCategories, SCThingWithCategoriesSpecificValues> {
|
||||
/**
|
||||
* Categories of a setting
|
||||
*/
|
||||
categories: SCSettingCategories[];
|
||||
/**
|
||||
* The default value of a setting
|
||||
*/
|
||||
|
||||
@@ -29,8 +29,6 @@ export interface SCTourWithoutReferences
|
||||
|
||||
/**
|
||||
* Steps of a tour
|
||||
*
|
||||
* @keyword
|
||||
*/
|
||||
steps: SCTourStep[];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -21,12 +21,7 @@
|
||||
"name": "Symposion Publishing"
|
||||
}
|
||||
],
|
||||
"inLanguages": [
|
||||
{
|
||||
"name": "german",
|
||||
"code": "de"
|
||||
}
|
||||
],
|
||||
"inLanguage": "de",
|
||||
"bookEdition": "2., überarb. u. erw. Aufl.",
|
||||
"isbn": "3936608776",
|
||||
"numberOfPages": 537,
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user