alp-node 6.2.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/AlpNodeApp-node18.mjs +303 -12
- package/dist/AlpNodeApp-node18.mjs.map +1 -1
- package/dist/definitions/AlpNodeApp.d.ts +15 -7
- package/dist/definitions/AlpNodeApp.d.ts.map +1 -1
- package/dist/definitions/config.d.ts +18 -0
- package/dist/definitions/config.d.ts.map +1 -0
- package/dist/definitions/errors.d.ts +4 -0
- package/dist/definitions/errors.d.ts.map +1 -0
- package/dist/definitions/index.d.ts +5 -3
- package/dist/definitions/index.d.ts.map +1 -1
- package/dist/definitions/language.d.ts +7 -0
- package/dist/definitions/language.d.ts.map +1 -0
- package/dist/definitions/listen.d.ts +7 -0
- package/dist/definitions/listen.d.ts.map +1 -0
- package/dist/definitions/params/ParamValid.d.ts +9 -0
- package/dist/definitions/params/ParamValid.d.ts.map +1 -0
- package/dist/definitions/params/ParamValidationResult.d.ts +9 -0
- package/dist/definitions/params/ParamValidationResult.d.ts.map +1 -0
- package/dist/definitions/params/ParamValidationResult.test.d.ts +2 -0
- package/dist/definitions/params/ParamValidationResult.test.d.ts.map +1 -0
- package/dist/definitions/params/ParamValueFromContext.d.ts +13 -0
- package/dist/definitions/params/ParamValueFromContext.d.ts.map +1 -0
- package/dist/definitions/params/ParamValueModelValidator.d.ts +4 -0
- package/dist/definitions/params/ParamValueModelValidator.d.ts.map +1 -0
- package/dist/definitions/params/ParamValueStringValidator.d.ts +5 -0
- package/dist/definitions/params/ParamValueStringValidator.d.ts.map +1 -0
- package/dist/definitions/params/ParamValueValidator.d.ts +10 -0
- package/dist/definitions/params/ParamValueValidator.d.ts.map +1 -0
- package/dist/definitions/params/index.d.ts +15 -0
- package/dist/definitions/params/index.d.ts.map +1 -0
- package/dist/definitions/router.d.ts +14 -0
- package/dist/definitions/router.d.ts.map +1 -0
- package/dist/definitions/translate/index.d.ts +11 -0
- package/dist/definitions/translate/index.d.ts.map +1 -0
- package/dist/definitions/translate/load.d.ts +4 -0
- package/dist/definitions/translate/load.d.ts.map +1 -0
- package/dist/definitions/types.d.ts +53 -0
- package/dist/definitions/types.d.ts.map +1 -0
- package/dist/index-node18.mjs +402 -15
- package/dist/index-node18.mjs.map +1 -1
- package/package.json +8 -9
- package/src/AlpNodeApp.ts +42 -21
- package/src/config.ts +121 -0
- package/src/errors.ts +70 -0
- package/src/index.ts +18 -3
- package/src/language.ts +27 -0
- package/src/listen.ts +68 -0
- package/src/params/ParamValid.ts +15 -0
- package/src/params/ParamValidationResult.test.ts +65 -0
- package/src/params/ParamValidationResult.ts +38 -0
- package/src/params/ParamValueFromContext.ts +42 -0
- package/src/params/ParamValueModelValidator.ts +36 -0
- package/src/params/ParamValueStringValidator.ts +13 -0
- package/src/params/ParamValueValidator.ts +23 -0
- package/src/params/index.ts +66 -0
- package/src/router.ts +64 -0
- package/src/translate/index.ts +45 -0
- package/src/translate/load.ts +30 -0
- package/src/types.ts +67 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ParamValidationResult } from './ParamValidationResult';
|
|
2
|
+
|
|
3
|
+
// const createContextMock = (): Context &
|
|
4
|
+
// Record<
|
|
5
|
+
// 'namedParam' | 'otherParam' | 'param' | 'paramGET' | 'paramGETorPOST',
|
|
6
|
+
// ReturnType<typeof jest.fn>
|
|
7
|
+
// > => {
|
|
8
|
+
// return {
|
|
9
|
+
// state: {} as ContextState,
|
|
10
|
+
// sanitizedState: {} as ContextSanitizedState,
|
|
11
|
+
// param: jest.fn(),
|
|
12
|
+
// namedParam: jest.fn(),
|
|
13
|
+
// otherParam: jest.fn(),
|
|
14
|
+
// paramGET: jest.fn(),
|
|
15
|
+
// paramGETorPOST: jest.fn(),
|
|
16
|
+
// } as unknown as Context &
|
|
17
|
+
// Record<
|
|
18
|
+
// 'namedParam' | 'otherParam' | 'param' | 'paramGET' | 'paramGETorPOST',
|
|
19
|
+
// ReturnType<typeof jest.fn>
|
|
20
|
+
// >;
|
|
21
|
+
// };
|
|
22
|
+
|
|
23
|
+
test('on init is valid', () => {
|
|
24
|
+
const paramValidator = new ParamValidationResult();
|
|
25
|
+
expect(paramValidator.getErrors()).toBe(undefined);
|
|
26
|
+
expect(paramValidator.hasErrors()).toBe(false);
|
|
27
|
+
expect(paramValidator.isValid()).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('has error', () => {
|
|
31
|
+
const paramValidator = new ParamValidationResult();
|
|
32
|
+
paramValidator._error('slug', 'notEmpty', '');
|
|
33
|
+
expect(paramValidator.hasErrors()).toBe(true);
|
|
34
|
+
expect(paramValidator.isValid()).toBe(false);
|
|
35
|
+
expect(paramValidator.getErrors()).toEqual({
|
|
36
|
+
slug: { error: 'notEmpty', value: '' },
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// test('.string() empty', () => {
|
|
41
|
+
// const contextMock = createContextMock();
|
|
42
|
+
// contextMock.param.mockReturnValue('');
|
|
43
|
+
|
|
44
|
+
// const paramValidator = new ParamValidationResult(contextMock);
|
|
45
|
+
|
|
46
|
+
// paramValidator.string('slug').notEmpty();
|
|
47
|
+
// expect(contextMock.param).toHaveBeenNthCalledWith(1, 'slug');
|
|
48
|
+
// expect(paramValidator.hasErrors()).toBe(true);
|
|
49
|
+
// expect(paramValidator.isValid()).toBe(false);
|
|
50
|
+
// expect(paramValidator.getErrors()).toEqual({
|
|
51
|
+
// slug: { error: 'notEmpty', value: '' },
|
|
52
|
+
// });
|
|
53
|
+
// });
|
|
54
|
+
|
|
55
|
+
// test('.string() not empty', () => {
|
|
56
|
+
// const contextMock = createContextMock();
|
|
57
|
+
// contextMock.param.mockReturnValue('testValue');
|
|
58
|
+
// const paramValidator = new ParamValidationResult(contextMock);
|
|
59
|
+
|
|
60
|
+
// paramValidator.string('slug').notEmpty();
|
|
61
|
+
// expect(contextMock.param).toHaveBeenNthCalledWith(1, 'slug');
|
|
62
|
+
// expect(paramValidator.hasErrors()).toBe(false);
|
|
63
|
+
// expect(paramValidator.isValid()).toBe(true);
|
|
64
|
+
// expect(paramValidator.getErrors()).toBe(undefined);
|
|
65
|
+
// });
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type Errors = Record<string, any>;
|
|
2
|
+
|
|
3
|
+
export class ParamValidationResult {
|
|
4
|
+
_errors?: Errors;
|
|
5
|
+
|
|
6
|
+
_error(name: string, key: string, value: unknown): void {
|
|
7
|
+
if (!this._errors) {
|
|
8
|
+
this._errors = {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this._errors[name] = { error: key, value };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getErrors(): Errors | undefined {
|
|
15
|
+
return this._errors;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
hasErrors(): boolean {
|
|
19
|
+
return this._errors !== undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
isValid(): boolean {
|
|
23
|
+
return this._errors === undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// string(name: string): ParamValueStringValidator {
|
|
27
|
+
// return new ParamValueStringValidator(this, name, this.context.param(name));
|
|
28
|
+
// }
|
|
29
|
+
/* int(name, position) {
|
|
30
|
+
return new ParamValueIntValidator(this, name, this.context.param(name, position));
|
|
31
|
+
}
|
|
32
|
+
model(modelName, name) {
|
|
33
|
+
name = name || S.string.lcFirst(modelName);
|
|
34
|
+
console.log('paramvalidator model', modelName, M[modelName]);
|
|
35
|
+
let data = this.context.getOrPostParam(name);
|
|
36
|
+
return new ParamValueModelValidator(this, name, !data ? null : new M[modelName](data));
|
|
37
|
+
} */
|
|
38
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Context } from '../AlpNodeApp';
|
|
2
|
+
import type { ParamValidationResult } from './ParamValidationResult';
|
|
3
|
+
import ParamValueStringValidator from './ParamValueStringValidator';
|
|
4
|
+
|
|
5
|
+
export class ParamValueFromContext {
|
|
6
|
+
readonly validationResult: ParamValidationResult;
|
|
7
|
+
|
|
8
|
+
readonly context: Context;
|
|
9
|
+
|
|
10
|
+
constructor(context: Context, validationResult: ParamValidationResult) {
|
|
11
|
+
this.validationResult = validationResult;
|
|
12
|
+
this.context = context;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
namedParam(name: string): ParamValueStringValidator {
|
|
16
|
+
return new ParamValueStringValidator(
|
|
17
|
+
this.validationResult,
|
|
18
|
+
name,
|
|
19
|
+
this.context.namedParam(name),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
otherParam(position: number): ParamValueStringValidator {
|
|
24
|
+
return new ParamValueStringValidator(
|
|
25
|
+
this.validationResult,
|
|
26
|
+
String(position),
|
|
27
|
+
this.context.otherParam(position),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
queryParam(name: string): ParamValueStringValidator {
|
|
32
|
+
return new ParamValueStringValidator(
|
|
33
|
+
this.validationResult,
|
|
34
|
+
name,
|
|
35
|
+
this.context.queryParam(name),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// bodyParam: <T>(name: string): ParamValueValidator<string | undefined> {
|
|
40
|
+
|
|
41
|
+
// }
|
|
42
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import ParamValueValidator from './ParamValueValidator';
|
|
2
|
+
|
|
3
|
+
export default class ParamValueModelValidator<
|
|
4
|
+
T,
|
|
5
|
+
> extends ParamValueValidator<T> {
|
|
6
|
+
/*
|
|
7
|
+
required() {
|
|
8
|
+
if (this.value == null) {
|
|
9
|
+
this._error('required');
|
|
10
|
+
}
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
valid(fieldsRequired) {
|
|
14
|
+
if (this.value == null) {
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
if (S.isString(fieldsRequired)) {
|
|
18
|
+
fieldsRequired = fieldsRequired.split(' ');
|
|
19
|
+
}
|
|
20
|
+
S.forEach(this.value.constructor.Fields, (name, fModel) => {
|
|
21
|
+
let value = this.value[name];
|
|
22
|
+
if (fieldsRequired) {
|
|
23
|
+
if(S.array.has(fieldsRequired, name) && value == null) {
|
|
24
|
+
this._error('required');
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
if (value == null && fModel[1] && fModel[1].required) {
|
|
28
|
+
this._error('required');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//TODO ...
|
|
32
|
+
});
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
*/
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import ParamValueValidator from './ParamValueValidator';
|
|
2
|
+
|
|
3
|
+
export default class ParamValueStringValidator<
|
|
4
|
+
T extends string = string,
|
|
5
|
+
> extends ParamValueValidator<T | null | undefined> {
|
|
6
|
+
notEmpty(): ParamValueValidator<T> {
|
|
7
|
+
if (this.value == null || this.value.trim() === '') {
|
|
8
|
+
this._error('notEmpty');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return this as ParamValueValidator<T>;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ParamValidationResult } from './ParamValidationResult';
|
|
2
|
+
|
|
3
|
+
export default class ParamValueValidator<T> {
|
|
4
|
+
readonly validationResult: ParamValidationResult;
|
|
5
|
+
|
|
6
|
+
readonly name: string;
|
|
7
|
+
|
|
8
|
+
readonly value: T;
|
|
9
|
+
|
|
10
|
+
constructor(validationResult: ParamValidationResult, name: string, value: T) {
|
|
11
|
+
this.validationResult = validationResult;
|
|
12
|
+
this.name = name;
|
|
13
|
+
this.value = value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
isValid(): boolean {
|
|
17
|
+
return this.validationResult.isValid();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_error(key: string): void {
|
|
21
|
+
this.validationResult._error(this.name, key, this.value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineLazyProperty } from 'object-properties';
|
|
2
|
+
import type { AlpNodeApp, Context } from '../AlpNodeApp';
|
|
3
|
+
import ParamValid from './ParamValid';
|
|
4
|
+
import { ParamValidationResult } from './ParamValidationResult';
|
|
5
|
+
import { ParamValueFromContext } from './ParamValueFromContext';
|
|
6
|
+
|
|
7
|
+
export interface AlpParamsContext {
|
|
8
|
+
params: ParamValueFromContext;
|
|
9
|
+
validParams: ParamValueFromContext;
|
|
10
|
+
namedParam: (name: string) => string | undefined;
|
|
11
|
+
otherParam: (position: number) => string | undefined;
|
|
12
|
+
queryParam: (name: string) => string | undefined;
|
|
13
|
+
bodyParam: <T>(name: string) => T | undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface AlpParamsRequest {
|
|
17
|
+
searchParams: URLSearchParams;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function alpParams(app: AlpNodeApp): void {
|
|
21
|
+
Object.assign(app.context, {
|
|
22
|
+
namedRouteParam(this: Context, name: string): string | undefined {
|
|
23
|
+
const namedParams = this.route.namedParams;
|
|
24
|
+
return namedParams?.get(name);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
otherRouteParam(this: Context, position: number): string | undefined {
|
|
28
|
+
const otherParams = this.route.otherParams;
|
|
29
|
+
return otherParams?.[position - 1];
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
queryParam(this: Context, name: string): string | undefined {
|
|
33
|
+
const searchParams = this.request.searchParams;
|
|
34
|
+
return searchParams.get(name) ?? undefined;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
bodyParam<T>(this: Context, name: string): T | undefined {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
|
|
39
|
+
return (this.body as any)[name];
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
defineLazyProperty(
|
|
44
|
+
app.request,
|
|
45
|
+
'searchParams',
|
|
46
|
+
function (this: Context['request']): URLSearchParams {
|
|
47
|
+
return new URLSearchParams(this.search);
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
defineLazyProperty(
|
|
52
|
+
app.context,
|
|
53
|
+
'params',
|
|
54
|
+
function (this: Context): ParamValueFromContext {
|
|
55
|
+
return new ParamValueFromContext(this, new ParamValidationResult());
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
defineLazyProperty(
|
|
60
|
+
app.context,
|
|
61
|
+
'validParams',
|
|
62
|
+
function (this: Context): ParamValueFromContext {
|
|
63
|
+
return new ParamValueFromContext(this, new ParamValid(this));
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
}
|
package/src/router.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Router,
|
|
3
|
+
LocaleType,
|
|
4
|
+
RouterBuilder,
|
|
5
|
+
RouteMatch,
|
|
6
|
+
} from 'router-segments';
|
|
7
|
+
import { createRouterBuilder } from 'router-segments';
|
|
8
|
+
import type { AlpNodeApp, Context } from './AlpNodeApp';
|
|
9
|
+
|
|
10
|
+
export type AlpRouter<Locales extends LocaleType> = Router<
|
|
11
|
+
Locales,
|
|
12
|
+
AlpRouteRef
|
|
13
|
+
>;
|
|
14
|
+
export type AlpRouteRef = (ctx: Context) => Promise<void> | void;
|
|
15
|
+
type ReturnType = (app: AlpNodeApp) => AlpRouteRef;
|
|
16
|
+
|
|
17
|
+
export interface RouterContext {
|
|
18
|
+
route: RouteMatch<any, AlpRouteRef>;
|
|
19
|
+
}
|
|
20
|
+
export const createAlpRouterBuilder = <
|
|
21
|
+
Locales extends LocaleType,
|
|
22
|
+
>(): RouterBuilder<Locales, AlpRouteRef> =>
|
|
23
|
+
createRouterBuilder<Locales, AlpRouteRef>();
|
|
24
|
+
|
|
25
|
+
export type UrlGenerator = <P extends Record<string, unknown> | undefined>(
|
|
26
|
+
routeKey: string,
|
|
27
|
+
params?: P,
|
|
28
|
+
) => string;
|
|
29
|
+
|
|
30
|
+
export default function alpRouter<Locales extends string>(
|
|
31
|
+
router: Router<Locales, AlpRouteRef>,
|
|
32
|
+
): ReturnType {
|
|
33
|
+
return (app: AlpNodeApp) => {
|
|
34
|
+
app.router = router;
|
|
35
|
+
|
|
36
|
+
app.context.urlGenerator = function <
|
|
37
|
+
P extends Record<string, unknown> | undefined,
|
|
38
|
+
>(this: Context, routeKey: string, params?: P): string {
|
|
39
|
+
return router.toLocalizedPath(this.language as Locales, routeKey, params);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
app.context.redirectTo = function <
|
|
43
|
+
P extends Record<string, unknown> | undefined,
|
|
44
|
+
>(this: Context, to: string, params?: P): void {
|
|
45
|
+
this.redirect(
|
|
46
|
+
router.toLocalizedPath(this.language as Locales, to, params),
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return async (ctx: Context): Promise<void> => {
|
|
51
|
+
// eslint-disable-next-line unicorn/no-array-method-this-argument
|
|
52
|
+
const routeMatch = router.find(ctx.request.path, ctx.language as Locales);
|
|
53
|
+
|
|
54
|
+
if (!routeMatch) {
|
|
55
|
+
ctx.status = 404;
|
|
56
|
+
throw new Error(`Route not found: ${ctx.request.path}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ctx.route = routeMatch;
|
|
60
|
+
|
|
61
|
+
await routeMatch.ref(ctx);
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Logger } from 'nightingale-logger';
|
|
2
|
+
import type { AlpNodeApp, Context } from '../AlpNodeApp';
|
|
3
|
+
import type { Translations } from './load';
|
|
4
|
+
import load from './load';
|
|
5
|
+
|
|
6
|
+
const logger = new Logger('alp:translate');
|
|
7
|
+
|
|
8
|
+
type Args = Record<string, any>;
|
|
9
|
+
|
|
10
|
+
export interface TranslateBaseContext {
|
|
11
|
+
t: (id: string, args: Args) => string;
|
|
12
|
+
}
|
|
13
|
+
export interface TranslateContext {
|
|
14
|
+
readonly language: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function alpTranslate(
|
|
18
|
+
dirname: string,
|
|
19
|
+
): (app: AlpNodeApp) => void {
|
|
20
|
+
dirname = dirname.replace(/\/*$/, '/');
|
|
21
|
+
return (app: AlpNodeApp) => {
|
|
22
|
+
const appTranslations = new Map<string, Translations>();
|
|
23
|
+
|
|
24
|
+
Object.assign(app.context, {
|
|
25
|
+
t(this: Context, id: string, args: Args): string {
|
|
26
|
+
const msg = appTranslations.get(this.language)!.get(id);
|
|
27
|
+
if (!msg) {
|
|
28
|
+
logger.warn('invalid msg', { language: this.language, id });
|
|
29
|
+
return id;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return msg.format(args) as string;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const config = app.config;
|
|
37
|
+
|
|
38
|
+
config.get<string[]>('availableLanguages').forEach((language) => {
|
|
39
|
+
const translations = app.loadConfigSync(dirname + language);
|
|
40
|
+
appTranslations.set(language, load(translations, language));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return appTranslations;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import IntlMessageFormatDefault from 'intl-messageformat';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4
|
+
const IntlMessageFormat: typeof IntlMessageFormatDefault =
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
6
|
+
(IntlMessageFormatDefault as any).default || IntlMessageFormatDefault;
|
|
7
|
+
|
|
8
|
+
export type Translations = ReadonlyMap<string, IntlMessageFormatDefault>;
|
|
9
|
+
|
|
10
|
+
export default function load(
|
|
11
|
+
translations: ReadonlyMap<string, unknown>,
|
|
12
|
+
language: string,
|
|
13
|
+
): Translations {
|
|
14
|
+
const result = new Map();
|
|
15
|
+
|
|
16
|
+
(function loadMap(map, prefix) {
|
|
17
|
+
map.forEach((value: any, key) => {
|
|
18
|
+
if (typeof value === 'object') {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
20
|
+
loadMap(value, `${prefix}${key}.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
25
|
+
result.set(`${prefix}${key}`, new IntlMessageFormat(value, language));
|
|
26
|
+
});
|
|
27
|
+
})(translations, '');
|
|
28
|
+
|
|
29
|
+
return result;
|
|
30
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
type RawConfig = ReadonlyMap<string, any>;
|
|
2
|
+
|
|
3
|
+
export interface Config {
|
|
4
|
+
get: <T>(key: string) => T;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type PackageConfig = Record<string, any>;
|
|
8
|
+
|
|
9
|
+
export interface NodeConfig extends Config {
|
|
10
|
+
loadConfigSync: (name: string) => RawConfig;
|
|
11
|
+
readonly packageConfig: PackageConfig;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
15
|
+
export interface ContextState {}
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
18
|
+
export interface ContextSanitizedState {}
|
|
19
|
+
|
|
20
|
+
export interface BaseContext {
|
|
21
|
+
config: Config;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Context extends BaseContext {
|
|
25
|
+
state: ContextState;
|
|
26
|
+
sanitizedState: ContextSanitizedState;
|
|
27
|
+
status: number;
|
|
28
|
+
|
|
29
|
+
response: any;
|
|
30
|
+
redirect: (url: string) => Promise<void>;
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ApplicationInCreation {
|
|
35
|
+
config?: Config;
|
|
36
|
+
context: BaseContext;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Application extends ApplicationInCreation {
|
|
40
|
+
config: Config;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface NodeApplicationInCreation extends ApplicationInCreation {
|
|
44
|
+
loadConfigSync: (name: string) => RawConfig;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface BrowserApplicationInCreation extends ApplicationInCreation {
|
|
48
|
+
appVersion: string;
|
|
49
|
+
existsConfig: (name: string) => Promise<boolean> | boolean;
|
|
50
|
+
loadConfig: (name: string) => Promise<RawConfig>;
|
|
51
|
+
createContext: () => Context;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface NodeApplication
|
|
55
|
+
extends Application,
|
|
56
|
+
NodeApplicationInCreation {
|
|
57
|
+
config: NodeConfig;
|
|
58
|
+
dirname: string;
|
|
59
|
+
on: (event: 'close', callback: () => void) => void;
|
|
60
|
+
existsConfigSync: (name: string) => boolean;
|
|
61
|
+
loadConfigSync: (name: string) => RawConfig;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface HtmlError extends Error {
|
|
65
|
+
status: number;
|
|
66
|
+
expose?: true;
|
|
67
|
+
}
|