@platforma-sdk/model 1.2.22
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/dist/index.cjs +779 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +728 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -0
- package/src/.gitignore +1 -0
- package/src/block_api.ts +75 -0
- package/src/block_state_patch.ts +10 -0
- package/src/block_state_util.ts +30 -0
- package/src/branding.ts +4 -0
- package/src/builder.ts +345 -0
- package/src/components/PlDataTable.ts +42 -0
- package/src/components/index.ts +1 -0
- package/src/config/actions.ts +428 -0
- package/src/config/actions_kinds.ts +241 -0
- package/src/config/index.ts +6 -0
- package/src/config/model.ts +197 -0
- package/src/config/model_meta.ts +5 -0
- package/src/config/type_engine.ts +58 -0
- package/src/config/type_util.ts +25 -0
- package/src/index.ts +15 -0
- package/src/internal.ts +56 -0
- package/src/pframe.ts +39 -0
- package/src/platforma.ts +46 -0
- package/src/ref_util.ts +16 -0
- package/src/render/accessor.ts +223 -0
- package/src/render/api.ts +170 -0
- package/src/render/future.ts +37 -0
- package/src/render/index.ts +5 -0
- package/src/render/internal.ts +164 -0
- package/src/render/traversal_ops.ts +55 -0
- package/src/sdk_info.ts +9 -0
- package/src/typing.test.ts +177 -0
- package/src/unionize.ts +12 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Option,
|
|
3
|
+
PColumn,
|
|
4
|
+
PFrameDef,
|
|
5
|
+
PFrameHandle,
|
|
6
|
+
PObject,
|
|
7
|
+
PObjectSpec,
|
|
8
|
+
PSpecPredicate,
|
|
9
|
+
PTableDef,
|
|
10
|
+
PTableHandle,
|
|
11
|
+
PTableRecordFilter,
|
|
12
|
+
PTableSorting,
|
|
13
|
+
ResultCollection,
|
|
14
|
+
ValueOrError,
|
|
15
|
+
mapPObjectData,
|
|
16
|
+
mapPTableDef,
|
|
17
|
+
mapValueInVOE
|
|
18
|
+
} from '@milaboratories/pl-model-common';
|
|
19
|
+
import { Optional } from 'utility-types';
|
|
20
|
+
import { getCfgRenderCtx } from '../internal';
|
|
21
|
+
import { TreeNodeAccessor } from './accessor';
|
|
22
|
+
import { FutureRef } from './future';
|
|
23
|
+
import { GlobalCfgRenderCtx, MainAccessorName, StagingAccessorName } from './internal';
|
|
24
|
+
|
|
25
|
+
export class ResultPool {
|
|
26
|
+
private readonly ctx: GlobalCfgRenderCtx = getCfgRenderCtx();
|
|
27
|
+
|
|
28
|
+
public calculateOptions(predicate: PSpecPredicate): Option[] {
|
|
29
|
+
return this.ctx.calculateOptions(predicate);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public getDataFromResultPool(): ResultCollection<PObject<TreeNodeAccessor>> {
|
|
33
|
+
const result = this.ctx.getDataFromResultPool();
|
|
34
|
+
return {
|
|
35
|
+
isComplete: result.isComplete,
|
|
36
|
+
entries: result.entries.map((e) => ({
|
|
37
|
+
ref: e.ref,
|
|
38
|
+
obj: {
|
|
39
|
+
...e.obj,
|
|
40
|
+
data: new TreeNodeAccessor(e.obj.data)
|
|
41
|
+
}
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public getDataWithErrorsFromResultPool(): ResultCollection<
|
|
47
|
+
Optional<PObject<ValueOrError<TreeNodeAccessor, string>>, 'id'>
|
|
48
|
+
> {
|
|
49
|
+
const result = this.ctx.getDataWithErrorsFromResultPool();
|
|
50
|
+
return {
|
|
51
|
+
isComplete: result.isComplete,
|
|
52
|
+
entries: result.entries.map((e) => ({
|
|
53
|
+
ref: e.ref,
|
|
54
|
+
obj: {
|
|
55
|
+
...e.obj,
|
|
56
|
+
data: mapValueInVOE(e.obj.data, (handle) => new TreeNodeAccessor(handle))
|
|
57
|
+
}
|
|
58
|
+
}))
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public getSpecsFromResultPool(): ResultCollection<PObjectSpec> {
|
|
63
|
+
return this.ctx.getSpecsFromResultPool();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class RenderCtx<Args, UiState> {
|
|
68
|
+
private readonly ctx: GlobalCfgRenderCtx;
|
|
69
|
+
|
|
70
|
+
public readonly args: Args;
|
|
71
|
+
public readonly uiState: UiState | undefined;
|
|
72
|
+
|
|
73
|
+
constructor() {
|
|
74
|
+
this.ctx = getCfgRenderCtx();
|
|
75
|
+
this.args = JSON.parse(this.ctx.args);
|
|
76
|
+
this.uiState = this.ctx.uiState !== undefined ? JSON.parse(this.ctx.uiState) : undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private getNamedAccessor(name: string): TreeNodeAccessor | undefined {
|
|
80
|
+
const accessorId = this.ctx.getAccessorHandleByName(name);
|
|
81
|
+
return accessorId ? new TreeNodeAccessor(accessorId) : undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get prerun(): TreeNodeAccessor | undefined {
|
|
85
|
+
return this.getNamedAccessor(StagingAccessorName);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @deprecated use prerun
|
|
90
|
+
*/
|
|
91
|
+
public get precalc(): TreeNodeAccessor | undefined {
|
|
92
|
+
return this.prerun;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @deprecated use prerun
|
|
97
|
+
*/
|
|
98
|
+
public get stagingOutput(): TreeNodeAccessor | undefined {
|
|
99
|
+
return this.precalc;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public get outputs(): TreeNodeAccessor | undefined {
|
|
103
|
+
return this.getNamedAccessor(MainAccessorName);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @deprecated use outputs
|
|
108
|
+
*/
|
|
109
|
+
public get mainOutput(): TreeNodeAccessor | undefined {
|
|
110
|
+
return this.outputs;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public readonly resultPool = new ResultPool();
|
|
114
|
+
|
|
115
|
+
public createPFrame(def: PFrameDef<TreeNodeAccessor>): PFrameHandle {
|
|
116
|
+
return this.ctx.createPFrame(def.map((c) => mapPObjectData(c, (d) => d.handle)));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public createPTable(def: PTableDef<PColumn<TreeNodeAccessor>>): PTableHandle;
|
|
120
|
+
public createPTable(def: {
|
|
121
|
+
columns: PColumn<TreeNodeAccessor>[];
|
|
122
|
+
filters?: PTableRecordFilter[];
|
|
123
|
+
/** Table sorting */
|
|
124
|
+
sorting?: PTableSorting[];
|
|
125
|
+
}): PTableHandle;
|
|
126
|
+
public createPTable(
|
|
127
|
+
def:
|
|
128
|
+
| PTableDef<PColumn<TreeNodeAccessor>>
|
|
129
|
+
| {
|
|
130
|
+
columns: PColumn<TreeNodeAccessor>[];
|
|
131
|
+
filters?: PTableRecordFilter[];
|
|
132
|
+
/** Table sorting */
|
|
133
|
+
sorting?: PTableSorting[];
|
|
134
|
+
}
|
|
135
|
+
): PTableHandle {
|
|
136
|
+
var rawDef: PTableDef<PColumn<TreeNodeAccessor>>;
|
|
137
|
+
if ('columns' in def) {
|
|
138
|
+
rawDef = {
|
|
139
|
+
src: {
|
|
140
|
+
type: 'inner',
|
|
141
|
+
entries: def.columns.map((c) => ({ type: 'column', column: c }))
|
|
142
|
+
},
|
|
143
|
+
filters: def.filters ?? [],
|
|
144
|
+
sorting: def.sorting ?? []
|
|
145
|
+
};
|
|
146
|
+
} else {
|
|
147
|
+
rawDef = def;
|
|
148
|
+
}
|
|
149
|
+
return this.ctx.createPTable(mapPTableDef(rawDef, (po) => mapPObjectData(po, (d) => d.handle)));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public getBlockLabel(blockId: string): string {
|
|
153
|
+
return this.ctx.getBlockLabel(blockId);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type RenderFunction<Args = unknown, UiState = unknown, Ret = unknown> = (
|
|
158
|
+
rCtx: RenderCtx<Args, UiState>
|
|
159
|
+
) => Ret;
|
|
160
|
+
|
|
161
|
+
export type UnwrapFutureRef<K> =
|
|
162
|
+
K extends FutureRef<infer T>
|
|
163
|
+
? T
|
|
164
|
+
: K extends bigint | boolean | null | number | string | symbol | undefined
|
|
165
|
+
? K
|
|
166
|
+
: { [key in keyof K]: UnwrapFutureRef<K[key]> };
|
|
167
|
+
|
|
168
|
+
export type InferRenderFunctionReturn<RF extends Function> = RF extends (...args: any) => infer R
|
|
169
|
+
? UnwrapFutureRef<R>
|
|
170
|
+
: never;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FutureAwait, FutureHandle } from './internal';
|
|
2
|
+
import { registerFutureAwait } from '../internal';
|
|
3
|
+
|
|
4
|
+
export class FutureRef<T = unknown> {
|
|
5
|
+
private isResolved = false;
|
|
6
|
+
private resolvedValue?: T;
|
|
7
|
+
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly handle: FutureHandle,
|
|
10
|
+
private readonly postProcess: (value: unknown) => T = (v) => v as T
|
|
11
|
+
) {
|
|
12
|
+
registerFutureAwait(handle, (value) => {
|
|
13
|
+
this.resolvedValue = postProcess(value);
|
|
14
|
+
this.isResolved = true;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public map<R>(mapping: (v: T) => R): FutureRef<R> {
|
|
19
|
+
return new FutureRef<R>(this.handle, (v) => mapping(this.postProcess(v)));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public mapDefined<R>(mapping: (v: NonNullable<T>) => R): FutureRef<R | undefined> {
|
|
23
|
+
return new FutureRef<R | undefined>(this.handle, (v) => {
|
|
24
|
+
const vv = this.postProcess(v);
|
|
25
|
+
return vv ? mapping(vv) : undefined;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
toJSON(): any {
|
|
30
|
+
return this.isResolved
|
|
31
|
+
? this.resolvedValue
|
|
32
|
+
: ({ __awaited_futures__: [this.handle] } as FutureAwait);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ExtractFutureRefType<Ref extends FutureRef> =
|
|
37
|
+
Ref extends FutureRef<infer T> ? T : never;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Optional } from 'utility-types';
|
|
2
|
+
import { Branded } from '../branding';
|
|
3
|
+
import { CommonFieldTraverseOps, FieldTraversalStep, ResourceType } from './traversal_ops';
|
|
4
|
+
import {
|
|
5
|
+
Option,
|
|
6
|
+
PColumn,
|
|
7
|
+
PFrameDef,
|
|
8
|
+
PFrameHandle,
|
|
9
|
+
PObject,
|
|
10
|
+
PObjectSpec,
|
|
11
|
+
PSpecPredicate,
|
|
12
|
+
PTableDef,
|
|
13
|
+
PTableHandle,
|
|
14
|
+
ResultCollection,
|
|
15
|
+
ValueOrError
|
|
16
|
+
} from '@milaboratories/pl-model-common';
|
|
17
|
+
|
|
18
|
+
export const StagingAccessorName = 'staging';
|
|
19
|
+
export const MainAccessorName = 'main';
|
|
20
|
+
|
|
21
|
+
export type AccessorHandle = Branded<string, 'AccessorHandle'>;
|
|
22
|
+
export type FutureHandle = Branded<string, 'FutureHandle'>;
|
|
23
|
+
|
|
24
|
+
export interface GlobalCfgRenderCtxMethods<AHandle = AccessorHandle, FHandle = FutureHandle> {
|
|
25
|
+
//
|
|
26
|
+
// Root accessor creation
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
getAccessorHandleByName(name: string): AHandle | undefined;
|
|
30
|
+
|
|
31
|
+
//
|
|
32
|
+
// Basic resource accessor actions
|
|
33
|
+
//
|
|
34
|
+
|
|
35
|
+
resolveWithCommon(
|
|
36
|
+
handle: AHandle,
|
|
37
|
+
commonOptions: CommonFieldTraverseOps,
|
|
38
|
+
...steps: (FieldTraversalStep | string)[]
|
|
39
|
+
): AHandle | undefined;
|
|
40
|
+
|
|
41
|
+
getResourceType(handle: AHandle): ResourceType;
|
|
42
|
+
|
|
43
|
+
getInputsLocked(handle: AHandle): boolean;
|
|
44
|
+
|
|
45
|
+
getOutputsLocked(handle: AHandle): boolean;
|
|
46
|
+
|
|
47
|
+
getIsReadyOrError(handle: AHandle): boolean;
|
|
48
|
+
|
|
49
|
+
getIsFinal(handle: AHandle): boolean;
|
|
50
|
+
|
|
51
|
+
getError(handle: AHandle): AHandle | undefined;
|
|
52
|
+
|
|
53
|
+
listInputFields(handle: AHandle): string[];
|
|
54
|
+
|
|
55
|
+
listOutputFields(handle: AHandle): string[];
|
|
56
|
+
|
|
57
|
+
listDynamicFields(handle: AHandle): string[];
|
|
58
|
+
|
|
59
|
+
getKeyValueBase64(handle: AHandle, key: string): string | undefined;
|
|
60
|
+
|
|
61
|
+
getKeyValueAsString(handle: AHandle, key: string): string | undefined;
|
|
62
|
+
|
|
63
|
+
getDataBase64(handle: AHandle): string | undefined;
|
|
64
|
+
|
|
65
|
+
getDataAsString(handle: AHandle): string | undefined;
|
|
66
|
+
|
|
67
|
+
/** If not final returns undefined */
|
|
68
|
+
parsePObjectCollection(
|
|
69
|
+
handle: AHandle,
|
|
70
|
+
errorOnUnknownField: boolean,
|
|
71
|
+
prefix: string
|
|
72
|
+
): Record<string, PObject<AHandle>> | undefined;
|
|
73
|
+
|
|
74
|
+
//
|
|
75
|
+
// Blob
|
|
76
|
+
//
|
|
77
|
+
|
|
78
|
+
getBlobContentAsBase64(handle: AHandle): FHandle; // string | undefined
|
|
79
|
+
|
|
80
|
+
getBlobContentAsString(handle: AHandle): FHandle; // string | undefined
|
|
81
|
+
|
|
82
|
+
getDownloadedBlobContentHandle(handle: AHandle): FHandle; // LocalBlobHandleAndSize | undefined;
|
|
83
|
+
|
|
84
|
+
getOnDemandBlobContentHandle(handle: AHandle): FHandle; // RemoteBlobHandleAndSize | undefined;
|
|
85
|
+
|
|
86
|
+
//
|
|
87
|
+
// Import progress
|
|
88
|
+
//
|
|
89
|
+
|
|
90
|
+
getImportProgress(handle: AHandle): FHandle; // ImportProgress;
|
|
91
|
+
|
|
92
|
+
//
|
|
93
|
+
// Logs
|
|
94
|
+
//
|
|
95
|
+
|
|
96
|
+
getLastLogs(handle: AHandle, nLines: number): FHandle; // string | undefined;
|
|
97
|
+
|
|
98
|
+
getProgressLog(handle: AHandle, patternToSearch: string): FHandle; // string | undefined;
|
|
99
|
+
|
|
100
|
+
getLogHandle(handle: AHandle): FHandle; // AnyLogHandle | undefined;
|
|
101
|
+
|
|
102
|
+
//
|
|
103
|
+
// Blocks
|
|
104
|
+
//
|
|
105
|
+
|
|
106
|
+
getBlockLabel(blockId: string): string;
|
|
107
|
+
|
|
108
|
+
//
|
|
109
|
+
// Result Pool
|
|
110
|
+
//
|
|
111
|
+
|
|
112
|
+
getDataFromResultPool(): ResultCollection<PObject<AHandle>>;
|
|
113
|
+
|
|
114
|
+
getDataWithErrorsFromResultPool(): ResultCollection<
|
|
115
|
+
Optional<PObject<ValueOrError<AHandle, string>>, 'id'>
|
|
116
|
+
>;
|
|
117
|
+
|
|
118
|
+
getSpecsFromResultPool(): ResultCollection<PObjectSpec>;
|
|
119
|
+
|
|
120
|
+
calculateOptions(predicate: PSpecPredicate): Option[];
|
|
121
|
+
|
|
122
|
+
//
|
|
123
|
+
// PFrame / PTable
|
|
124
|
+
//
|
|
125
|
+
|
|
126
|
+
createPFrame(def: PFrameDef<AHandle>): PFrameHandle;
|
|
127
|
+
|
|
128
|
+
createPTable(def: PTableDef<PColumn<AHandle>>): PTableHandle;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface GlobalCfgRenderCtx extends GlobalCfgRenderCtxMethods {
|
|
132
|
+
readonly args: string;
|
|
133
|
+
readonly uiState?: string;
|
|
134
|
+
readonly callbackRegistry: Record<string, Function>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type FutureAwait = {
|
|
138
|
+
__awaited_futures__: FutureHandle[];
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export function isFutureAwait(obj: unknown): obj is FutureAwait {
|
|
142
|
+
return typeof obj === 'object' && obj !== null && '__awaited_futures__' in obj;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function addAllFutureAwaits(set: Set<string>, visited: Set<unknown>, node: unknown) {
|
|
146
|
+
if (visited.has(node)) return;
|
|
147
|
+
visited.add(node);
|
|
148
|
+
|
|
149
|
+
const type = typeof node;
|
|
150
|
+
if (type === 'object') {
|
|
151
|
+
if (isFutureAwait(node)) node.__awaited_futures__.forEach((a) => set.add(a));
|
|
152
|
+
else if (Array.isArray(node))
|
|
153
|
+
for (const nested of node) addAllFutureAwaits(set, visited, nested);
|
|
154
|
+
else
|
|
155
|
+
for (const [, nested] of Object.entries(node as object))
|
|
156
|
+
if (nested !== node) addAllFutureAwaits(set, visited, nested);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function getAllFutureAwaits(obj: unknown): Set<string> {
|
|
161
|
+
const set = new Set<string>();
|
|
162
|
+
addAllFutureAwaits(set, new Set(), obj);
|
|
163
|
+
return set;
|
|
164
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type CommonTraversalOps = {
|
|
2
|
+
/**
|
|
3
|
+
* Don't terminate chain if current resource or field has an error associated
|
|
4
|
+
* with, by default resource or field error will be thrown. If field has error
|
|
5
|
+
* and no value, error will be thrown anyway, because this is the reason
|
|
6
|
+
* traversal is terminated.
|
|
7
|
+
* */
|
|
8
|
+
ignoreError?: true;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CommonFieldTraverseOps = {
|
|
12
|
+
/**
|
|
13
|
+
* Valid only if {@link assertFieldType} is defined and equal to 'Input',
|
|
14
|
+
* 'Service' or 'Output'. By default, if field is not found, and corresponding
|
|
15
|
+
* field list is locked, call will fail with exception.
|
|
16
|
+
* */
|
|
17
|
+
allowPermanentAbsence?: true;
|
|
18
|
+
|
|
19
|
+
/** Will not mark current context as unstable, if field is not found. */
|
|
20
|
+
stableIfNotFound?: true;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type FieldType = 'Input' | 'Output' | 'Service' | 'OTW' | 'Dynamic' | 'MTW';
|
|
24
|
+
|
|
25
|
+
export interface ResourceType {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly version: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ResourceTraversalOps = CommonTraversalOps & {
|
|
31
|
+
/**
|
|
32
|
+
* Assert resource type of the resource the fields points to. Call will fail
|
|
33
|
+
* with exception if this assertion is not fulfilled.
|
|
34
|
+
* */
|
|
35
|
+
assertResourceType?: ResourceType | ResourceType[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type GetFieldStep = CommonFieldTraverseOps & {
|
|
39
|
+
/** Field name */
|
|
40
|
+
field: string;
|
|
41
|
+
|
|
42
|
+
/** Field must exist, if this option is set, instead error will be thrown */
|
|
43
|
+
errorIfFieldNotFound?: true;
|
|
44
|
+
|
|
45
|
+
/** Field must be assigned a value, if this option is set, instead error will be thrown */
|
|
46
|
+
errorIfFieldNotSet?: true;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Assert field type. Call will fail with exception if this assertion is not
|
|
50
|
+
* fulfilled
|
|
51
|
+
* */
|
|
52
|
+
assertFieldType?: FieldType;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type FieldTraversalStep = GetFieldStep & ResourceTraversalOps;
|
package/src/sdk_info.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlockSection,
|
|
3
|
+
LocalBlobHandleAndSize,
|
|
4
|
+
RemoteBlobHandleAndSize,
|
|
5
|
+
ValueOrErrors
|
|
6
|
+
} from '@milaboratories/pl-model-common';
|
|
7
|
+
import { BlockModel, DeriveHref, StdCtx } from './builder';
|
|
8
|
+
import {
|
|
9
|
+
Args,
|
|
10
|
+
ConfigResult,
|
|
11
|
+
flatten,
|
|
12
|
+
getBlobContent,
|
|
13
|
+
getBlobContentAsJson,
|
|
14
|
+
getBlobContentAsString,
|
|
15
|
+
getDownloadedBlobContent,
|
|
16
|
+
getImmediate,
|
|
17
|
+
getJsonField,
|
|
18
|
+
getOnDemandBlobContent,
|
|
19
|
+
getResourceField,
|
|
20
|
+
getResourceValueAsJson,
|
|
21
|
+
isEmpty,
|
|
22
|
+
It,
|
|
23
|
+
MainOutputs,
|
|
24
|
+
makeArray,
|
|
25
|
+
makeObject,
|
|
26
|
+
mapArrayValues,
|
|
27
|
+
mapRecordValues
|
|
28
|
+
} from './config';
|
|
29
|
+
import { InferHrefType, InferOutputsType } from './platforma';
|
|
30
|
+
|
|
31
|
+
type AssertEqual<T, Expected> = [T] extends [Expected]
|
|
32
|
+
? [Expected] extends [T]
|
|
33
|
+
? true
|
|
34
|
+
: false
|
|
35
|
+
: false;
|
|
36
|
+
|
|
37
|
+
export const assertType = <T, Expected>(
|
|
38
|
+
..._: AssertEqual<T, Expected> extends true ? [] : ['invalid type']
|
|
39
|
+
) => {
|
|
40
|
+
// noop
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type AssertExtends<T, Expected> = T extends Expected ? true : false;
|
|
44
|
+
|
|
45
|
+
export const assertTypeExtends = <T, Expected>(
|
|
46
|
+
..._: AssertExtends<T, Expected> extends true ? [] : ['invalid type']
|
|
47
|
+
) => {
|
|
48
|
+
// noop
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function typeTest1() {
|
|
52
|
+
const a = getJsonField(Args, 'field1');
|
|
53
|
+
const dd = getResourceValueAsJson<{ s: boolean; g: number }>()(
|
|
54
|
+
getResourceField(MainOutputs, 'a')
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const cfg1 = makeObject({
|
|
58
|
+
a,
|
|
59
|
+
b: 'attagaca',
|
|
60
|
+
c: mapRecordValues(getJsonField(Args, 'field2'), getJsonField(It, 'b')),
|
|
61
|
+
d: getJsonField(dd, 's')
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
type Ret = ConfigResult<
|
|
65
|
+
typeof cfg1,
|
|
66
|
+
StdCtx<{
|
|
67
|
+
field1: number;
|
|
68
|
+
field2: Record<string, { b: 'yap' }>;
|
|
69
|
+
}>
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
assertType<
|
|
73
|
+
Ret,
|
|
74
|
+
{
|
|
75
|
+
a: number;
|
|
76
|
+
b: 'attagaca';
|
|
77
|
+
c: Record<string, 'yap'>;
|
|
78
|
+
d: boolean;
|
|
79
|
+
}
|
|
80
|
+
>();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function testCreateSections<const S extends BlockSection[]>(sections: () => S): DeriveHref<S> {
|
|
84
|
+
return undefined as any;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
test('test config content', () => {
|
|
88
|
+
const s1 = testCreateSections(() => [
|
|
89
|
+
{ type: 'delimiter' },
|
|
90
|
+
{ type: 'link', href: '/a1', label: 'l' },
|
|
91
|
+
{ type: 'link', href: '/a2', label: 'ls' }
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
assertType<typeof s1, '/a1' | '/a2'>();
|
|
95
|
+
|
|
96
|
+
const s2 = testCreateSections(() => [{ type: 'delimiter' }]);
|
|
97
|
+
|
|
98
|
+
assertType<typeof s2, never>();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('test config content', () => {
|
|
102
|
+
const platforma = BlockModel.create<{ a: string[] }>('Heavy')
|
|
103
|
+
.initialArgs({ a: [] })
|
|
104
|
+
.output('cell1', makeObject({ b: getJsonField(Args, 'a') }))
|
|
105
|
+
.output('cell2', mapArrayValues(getJsonField(Args, 'a'), getImmediate('v1')))
|
|
106
|
+
.inputsValid(isEmpty(getJsonField(Args, 'a')))
|
|
107
|
+
.sections((r) => {
|
|
108
|
+
return [
|
|
109
|
+
{ type: 'link', href: '/', label: 'Main' },
|
|
110
|
+
{ type: 'link', href: '/subsection', label: 'Subsection' }
|
|
111
|
+
];
|
|
112
|
+
})
|
|
113
|
+
.done();
|
|
114
|
+
|
|
115
|
+
assertType<
|
|
116
|
+
InferOutputsType<typeof platforma>,
|
|
117
|
+
{
|
|
118
|
+
cell1: ValueOrErrors<{ b: string[] }>;
|
|
119
|
+
cell2: ValueOrErrors<'v1'[]>;
|
|
120
|
+
}
|
|
121
|
+
>();
|
|
122
|
+
|
|
123
|
+
assertType<InferHrefType<typeof platforma>, '/' | '/subsection'>();
|
|
124
|
+
|
|
125
|
+
expect(JSON.stringify((platforma as any).config).length).toBeGreaterThan(20);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('test config 2', () => {
|
|
129
|
+
const platforma = BlockModel.create<{ a: string[] }>('Heavy')
|
|
130
|
+
.initialArgs({ a: [] })
|
|
131
|
+
.output(
|
|
132
|
+
'cell1',
|
|
133
|
+
makeObject({
|
|
134
|
+
b: getBlobContentAsString(getResourceField(MainOutputs, 'field1')),
|
|
135
|
+
c: makeArray(getBlobContent(getResourceField(MainOutputs, 'field2')), 'asd'),
|
|
136
|
+
d: getBlobContentAsJson<string[]>()(getResourceField(MainOutputs, 'field3')),
|
|
137
|
+
e: flatten(
|
|
138
|
+
makeArray(
|
|
139
|
+
getBlobContentAsJson<string[]>()(getResourceField(MainOutputs, 'field3')),
|
|
140
|
+
getImmediate(['asd', 'd'] as string[])
|
|
141
|
+
)
|
|
142
|
+
),
|
|
143
|
+
f: getDownloadedBlobContent(getResourceField(MainOutputs, 'field4')),
|
|
144
|
+
g: getOnDemandBlobContent(getResourceField(MainOutputs, 'field5'))
|
|
145
|
+
})
|
|
146
|
+
)
|
|
147
|
+
.output('cell2', (ctx) => 42)
|
|
148
|
+
.output('cell3', () => undefined)
|
|
149
|
+
.inputsValid(isEmpty(getJsonField(Args, 'a')))
|
|
150
|
+
.sections(
|
|
151
|
+
getImmediate([
|
|
152
|
+
{ type: 'link', href: '/', label: 'Main' },
|
|
153
|
+
{ type: 'link', href: '/subsection', label: 'Subsection' }
|
|
154
|
+
])
|
|
155
|
+
)
|
|
156
|
+
.done();
|
|
157
|
+
|
|
158
|
+
assertType<
|
|
159
|
+
InferOutputsType<typeof platforma>,
|
|
160
|
+
{
|
|
161
|
+
cell1: ValueOrErrors<{
|
|
162
|
+
b: string;
|
|
163
|
+
c: [Uint8Array, 'asd'];
|
|
164
|
+
d: string[];
|
|
165
|
+
e: string[];
|
|
166
|
+
f: LocalBlobHandleAndSize;
|
|
167
|
+
g: RemoteBlobHandleAndSize;
|
|
168
|
+
}>;
|
|
169
|
+
cell2: ValueOrErrors<number>;
|
|
170
|
+
cell3: ValueOrErrors<undefined>;
|
|
171
|
+
}
|
|
172
|
+
>();
|
|
173
|
+
|
|
174
|
+
assertType<InferHrefType<typeof platforma>, '/' | '/subsection'>();
|
|
175
|
+
|
|
176
|
+
expect(JSON.stringify((platforma as any).config).length).toBeGreaterThan(20);
|
|
177
|
+
});
|
package/src/unionize.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Patch for the structural object */
|
|
2
|
+
export type Patch<K, V> = {
|
|
3
|
+
/** Field name to patch */
|
|
4
|
+
readonly key: K;
|
|
5
|
+
/** New value for the field */
|
|
6
|
+
readonly value: V;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/** Creates union type of all possible shallow patches for the given structure */
|
|
10
|
+
export type Unionize<T extends Record<string, unknown>> = {
|
|
11
|
+
[K in keyof T]: Patch<K, T[K]>;
|
|
12
|
+
}[keyof T];
|
package/src/version.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PlatformaSDKVersion = '1.2.22';
|