# Contributing to `@openstapps/core`

Please see the appropriate general group contributing guides in [project-management](https://gitlab.com/openstapps/projectmanagement/tree/master/project-docs/workflow).

## Updating and releasing related projects

Following semantic versioning patches to the core should not break existing usage.

### API

Every minor and major version of the core needs a corresponding version of the [API](https://openstapps.gitlab.io/api) to be used in the app and connectors.

Because the API is an integral part of the App and Node.js-based connectors this should be done for every new minor and major release of the core.

### Backend

The [backend](https://openstapps.gitlab.io/backend) uses the core to validate requests and responses. With the use of the [core tools](https://openstapps.gitlab.io/core-tools) it uses the core to set up the database according to the model.

Like for the API there should be a new release of the backend for every minor and major release of the core.

### Core tools

The [core tools](https://openstapps.gitlab.io/core-tools) are more or less not dependent on a specific core version and should normally not need adjustments for new core versions as long the structure of the code in the core stays the same.

### App and connectors

[App](https://openstapps.gitlab.io/app) and connectors use the API to communicate with the backend. To ensure compatibility the version of the used core must be the same as the one that is used in the used API.

App and connectors should be updated regularly to new releases of the core but not as important like API and backend. Since the app is just a view for the data stored in the backend it is not necessary to be up to date with the newest core immediately and the connectors are developed independently by every school and up to their responsibility.

## Adding new Types

Adding new types requires changes at multiple locations for it to work correctly

### Required changes

- Add your SCThing and SCThingWithoutReferences to `src/things/your-thing-name.ts` and make them extend `SCThingWithoutReferences` and `SCThing` respectively
- Add your SCThingMeta to `src/things/your-thing-name.ts` and make it extend `SCThingMeta`
- Add your SCThingMeta to `SCClasses` in `src/meta.ts`
- Add your SCThing to `SCIndexableThings ` in `src/meta.ts`
- Add your SCThingWithoutReferences to `SCAssociatedThingWithoutReferences` in `src/meta.ts`
- Add your SCThing to `SCAssociatedThing` in `src/meta.ts`
- Add your SCThing to the `SCThingType` enum in `src/things/abstract/thing.ts`
- Add an example file for your SCThing in `test/resources/YourThingName.json`
- Add the following lines for your SCThing in `test/type.spec.ts`:
- Make sure your SCThing (but not SCThingWithoutReferences!) includes the `@indexable` and `@validatable` JSDoc annotations, otherwise neither JSON Schemas nor Elasticsearch mappings will be generated
```typescript
/**
 * Types of properties of SCYourThingName
 */
type SCYourThingNamePropertyTypes = PropertyTypesNested<SCYourThingName>;
assert<NotHas<SCYourThingNamePropertyTypes, SCThingWithoutReferences>>(false);
assert<Has<SCYourThingNamePropertyTypes, SCThingWithoutReferences>>(true);
assert<NotHas<SCYourThingNamePropertyTypes, SCThing>>(true);
assert<Has<SCYourThingNamePropertyTypes, SCThing>>(false);
assert<Extends<SCYourThingNameWithoutReferences, SCThing>>(false);
assert<Extends<SCYourThingName, SCThing>>(true);
```

## Additional coding style

### Extract inline type definitions

For consistency and correct functionality of `core-tools` we need well-defined type assignments.

Type assignments shall always be primitive types, classes, interfaces, enums or unions. Not allowed are inline type-definitions. Those shall be refactored accordingly:

```typescript
export interface SCPlaceWithoutReferences extends SCThing {
    ...
    // Use this:
    geo: SCGeoInformation;

    // Instead of:
    geo: {
        point: Point,
        polygon?: Polygon,
    };
}
```

### Reuse the map structure

If you come around a map-like-type use `SCMap<T>`.

```typescript
// Use this:
interface AnyClass {
  inventory: SCMap<number>;
}

// Instead of:
interface AnyClass {
  inventory?: Array<{key: string; value: number}>;
}
// or instead of
interface AnyClass {
  inventory?: {[key: string]: number};
}
```
