Skip to content

Commit

Permalink
feat: add typescript declaration file (#743)
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveBunlon authored Jul 1, 2021
1 parent d3e4711 commit a536f1c
Show file tree
Hide file tree
Showing 5 changed files with 418 additions and 4 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
- [ ] Test manually the implemented changes
- [ ] Review my own code (indentation, syntax, style, simplicity, readability)
- [ ] Wonder if you can improve the existing code
- [ ] If needed, Types have been updated
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"url": "git://github.com/ForestAdmin/forest-express-sequelize.git"
},
"main": "dist/index.js",
"types": "./types/index.d.ts",
"dependencies": {
"@babel/runtime": "7.10.1",
"bluebird": "2.9.25",
Expand All @@ -47,6 +48,8 @@
"@semantic-release/changelog": "5.0.1",
"@semantic-release/git": "9.0.0",
"@types/jest": "26.0.9",
"@typescript-eslint/eslint-plugin": "4.26.0",
"@typescript-eslint/parser": "4.26.0",
"babel-eslint": "10.0.3",
"eslint": "6.8.0",
"eslint-config-airbnb-base": "14.0.0",
Expand All @@ -65,12 +68,13 @@
"sequelize": "5.21.3",
"sequelize-fixtures": "1.1.1",
"simple-git": "1.65.0",
"tedious": "11.0.8"
"tedious": "11.0.8",
"typescript": "4.3.2"
},
"scripts": {
"build": "babel src --out-dir dist",
"build:watch": "onchange 'src/**/*.js' 'node_modules/forest-express/dist/*' --no-exclude -i -- babel --source-maps inline --out-dir dist src",
"lint": "./node_modules/eslint/bin/eslint.js .eslint-bin src test",
"lint": "./node_modules/eslint/bin/eslint.js .eslint-bin src test types/index.d.ts",
"test": "jest",
"test:coverage": "jest --coverage"
}
Expand Down
15 changes: 15 additions & 0 deletions types/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off"
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
]
}
256 changes: 256 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
import { RequestHandler, Response, Request, NextFunction, Application } from 'express';
import * as Sequelize from 'sequelize';

// Everything related to Forest initialization

export interface LianaOptions {
objectMapping: typeof Sequelize;
envSecret: string;
authSecret: string;
connections: Record<string, Sequelize.Sequelize>;
includedModels?: string[];
excludedModels?: string[];
configDir?: string;
}

export function init(options: LianaOptions): Promise<Application>;

export interface DatabaseConfiguration {
name: string,
modelsDir: string,
connection: {
url: string,
options: Sequelize.Options,
}
}

// Everything related to Forest Authentication

export function ensureAuthenticated(request: Request, response: Response, next: NextFunction): void;

// Everything related to Forest constants

export const PUBLIC_ROUTES: string[];

// Everything related to record manipulation

interface RecordsSerialized {
data: Record<string, unknown>[],
included: Record<string, unknown>[],
}

export class AbstractRecordTool<M extends Sequelize.Model> {
constructor(model: Sequelize.ModelCtor<M>)
serialize(records: M | M[]): Promise<RecordsSerialized>;
}

export class RecordGetter<M extends Sequelize.Model> extends AbstractRecordTool<M> {
get(recordId: string): Promise<M>;
}

export class RecordsGetter<M extends Sequelize.Model> extends AbstractRecordTool<M> {
getAll(query: Query): Promise<M[]>;
getIdsFromRequest(request: Request): Promise<string[]>;
}

export class RecordsCounter<M extends Sequelize.Model> extends AbstractRecordTool<M> {
count(query: Query): Promise<number>;
}

export class RecordsExporter<M extends Sequelize.Model> extends AbstractRecordTool<M> {
streamExport(response: Response, query: Query): Promise<void>;
}

export class RecordUpdater<M extends Sequelize.Model> extends AbstractRecordTool<M> {
deserialize(body: Record<string, unknown>): Promise<Record<string, unknown>>;
update(record: Record<string, unknown>, recordId: string): Promise<M>;
}

export class RecordCreator<M extends Sequelize.Model> extends AbstractRecordTool<M> {
deserialize(body: Record<string, unknown>): Promise<Record<string, unknown>>;
create(record: Record<string, unknown>): Promise<M>;
}

export class RecordRemover<M extends Sequelize.Model> extends AbstractRecordTool<M> {
remove(recordId: string | number): Promise<void>;
}

export class RecordsRemover<M extends Sequelize.Model> extends AbstractRecordTool<M> {
remove(recordIds: string[] | number[]): Promise<void>;
}

// Everything related to Forest permissions

export class PermissionMiddlewareCreator {
constructor(collectionName: string)
list(): RequestHandler;
export(): RequestHandler;
details(): RequestHandler;
create(): RequestHandler;
update(): RequestHandler;
delete(): RequestHandler;
smartAction(): RequestHandler;
}

// Everything related to Forest Charts

export interface StatSerialized {
data: {
type: string,
id: string,
attributes: {
value: any[]
}
};
}

export class StatSerializer {
constructor(stats: { value: any[] })
perform(): StatSerialized;
}

// Everything related to Forest request params

export interface Page {
number: number;
size: number;
}

export interface Filter {
field: string;
operator: string;
value: string;
}

export enum Aggregator {
AND = 'and',
OR = 'or'
}

export interface AggregatedFilters {
aggregator: Aggregator;
conditions: Filter[];
}

export interface Query {
timezone?: string;
search?: string;
fields?: {[key: string]: string};
sort?: string;
filters?: Filter|AggregatedFilters;
page?: Page;
searchExtended?: string;
}

// Everything related to Forest collection configuration

export interface SmartFieldValueGetter<M extends Sequelize.Model = any> {
(record: M): any;
}

export interface SmartFieldValueSetter<M extends Sequelize.Model = any> {
(record: M, fieldValue: any): any;
}

export interface SmartFieldSearchQuery {
include: string[],
where: Sequelize.WhereOptions,
}

export interface SmartFieldSearcher {
(query: SmartFieldSearchQuery, search: string): SmartFieldSearchQuery;
}

export interface SmartFieldFiltererFilter {
condition: Filter,
where: Record<symbol, Record<symbol, any> | any>,
}

export interface SmartFieldFilterer {
(filter: SmartFieldFiltererFilter): Sequelize.WhereOptions;
}

export interface SegmentAggregationCreator<M extends Sequelize.Model = any> {
(model: M): Sequelize.WhereOptions;
}

type FieldType = 'Boolean' | 'Date' | 'Dateonly' | 'Enum' | 'File' | 'Number' | 'String' | ['Enum'] | ['Number'] | ['String'];

type FieldEnumsType = string[] | number[] | Date[] | boolean[];

export interface SmartFieldOptions {
field: string;
description?: string;
type: FieldType;
isFilterable?: boolean;
isReadOnly?: boolean;
isRequired?: boolean;
reference?: string;
enums?: FieldEnumsType;
defaultValue?: any;
get?: SmartFieldValueGetter;
set?: SmartFieldValueSetter;
search?: SmartFieldSearcher;
filter?: SmartFieldFilterer;
}

export interface SmartActionField {
field: string,
description?: string,
type: FieldType,
isRequired?: boolean,
isReadOnly?: boolean,
enums?: FieldEnumsType,
defaultValue?: any,
reference?: string,
}

export interface SmartActionHookField extends SmartActionField {
value: any,
}

export interface SmartActionLoadHookField extends SmartActionHookField {
position: number,
}

export interface SmartActionLoadHook<M extends Sequelize.Model = any> {
(context: { fields: Record<string, SmartActionLoadHookField>, record: M }): Record<string, SmartActionLoadHookField>
}

export interface SmartActionChangeHookField extends SmartActionHookField {
previousValue: any,
}

export interface SmartActionChangeHook<M extends Sequelize.Model = any> {
(context: { fields: Record<string, SmartActionChangeHookField>, record: M }): Record<string, SmartActionChangeHookField>
}

export interface SmartActionHooks {
load: SmartActionLoadHook;
change: Record<string, SmartActionChangeHook>;
}

export interface SmartActionOptions {
name: string;
type?: 'global' | 'bulk' | 'single';
fields?: SmartActionField[];
download?: boolean;
endpoint?: string;
httpMethod?: string;
hooks?: SmartActionHooks;
}

export interface SmartSegmentOptions {
name: string;
where: SegmentAggregationCreator;
}

export interface CollectionOptions {
fields?: SmartFieldOptions[];
actions?: SmartActionOptions[];
segments?: SmartSegmentOptions[];
}

export function collection(name: string, options: CollectionOptions): void;

export function errorHandler(): RequestHandler;
Loading

0 comments on commit a536f1c

Please sign in to comment.