@golemui/core 0.0.2 → 0.12.1

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.
@@ -0,0 +1,3 @@
1
+ import { State } from '../model';
2
+ import * as Actions from '../actions';
3
+ export declare const setMeta: (state: State, action: Actions.SET_META) => State;
@@ -1,4 +1,3 @@
1
- import { DotPath } from '../../shared';
2
1
  import { State } from '../model';
3
2
  /**
4
3
  * Conditionally applies a reducer function based on a predicate
@@ -26,7 +25,6 @@ import { State } from '../model';
26
25
  * ```
27
26
  */
28
27
  export declare const reduceIf: (predicate: (state: State) => boolean, reducerFn: (state: State) => State) => (state: State) => State;
29
- export declare const isControlTouched: (widgetPath: DotPath) => (state: State) => boolean;
30
28
  export declare const hasWhen: (val: unknown) => val is {
31
29
  when: string;
32
30
  };
@@ -1,3 +1,4 @@
1
1
  import { ValidatorFn } from '../../form-validator';
2
+ import { I18nTranslator } from '../../i18n';
2
3
  import { State } from '../model';
3
- export declare const validateAll: (validators: ValidatorFn<any>) => (state: State) => State;
4
+ export declare const validateAll: (validators: ValidatorFn<any>, localization: I18nTranslator) => (state: State) => State;
@@ -5,7 +5,11 @@ import { State } from './model';
5
5
  export declare const dataByPath$: <T = any>(path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<T>>;
6
6
  export declare const validationByPath$: (path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<import('../shared').ValidationStatus>>;
7
7
  export declare const injectedValidationByPath$: (path: DotPath) => import('rxjs').UnaryFunction<Observable<State>, Observable<import('../shared').ValidationStatus>>;
8
- export declare const calculatedWidgetsByUid$: (uid: Uid) => import('rxjs').UnaryFunction<Observable<State>, Observable<import('../form-widget').NonFunctionWidget<string, any, any>>>;
8
+ /**
9
+ * Emits the current calculated widget for the given uid
10
+ * Re triggers on widget changes OR store.lang changes
11
+ */
12
+ export declare const calculatedWidgetsByUid$: (uid: Uid) => (state$: Observable<State>) => Observable<import('../form-widget').NonFunctionWidget<string, any, any>>;
9
13
  export declare const calculatedLayoutChildrenByUid$: (uid: Uid) => import('rxjs').UnaryFunction<Observable<State>, Observable<(import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, (import('../form-widget').DisplayWidget<never, any, any> | import('../form-widget').InputWidget<any, never, any, any, any> | LayoutWidget<never, any, any, /*elided*/ any> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]> | import('../form-widget').ActionWidget<never, any, any> | import('../form-widget').FunctionWidget<never, any, any>)[]>>;
10
14
  export declare const selectWidgetFlags: import('rxjs').UnaryFunction<Observable<State>, Observable<Record<string, {
11
15
  hidden?: boolean;
@@ -30,6 +30,66 @@ export declare const SKIP: unique symbol;
30
30
  * ```
31
31
  */
32
32
  export declare function filterMap<T, U>(array: readonly T[], fn: (value: T, index: number, array: readonly T[]) => U | typeof SKIP): U[];
33
+ /**
34
+ * Iterates over an array, executing a callback function only for elements
35
+ * that satisfy the provided predicate.
36
+ *
37
+ * This combines `filter` and `forEach` in a single pass without allocating
38
+ * intermediate arrays, improving performance and reducing garbage collection.
39
+ *
40
+ * @typeParam T - The type of the input array elements.
41
+ * @typeParam S - A narrower type of the elements that pass a type guard predicate.
42
+ *
43
+ * @param array - The source array to iterate over.
44
+ * @param predicate - A function that evaluates each element. If it returns truthy,
45
+ * the callback is executed.
46
+ * @param callback - A function to execute for each element that passes the predicate.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * filterTap(
51
+ * [1, 2, 3, 4],
52
+ * n => n % 2 === 0,
53
+ * n => console.log('Even:', n)
54
+ * );
55
+ * // "Even: 2", "Even: 4"
56
+ * ```
57
+ */
58
+ export declare function filterTap<T, S extends T>(array: readonly T[], predicate: (value: T, index: number, array: readonly T[]) => value is S, callback: (value: S, index: number, array: readonly T[]) => void): void;
59
+ export declare function filterTap<T>(array: readonly T[], predicate: (value: T, index: number, array: readonly T[]) => unknown, callback: (value: T, index: number, array: readonly T[]) => void): void;
60
+ /**
61
+ * Iterates over an array, filtering elements using a predicate, and
62
+ * accumulating a single result using a reducer function.
63
+ *
64
+ * This combines `filter` and `reduce` in a single pass without allocating
65
+ * intermediate arrays, improving performance and memory efficiency.
66
+ *
67
+ * @typeParam T - The type of the input array elements.
68
+ * @typeParam S - A narrower type of the elements that pass a type guard predicate.
69
+ * @typeParam U - The type of the accumulated value.
70
+ *
71
+ * @param array - The source array to iterate over.
72
+ * @param predicate - A function that evaluates each element. If truthy, the element
73
+ * is passed to the reducer.
74
+ * @param reducer - A function that accumulates the results.
75
+ * @param initialValue - The initial value to start the accumulation. Required to ensure
76
+ * safety in cases where no elements pass the predicate.
77
+ *
78
+ * @returns The final accumulated value.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const sumOfEvens = filterReduce(
83
+ * [1, 2, 3, 4, 5],
84
+ * n => n % 2 === 0,
85
+ * (acc, n) => acc + n,
86
+ * 0
87
+ * );
88
+ * // sumOfEvens: 6
89
+ * ```
90
+ */
91
+ export declare function filterReduce<T, S extends T, U>(array: readonly T[], predicate: (value: T, index: number, array: readonly T[]) => value is S, reducer: (accumulator: U, currentValue: S, index: number, array: readonly T[]) => U, initialValue: U): U;
92
+ export declare function filterReduce<T, U>(array: readonly T[], predicate: (value: T, index: number, array: readonly T[]) => unknown, reducer: (accumulator: U, currentValue: T, index: number, array: readonly T[]) => U, initialValue: U): U;
33
93
  /**
34
94
  * Compares two arrays for structural equality by applying a predicate
35
95
  * to each pair of elements.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Throws when properties in widget.props collide with base widget props, which should never happen.
3
+ * Only runs when dev mode is enabled via enableDevMode().
4
+ *
5
+ * @param widgetUid to describe which field has collisions
6
+ * @param props widget.props
7
+ * @param base widget props
8
+ */
9
+ export declare function assertNoPropCollisions(widgetUid: string, props: Record<string, unknown> | undefined, base: Record<string, unknown>): void;
@@ -0,0 +1,2 @@
1
+ export declare function enableDevMode(): void;
2
+ export declare function isDevMode(): boolean;
@@ -1,4 +1,55 @@
1
+ import { $Errors, DotPath } from '../shared';
2
+ import { State } from '../store/model';
1
3
  import * as Widget from '../form-widget';
4
+ /**
5
+ * Expression Scopes define the root namespaces accessible within
6
+ * reactive expressions and template strings.
7
+ */
8
+ export declare const EXPRESSION_SCOPE: {
9
+ readonly FORM: "$form";
10
+ readonly META: "$meta";
11
+ readonly ERRORS: "$errors";
12
+ readonly FORM_IS_INVALID: "$formIsInvalid";
13
+ };
14
+ /**
15
+ * Heuristically checks if a value looks like a scoped path
16
+ * rather than a standard string.
17
+ * To be considered a "potential" scoped path, the value must:
18
+ * 1. Be a string.
19
+ * 2. Start with one of the allowed prefixes ($form.*, $meta.*, etc..).
20
+ * 3. Not contain any spaces (distinguishing it from sentences).
21
+ *
22
+ * * @example
23
+ * isPotentialScopedPath('$form.user.id'); // true
24
+ * isPotentialScopedPath('name'); // false (No prefix)
25
+ * isPotentialScopedPath('my file'); // false (Contains space)
26
+ * isPotentialScopedPath(123); // false (Not a string)
27
+ */
28
+ export declare const isPotentialScopedPath: (path: unknown) => path is DotPath;
29
+ export interface ScopedPathResolvers {
30
+ resolveFormPath: (expr: string) => any;
31
+ resolveMetaPath: (expr: string) => any;
32
+ resolveErrorsPath: (expr: string) => any;
33
+ resolveFormIsInvalid: () => string | boolean;
34
+ }
35
+ /**
36
+ * Resolves all scoped path placeholders within a string in a single pass.
37
+ * e.g. "User {{ $form.name }} has status {{ $meta.status }} or {{ $formIsInvalid }}"
38
+ *
39
+ * @param input - The template string to process
40
+ * @param resolvers - Implementation of value resolution logic
41
+ * @returns The string with all valid placeholders replaced by their resolved values
42
+ */
43
+ export declare const resolveScopedPaths: (input: string, resolvers: ScopedPathResolvers) => string;
44
+ /**
45
+ * Resolves a scoped path to its underlying value using the
46
+ * appropriate resolver based on the path prefix (`$form.*`, `$meta.*`, `$errors.*` or `$formIsInvalid`).
47
+ *
48
+ * @param variable - A dot-notation path starting with `$form.`, `$meta.` or `$errors.`, or `$formIsInvalid`.
49
+ * @param resolvers.resolveFormPath - Resolves a path within the $form scope
50
+ * @param resolvers.resolveMetaPath - Resolves a path within the $meta scope
51
+ */
52
+ export declare const resolveScopedPath: (variable: string, resolvers: ScopedPathResolvers) => any;
2
53
  /**
3
54
  * Flattens the hierarchical form structure into a single-level array of form widgets.
4
55
  *
@@ -18,3 +69,11 @@ import * as Widget from '../form-widget';
18
69
  * ```
19
70
  */
20
71
  export declare function flattenForm(widgets: Widget.FormWidget[]): Widget.FormWidget[];
72
+ /**
73
+ * Calculates validation variables to be used in reactive expressions
74
+ * e.g. `{ invalidAge: '!!$errors.age' }` or { disabled { when: '$formIsInvalid' } }
75
+ */
76
+ export declare function calculateValidationVariables(state: State): {
77
+ $formIsInvalid: boolean;
78
+ $errors: $Errors;
79
+ };
@@ -0,0 +1,3 @@
1
+ import { $Errors, ReactiveExpression } from '../shared';
2
+ import { State } from '../store/model';
3
+ export declare function expressionIsTrue(expression: ReactiveExpression, $form: State['data'], $meta: State['meta'], $errors: $Errors, $formIsInvalid: boolean): boolean;
@@ -135,6 +135,8 @@ export declare const set: (object: Record<string, any>, path: DotPath, value: an
135
135
  */
136
136
  export declare const deleteKey: (object: Record<string, any>, key: string) => Record<string, any>;
137
137
  /**
138
- * Cheap JSON.stringify-based clone object utility
138
+ * Deep-clones plain objects and arrays while preserving function references
139
+ * (and other non-plain values) by reference. Functions are stateless widget
140
+ * resolvers and only need to survive the trip into repeater item configs.
139
141
  */
140
- export declare function cloneObject(obj: Record<string, any>): any;
142
+ export declare function cloneObject<T>(value: T): T;
@@ -1,2 +1,32 @@
1
1
  import { NonFunctionWidget } from '../form-widget';
2
- export declare function makeRepeaterItemConfig(widget: NonFunctionWidget<string>, repeaterIndex: number): NonFunctionWidget<string>;
2
+ import { Uid } from '../shared';
3
+ /**
4
+ * Derives a concrete widget config for a specific repeater item by stamping
5
+ * the provided indexes into the widget's `uid` (and `path` for input widgets).
6
+ *
7
+ * @param widget - The base widget config defined on the repeater template.
8
+ * @param repeaterIndexes - Ordered list of indexes for each nesting level,
9
+ * e.g. `[2, 0]` for the first item of a nested repeater inside the third
10
+ * item of an outer repeater.
11
+ * @returns A new widget config with the indexes baked in; the original is not mutated.
12
+ *
13
+ * @example
14
+ * makeRepeaterItemConfig(widget, [1]) // { uid: 'user-name[1]', path: 'users.1.name' }
15
+ */
16
+ export declare function makeRepeaterItemConfig(widget: NonFunctionWidget<string>, repeaterIndexes: number[]): NonFunctionWidget<string>;
17
+ export declare function toRepeaterItemUid(uid: Uid, repeaterIndexes: number[]): Uid;
18
+ /**
19
+ * Replaces `.items.` and `.items?.` tokens in a `when` expression with the
20
+ * concrete repeater indexes so the expression can be evaluated.
21
+ * Multiple `items` tokens are replaced in order, supporting nested repeaters.
22
+ *
23
+ * @example
24
+ * // repeaterIndexes = [2]
25
+ * // "$form.reptr.items.active" -> "$form.reptr.2.active"
26
+ * // "$form.reptr.items?.active" -> "$form.reptr.2?.active"
27
+ *
28
+ * @example
29
+ * // repeaterIndexes = [1, 0]
30
+ * // "$form.reptr.teams.items?.devs?.items?.firstName?.length > 0" -> "$form.reptr.teams.1?.devs?.0?.firstName?.length > 0"
31
+ */
32
+ export declare function transformRepeaterItemWhenExpression(expression: string, repeaterIndexes: number[]): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@golemui/core",
3
- "version": "0.0.2",
3
+ "version": "0.12.1",
4
4
  "type": "module",
5
5
  "main": "./index.umd.cjs",
6
6
  "module": "./index.js",
@@ -26,5 +26,10 @@
26
26
  "subscript": "^10.1.8",
27
27
  "rxjs": "^7.8.0",
28
28
  "@standard-schema/spec": "^1.0.0"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/golemui/golemui.git",
33
+ "directory": "libs/core"
29
34
  }
30
35
  }
@@ -1,67 +0,0 @@
1
- export type RefResolver = (ref: string) => JSONSchemaObject;
2
- export declare function isJsonSchema(json: Record<string, any>): json is JSONSchemaObject;
3
- /**
4
- * JSON Schema Draft 2020-12
5
- * @see
6
- * https://json-schema.org/draft/2020-12
7
- */
8
- export interface JSONSchemaObject {
9
- $schema?: string;
10
- $id?: string;
11
- $ref?: string;
12
- $defs?: Record<string, JSONSchemaObject>;
13
- $comment?: string;
14
- $vocabulary?: Record<string, boolean>;
15
- $dynamicRef?: string;
16
- $dynamicAnchor?: string;
17
- $anchor?: string;
18
- title?: string;
19
- description?: string;
20
- default?: unknown;
21
- deprecated?: boolean;
22
- readOnly?: boolean;
23
- writeOnly?: boolean;
24
- examples?: unknown[];
25
- type?: JSONSchemaType | JSONSchemaType[];
26
- enum?: unknown[];
27
- const?: unknown;
28
- multipleOf?: number;
29
- maximum?: number;
30
- exclusiveMaximum?: number;
31
- minimum?: number;
32
- exclusiveMinimum?: number;
33
- maxLength?: number;
34
- minLength?: number;
35
- pattern?: string;
36
- prefixItems?: JSONSchemaObject[];
37
- items?: JSONSchemaObject;
38
- contains?: JSONSchemaObject;
39
- maxContains?: number;
40
- minContains?: number;
41
- maxItems?: number;
42
- minItems?: number;
43
- uniqueItems?: boolean;
44
- properties?: Record<string, JSONSchemaObject>;
45
- patternProperties?: Record<string, JSONSchemaObject>;
46
- additionalProperties?: JSONSchemaObject;
47
- propertyNames?: JSONSchemaObject;
48
- maxProperties?: number;
49
- minProperties?: number;
50
- required?: string[];
51
- dependentRequired?: Record<string, string[]>;
52
- allOf?: JSONSchemaObject[];
53
- anyOf?: JSONSchemaObject[];
54
- oneOf?: JSONSchemaObject[];
55
- not?: JSONSchemaObject;
56
- if?: JSONSchemaObject;
57
- then?: JSONSchemaObject;
58
- else?: JSONSchemaObject;
59
- dependentSchemas?: Record<string, JSONSchemaObject>;
60
- unevaluatedItems?: JSONSchemaObject;
61
- unevaluatedProperties?: JSONSchemaObject;
62
- format?: string;
63
- contentEncoding?: string;
64
- contentMediaType?: string;
65
- contentSchema?: JSONSchemaObject;
66
- }
67
- export type JSONSchemaType = 'null' | 'boolean' | 'object' | 'array' | 'number' | 'integer' | 'string';
@@ -1,19 +0,0 @@
1
- import { FormWidget } from '../../form-widget';
2
- import { Action } from '../../store/actions';
3
- import { Middleware, State } from '../../store/model';
4
- import { JSONSchemaObject } from './json-schema';
5
- type JsonSchemaTypeMap = 'string' | 'enum' | 'boolean' | 'number' | 'integer' | 'object' | 'oneOf' | 'anyOf' | 'fallback';
6
- /**
7
- * Maps a Json Schema type to a widget name, so
8
- */
9
- export type SchemaToWidgetMap = Record<JsonSchemaTypeMap, (schema: JSONSchemaObject, ...rest: any[]) => FormWidget>;
10
- /**
11
- * Use this middleware to convert a JSON schema into a JSON form.
12
- *
13
- * @example
14
- * protected middlewares = jsonSchemaMiddleware(vanillaSchemaToWidgetMap);
15
- * @example
16
- * <gui-form [middlewares]="middlewares" />
17
- */
18
- export declare const jsonSchemaMiddleware: (schemaToWidgetMap: SchemaToWidgetMap) => Middleware<State, Action>;
19
- export {};
@@ -1,16 +0,0 @@
1
- import { DotPath } from '../shared';
2
- /**
3
- * Heuristically checks if a value looks like a dot notation path
4
- * rather than a standard string.
5
- * To be considered a "potential" dot path, the value must:
6
- * 1. Be a string.
7
- * 2. Start with one of the allowed prefixes ($form.*, $error.* or $meta.*).
8
- * 3. Not contain any spaces (distinguishing it from sentences).
9
- *
10
- * * @example
11
- * isPotentialDotPath('$form.user.id'); // true
12
- * isPotentialDotPath('name'); // false (No prefix)
13
- * isPotentialDotPath('my file'); // false (Contains space)
14
- * isPotentialDotPath(123); // false (Not a string)
15
- */
16
- export declare const isPotentialDotPath: (path: unknown) => path is DotPath;