@jfdevelops/react-layout 2.2.0 → 2.4.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.
Files changed (117) hide show
  1. package/dist/create-config/create-defined-resource-layout.cjs +2 -0
  2. package/dist/create-config/create-defined-resource-layout.cjs.map +1 -1
  3. package/dist/create-config/create-defined-resource-layout.d.cts +15 -12
  4. package/dist/create-config/create-defined-resource-layout.d.cts.map +1 -1
  5. package/dist/create-config/create-defined-resource-layout.d.mts +15 -12
  6. package/dist/create-config/create-defined-resource-layout.d.mts.map +1 -1
  7. package/dist/create-config/create-defined-resource-layout.mjs +2 -0
  8. package/dist/create-config/create-defined-resource-layout.mjs.map +1 -1
  9. package/dist/create-config/create-resource-links.cjs.map +1 -1
  10. package/dist/create-config/create-resource-links.d.cts +3 -1
  11. package/dist/create-config/create-resource-links.d.cts.map +1 -1
  12. package/dist/create-config/create-resource-links.d.mts +3 -1
  13. package/dist/create-config/create-resource-links.d.mts.map +1 -1
  14. package/dist/create-config/create-resource-links.mjs.map +1 -1
  15. package/dist/create-config/create-reusable.cjs +213 -0
  16. package/dist/create-config/create-reusable.cjs.map +1 -0
  17. package/dist/create-config/create-reusable.d.cts +1 -0
  18. package/dist/create-config/create-reusable.d.mts +1 -0
  19. package/dist/create-config/create-reusable.mjs +213 -0
  20. package/dist/create-config/create-reusable.mjs.map +1 -0
  21. package/dist/create-config/define-layout.cjs +11 -8
  22. package/dist/create-config/define-layout.cjs.map +1 -1
  23. package/dist/create-config/define-layout.d.cts +43 -42
  24. package/dist/create-config/define-layout.d.cts.map +1 -1
  25. package/dist/create-config/define-layout.d.mts +43 -42
  26. package/dist/create-config/define-layout.d.mts.map +1 -1
  27. package/dist/create-config/define-layout.mjs +11 -8
  28. package/dist/create-config/define-layout.mjs.map +1 -1
  29. package/dist/create-config/for-paths/builder.cjs +1 -0
  30. package/dist/create-config/for-paths/builder.cjs.map +1 -1
  31. package/dist/create-config/for-paths/builder.d.cts +5 -3
  32. package/dist/create-config/for-paths/builder.d.cts.map +1 -1
  33. package/dist/create-config/for-paths/builder.d.mts +5 -3
  34. package/dist/create-config/for-paths/builder.d.mts.map +1 -1
  35. package/dist/create-config/for-paths/builder.mjs +1 -0
  36. package/dist/create-config/for-paths/builder.mjs.map +1 -1
  37. package/dist/create-config/for-resource.cjs.map +1 -1
  38. package/dist/create-config/for-resource.d.cts +7 -6
  39. package/dist/create-config/for-resource.d.cts.map +1 -1
  40. package/dist/create-config/for-resource.d.mts +7 -6
  41. package/dist/create-config/for-resource.d.mts.map +1 -1
  42. package/dist/create-config/for-resource.mjs.map +1 -1
  43. package/dist/create-config/for-resources/create-component.d.cts +34 -33
  44. package/dist/create-config/for-resources/create-component.d.cts.map +1 -1
  45. package/dist/create-config/for-resources/create-component.d.mts +34 -33
  46. package/dist/create-config/for-resources/create-component.d.mts.map +1 -1
  47. package/dist/create-config/for-resources/create-for-resources.cjs +7 -6
  48. package/dist/create-config/for-resources/create-for-resources.cjs.map +1 -1
  49. package/dist/create-config/for-resources/create-for-resources.d.cts +2 -1
  50. package/dist/create-config/for-resources/create-for-resources.d.mts +2 -1
  51. package/dist/create-config/for-resources/create-for-resources.mjs +7 -6
  52. package/dist/create-config/for-resources/create-for-resources.mjs.map +1 -1
  53. package/dist/create-config/for-resources/scoped-layout.d.cts +5 -4
  54. package/dist/create-config/for-resources/scoped-layout.d.cts.map +1 -1
  55. package/dist/create-config/for-resources/scoped-layout.d.mts +5 -4
  56. package/dist/create-config/for-resources/scoped-layout.d.mts.map +1 -1
  57. package/dist/create-config/index.d.cts +1 -0
  58. package/dist/create-config/index.d.mts +1 -0
  59. package/dist/create-config/layout-name.cjs +1 -1
  60. package/dist/create-config/layout-name.mjs +1 -1
  61. package/dist/create-config/lazy-resource-layout.cjs +1 -1
  62. package/dist/create-config/lazy-resource-layout.d.cts +1 -1
  63. package/dist/create-config/lazy-resource-layout.d.mts +1 -1
  64. package/dist/create-config/lazy-resource-layout.mjs +1 -1
  65. package/dist/create-config/merge-layout-props.cjs.map +1 -1
  66. package/dist/create-config/merge-layout-props.mjs.map +1 -1
  67. package/dist/create-config/render-state.cjs +3 -2
  68. package/dist/create-config/render-state.cjs.map +1 -1
  69. package/dist/create-config/render-state.d.cts +27 -25
  70. package/dist/create-config/render-state.d.cts.map +1 -1
  71. package/dist/create-config/render-state.d.mts +27 -25
  72. package/dist/create-config/render-state.d.mts.map +1 -1
  73. package/dist/create-config/render-state.mjs +3 -2
  74. package/dist/create-config/render-state.mjs.map +1 -1
  75. package/dist/create-config/reusable-types.d.cts +131 -0
  76. package/dist/create-config/reusable-types.d.cts.map +1 -0
  77. package/dist/create-config/reusable-types.d.mts +131 -0
  78. package/dist/create-config/reusable-types.d.mts.map +1 -0
  79. package/dist/create-config/state-composable.cjs +1 -1
  80. package/dist/create-config/state-composable.mjs +1 -1
  81. package/dist/custom-props.cjs +15 -0
  82. package/dist/custom-props.cjs.map +1 -0
  83. package/dist/custom-props.d.cts +17 -0
  84. package/dist/custom-props.d.cts.map +1 -0
  85. package/dist/custom-props.d.mts +17 -0
  86. package/dist/custom-props.d.mts.map +1 -0
  87. package/dist/custom-props.mjs +15 -0
  88. package/dist/custom-props.mjs.map +1 -0
  89. package/dist/errors/react-layout-error.cjs +1 -1
  90. package/dist/errors/react-layout-error.mjs +1 -1
  91. package/dist/index.cjs +3 -3
  92. package/dist/index.d.cts +4 -2
  93. package/dist/index.d.mts +4 -2
  94. package/dist/index.mjs +3 -3
  95. package/dist/lazy/create-render-state.cjs.map +1 -1
  96. package/dist/lazy/create-render-state.d.cts +5 -5
  97. package/dist/lazy/create-render-state.d.cts.map +1 -1
  98. package/dist/lazy/create-render-state.d.mts +5 -5
  99. package/dist/lazy/create-render-state.d.mts.map +1 -1
  100. package/dist/lazy/create-render-state.mjs.map +1 -1
  101. package/dist/lazy/lazy-boundary.cjs +1 -1
  102. package/dist/lazy/lazy-boundary.mjs +1 -1
  103. package/dist/lazy/types.cjs.map +1 -1
  104. package/dist/lazy/types.d.cts +5 -4
  105. package/dist/lazy/types.d.cts.map +1 -1
  106. package/dist/lazy/types.d.mts +5 -4
  107. package/dist/lazy/types.d.mts.map +1 -1
  108. package/dist/lazy/types.mjs.map +1 -1
  109. package/dist/props.cjs.map +1 -1
  110. package/dist/props.d.cts +10 -4
  111. package/dist/props.d.cts.map +1 -1
  112. package/dist/props.d.mts +10 -4
  113. package/dist/props.d.mts.map +1 -1
  114. package/dist/props.mjs.map +1 -1
  115. package/dist/resource.d.cts +1 -1
  116. package/dist/resource.d.mts +1 -1
  117. package/package.json +4 -4
@@ -0,0 +1,213 @@
1
+ const require_layout_configuration_error = require('../errors/layout-configuration-error.cjs');
2
+ const require_define_layout = require('./define-layout.cjs');
3
+ let _jfdevelops_react_layout_validator = require("@jfdevelops/react-layout-validator");
4
+
5
+ //#region src/create-config/create-reusable.ts
6
+ function objectPlan(children, optional = false, guards = [[]]) {
7
+ return {
8
+ kind: "object",
9
+ children,
10
+ optional,
11
+ guards
12
+ };
13
+ }
14
+ function optionPlan(definitions, selection, from, path = [], optionalPaths = []) {
15
+ const entries = selection === true ? Object.fromEntries(Object.keys(definitions).map((key) => [key, true])) : selection;
16
+ const children = {};
17
+ for (const [key, value] of Object.entries(entries ?? {})) {
18
+ if (!Object.hasOwn(definitions, key)) throw new require_layout_configuration_error.LayoutConfigurationError(`Unknown reusable option "${key}".`);
19
+ const definition = definitions[key];
20
+ const location = {
21
+ from,
22
+ path: [...path, key]
23
+ };
24
+ if (typeof value === "function") children[key] = {
25
+ ...location,
26
+ from: "options",
27
+ guards: optionalPaths.map((path) => ({
28
+ from: "options",
29
+ path
30
+ })),
31
+ kind: "value",
32
+ source: "option",
33
+ selector: value,
34
+ definition
35
+ };
36
+ else if ("properties" in definition && "type" in definition && definition.type === "object" && (value === true || value && typeof value === "object")) children[key] = {
37
+ ...optionPlan(definition.properties, value, from, location.path, definition.visibility === "optional" ? [...optionalPaths, location.path] : optionalPaths),
38
+ optional: definition.visibility === "optional"
39
+ };
40
+ else if (value === true) children[key] = {
41
+ ...location,
42
+ guards: optionalPaths.map((path) => ({
43
+ from,
44
+ path
45
+ })),
46
+ kind: "value",
47
+ source: "option",
48
+ definition
49
+ };
50
+ else throw new require_layout_configuration_error.LayoutConfigurationError(`Invalid reusable selection for "${key}".`);
51
+ }
52
+ const origins = /* @__PURE__ */ new Set();
53
+ function collectOrigins(node) {
54
+ if (node.kind === "value") origins.add(node.from);
55
+ else Object.values(node.children).forEach(collectOrigins);
56
+ }
57
+ Object.values(children).forEach(collectOrigins);
58
+ if (!origins.size) origins.add(from);
59
+ return objectPlan(children, false, [...origins].map((origin) => optionalPaths.map((path) => ({
60
+ from: origin,
61
+ path
62
+ }))));
63
+ }
64
+ function sameSelection(left, right) {
65
+ return left.source === right.source && left.selector === right.selector && left.path.join(".") === right.path.join(".") && (left.source === "option" || left.from === right.from);
66
+ }
67
+ function mergePlans(left, right, overlap, path = []) {
68
+ const children = { ...left.children };
69
+ for (const [key, other] of Object.entries(right.children)) {
70
+ const current = children[key];
71
+ if (!current) {
72
+ children[key] = other;
73
+ continue;
74
+ }
75
+ if (current.kind === "object" && other.kind === "object") children[key] = mergePlans(current, other, overlap, [...path, key]);
76
+ else if (current.kind === "value" && other.kind === "value" && sameSelection(current, other)) children[key] = other.from === "options" ? other : current;
77
+ else if (overlap) children[key] = overlap === "preferProps" ? current : other;
78
+ else throw new require_layout_configuration_error.LayoutConfigurationError(`Ambiguous reusable property "${[...path, key].join(".")}". Rename one result or set overlap to "preferProps" or "preferSelect".`);
79
+ }
80
+ return {
81
+ kind: "object",
82
+ children,
83
+ optional: left.optional && right.optional,
84
+ guards: [...left.guards, ...right.guards]
85
+ };
86
+ }
87
+ function withoutSharedCallerValues(left, right) {
88
+ const children = { ...left.children };
89
+ for (const [key, other] of Object.entries(right.children)) {
90
+ const current = children[key];
91
+ if (current?.kind === "object" && other.kind === "object") children[key] = withoutSharedCallerValues(current, other);
92
+ else if (current?.kind === "value" && other.kind === "value" && sameSelection(current, other) && other.from === "options") delete children[key];
93
+ }
94
+ return {
95
+ ...left,
96
+ children
97
+ };
98
+ }
99
+ function planDefinitions(plan, from) {
100
+ const definitions = {};
101
+ for (const [key, value] of Object.entries(plan.children)) if (value.kind === "value") {
102
+ if (value.from === from && value.definition) definitions[key] = value.definition;
103
+ } else {
104
+ const nested = planDefinitions(value, from);
105
+ if (Object.keys(nested).length) {
106
+ const definition = _jfdevelops_react_layout_validator.createProp.object(nested);
107
+ definitions[key] = value.optional ? definition.optional() : definition;
108
+ }
109
+ }
110
+ return definitions;
111
+ }
112
+ function sourceSelection(selection, callbacksOnly) {
113
+ if (typeof selection === "function") return true;
114
+ if (selection === true) return callbacksOnly ? {} : true;
115
+ const source = {};
116
+ for (const [key, value] of Object.entries(selection ?? {})) {
117
+ const nested = sourceSelection(value, callbacksOnly);
118
+ if (nested === true || Object.keys(nested).length) source[key] = nested;
119
+ }
120
+ return source;
121
+ }
122
+ function mergeSelections(left, right) {
123
+ if (left === true || right === true) return true;
124
+ const merged = { ...left };
125
+ for (const [key, value] of Object.entries(right)) merged[key] = Object.hasOwn(left, key) ? mergeSelections(left[key], value) : value;
126
+ return merged;
127
+ }
128
+ function readLocation(location, props, options, resources) {
129
+ let value = location.from === "props" ? props : location.from === "options" ? options : resources;
130
+ for (const key of location.path) value = value?.[key];
131
+ return value;
132
+ }
133
+ function resolvePlan(plan, props, options, resources) {
134
+ const result = {};
135
+ for (const [key, node] of Object.entries(plan.children)) if (node.kind === "object") {
136
+ if (node.guards.some((group) => group.every((location) => readLocation(location, props, options, resources) !== void 0))) result[key] = resolvePlan(node, props, options, resources);
137
+ } else {
138
+ if (node.guards?.some((location) => readLocation(location, props, options, resources) === void 0)) continue;
139
+ const value = readLocation(node, props, options, resources);
140
+ if (node.selector) result[key] = node.selector(value);
141
+ else if (value !== void 0 || node.definition?.visibility !== "optional") result[key] = value;
142
+ }
143
+ return result;
144
+ }
145
+ function createReusableBuilder(resources, options) {
146
+ const keys = resources.map((entry) => typeof entry === "string" ? entry : entry.value);
147
+ const resource = _jfdevelops_react_layout_validator.createProp.string.enum(keys);
148
+ const resourcesAccessor = require_define_layout.createLayoutResourcesAccessor(resources);
149
+ function createReusable(definition) {
150
+ const include = definition.props?.include ?? {};
151
+ const select = definition.select ?? {};
152
+ if (definition.overlap !== void 0 && definition.overlap !== "preferProps" && definition.overlap !== "preferSelect") throw new require_layout_configuration_error.LayoutConfigurationError("Unknown reusable overlap policy.");
153
+ const optionDefinitions = typeof options === "function" ? options({
154
+ name: _jfdevelops_react_layout_validator.createProp.string.literal("Reusable"),
155
+ resource
156
+ }) : options;
157
+ function compile(selection, from) {
158
+ let plan = objectPlan({});
159
+ for (const [key, value] of Object.entries(selection)) {
160
+ let next;
161
+ if (key === "options") {
162
+ if (value !== true && typeof value !== "function" && (!value || typeof value !== "object" || Array.isArray(value))) throw new require_layout_configuration_error.LayoutConfigurationError("Invalid reusable options selection.");
163
+ next = typeof value === "function" ? objectPlan({ options: {
164
+ kind: "value",
165
+ source: "option",
166
+ from: "options",
167
+ path: [],
168
+ selector: value
169
+ } }) : optionPlan(optionDefinitions, value, from);
170
+ } else if (key === "resources" && (value === true || typeof value === "function")) next = objectPlan({ resources: {
171
+ kind: "value",
172
+ source: "resource",
173
+ from: value === true && from === "props" ? "props" : "resources",
174
+ path: value === true && from === "props" ? ["resources"] : [],
175
+ selector: typeof value === "function" ? value : void 0,
176
+ definition: value === true && from === "props" ? _jfdevelops_react_layout_validator.createProp.array(resource) : void 0
177
+ } });
178
+ else throw new require_layout_configuration_error.LayoutConfigurationError(`Invalid reusable source "${key}".`);
179
+ plan = mergePlans(plan, next);
180
+ }
181
+ return plan;
182
+ }
183
+ let included = compile(include, "props");
184
+ const custom = objectPlan(Object.fromEntries(Object.entries(definition.props?.custom ?? {}).map(([key, value]) => [key, {
185
+ kind: "value",
186
+ source: "custom",
187
+ from: "props",
188
+ path: [key],
189
+ definition: value
190
+ }])));
191
+ included = mergePlans(included, custom);
192
+ const selected = compile(select, "options");
193
+ const plan = mergePlans(included, selected, definition.overlap);
194
+ const callerDefinitions = planDefinitions(withoutSharedCallerValues(included, selected), "props");
195
+ const effectiveCallerDefinitions = planDefinitions(plan, "props");
196
+ const sources = mergeSelections(sourceSelection(include.options, true), sourceSelection(select.options, false));
197
+ const sourceDefinitions = sources === true ? optionDefinitions : planDefinitions(optionPlan(optionDefinitions, sources, "options"), "options");
198
+ const needsOptions = Object.keys(sourceDefinitions).length > 0;
199
+ if (needsOptions && Object.hasOwn(callerDefinitions, "options")) throw new require_layout_configuration_error.LayoutConfigurationError("Reusable prop \"options\" is reserved for source values.");
200
+ return function reusable(props = {}) {
201
+ (0, _jfdevelops_react_layout_validator.validateProps)(definition.overlap ? callerDefinitions : effectiveCallerDefinitions, props);
202
+ if (needsOptions && props.options !== void 0 && (props.options === null || typeof props.options !== "object" || Array.isArray(props.options))) throw new require_layout_configuration_error.LayoutConfigurationError("Reusable source options must be an object.");
203
+ const values = props.options ?? {};
204
+ (0, _jfdevelops_react_layout_validator.validateProps)(sourceDefinitions, values);
205
+ return definition.fn(resolvePlan(plan, props, values, resourcesAccessor));
206
+ };
207
+ }
208
+ return createReusable;
209
+ }
210
+
211
+ //#endregion
212
+ exports.createReusableBuilder = createReusableBuilder;
213
+ //# sourceMappingURL=create-reusable.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-reusable.cjs","names":["LayoutConfigurationError","createProp","createLayoutResourcesAccessor"],"sources":["../../src/create-config/create-reusable.ts"],"sourcesContent":["import {\n createProp,\n validateProps,\n type AnyBuiltPropDefinition,\n} from '@jfdevelops/react-layout-validator';\nimport type { InPropsDefinition, InPropsObject, PropsContract } from '../props';\nimport type { ResourceDefinition } from '../resource';\nimport { LayoutConfigurationError } from '../errors';\nimport { createLayoutResourcesAccessor } from './define-layout';\nimport type { CreateReusable, ReusableOverlap } from './reusable-types';\nexport type * from './reusable-types';\n\ntype RuntimeSelection = Record<string, unknown>;\ntype PlanLocation = { from: 'props' | 'options' | 'resources'; path: string[] };\ntype ValuePlan = PlanLocation & {\n kind: 'value';\n // Optional ancestors remain tied to the value's original source after merging.\n guards?: PlanLocation[];\n source: 'option' | 'resource' | 'custom';\n selector?: (value: any) => unknown;\n definition?: AnyBuiltPropDefinition;\n};\ntype ObjectPlan = {\n kind: 'object';\n children: Record<string, Plan>;\n optional: boolean;\n guards: PlanLocation[][];\n};\ntype Plan = ValuePlan | ObjectPlan;\n\nfunction objectPlan(\n children: Record<string, Plan>,\n optional = false,\n guards: PlanLocation[][] = [[]],\n): ObjectPlan {\n return { kind: 'object', children, optional, guards };\n}\n\nfunction optionPlan(\n definitions: InPropsObject,\n selection: unknown,\n from: 'props' | 'options',\n path: string[] = [],\n optionalPaths: string[][] = [],\n): ObjectPlan {\n const entries =\n selection === true\n ? Object.fromEntries(Object.keys(definitions).map((key) => [key, true]))\n : (selection as RuntimeSelection);\n const children: Record<string, Plan> = {};\n for (const [key, value] of Object.entries(entries ?? {})) {\n if (!Object.hasOwn(definitions, key))\n throw new LayoutConfigurationError(`Unknown reusable option \"${key}\".`);\n const definition = definitions[key];\n const location: PlanLocation = { from, path: [...path, key] };\n if (typeof value === 'function') {\n children[key] = {\n ...location,\n from: 'options',\n guards: optionalPaths.map((path) => ({ from: 'options', path })),\n kind: 'value',\n source: 'option',\n selector: value as ValuePlan['selector'],\n definition,\n };\n } else if (\n 'properties' in definition &&\n 'type' in definition &&\n definition.type === 'object' &&\n (value === true || (value && typeof value === 'object'))\n ) {\n const nested = optionPlan(\n definition.properties as InPropsObject,\n value,\n from,\n location.path,\n definition.visibility === 'optional'\n ? [...optionalPaths, location.path]\n : optionalPaths,\n );\n children[key] = {\n ...nested,\n optional: definition.visibility === 'optional',\n };\n } else if (value === true) {\n children[key] = {\n ...location,\n guards: optionalPaths.map((path) => ({ from, path })),\n kind: 'value',\n source: 'option',\n definition,\n };\n } else\n throw new LayoutConfigurationError(\n `Invalid reusable selection for \"${key}\".`,\n );\n }\n const origins = new Set<PlanLocation['from']>();\n function collectOrigins(node: Plan) {\n if (node.kind === 'value') origins.add(node.from);\n else Object.values(node.children).forEach(collectOrigins);\n }\n Object.values(children).forEach(collectOrigins);\n if (!origins.size) origins.add(from);\n return objectPlan(\n children,\n false,\n [...origins].map((origin) =>\n optionalPaths.map((path) => ({ from: origin, path })),\n ),\n );\n}\n\nfunction sameSelection(left: ValuePlan, right: ValuePlan) {\n return (\n left.source === right.source &&\n left.selector === right.selector &&\n left.path.join('.') === right.path.join('.') &&\n (left.source === 'option' || left.from === right.from)\n );\n}\n\nfunction mergePlans(\n left: ObjectPlan,\n right: ObjectPlan,\n overlap?: ReusableOverlap,\n path: string[] = [],\n): ObjectPlan {\n const children = { ...left.children };\n for (const [key, other] of Object.entries(right.children)) {\n const current = children[key];\n if (!current) {\n children[key] = other;\n continue;\n }\n if (current.kind === 'object' && other.kind === 'object') {\n children[key] = mergePlans(current, other, overlap, [...path, key]);\n } else if (\n current.kind === 'value' &&\n other.kind === 'value' &&\n sameSelection(current, other)\n ) {\n // A shared option selection uses one source value and executes only once.\n children[key] = other.from === 'options' ? other : current;\n } else if (overlap)\n children[key] = overlap === 'preferProps' ? current : other;\n else\n throw new LayoutConfigurationError(\n `Ambiguous reusable property \"${[...path, key].join(\n '.',\n )}\". Rename one result or set overlap to \"preferProps\" or \"preferSelect\".`,\n );\n }\n return {\n kind: 'object',\n children,\n optional: left.optional && right.optional,\n guards: [...left.guards, ...right.guards],\n };\n}\n\nfunction withoutSharedCallerValues(\n left: ObjectPlan,\n right: ObjectPlan,\n): ObjectPlan {\n const children = { ...left.children };\n for (const [key, other] of Object.entries(right.children)) {\n const current = children[key];\n if (current?.kind === 'object' && other.kind === 'object')\n children[key] = withoutSharedCallerValues(current, other);\n else if (\n current?.kind === 'value' &&\n other.kind === 'value' &&\n sameSelection(current, other) &&\n other.from === 'options'\n )\n delete children[key];\n }\n return { ...left, children };\n}\n\nfunction planDefinitions(\n plan: ObjectPlan,\n from: 'props' | 'options',\n): InPropsObject {\n const definitions: InPropsObject = {};\n for (const [key, value] of Object.entries(plan.children)) {\n if (value.kind === 'value') {\n if (value.from === from && value.definition)\n definitions[key] = value.definition;\n } else {\n const nested = planDefinitions(value, from);\n if (Object.keys(nested).length) {\n const definition = createProp.object(nested);\n definitions[key] = value.optional ? definition.optional() : definition;\n }\n }\n }\n return definitions;\n}\n\nfunction sourceSelection(\n selection: unknown,\n callbacksOnly: boolean,\n): true | RuntimeSelection {\n if (typeof selection === 'function') return true;\n if (selection === true) return callbacksOnly ? {} : true;\n const source: RuntimeSelection = {};\n for (const [key, value] of Object.entries(\n (selection ?? {}) as RuntimeSelection,\n )) {\n const nested = sourceSelection(value, callbacksOnly);\n if (nested === true || Object.keys(nested).length) source[key] = nested;\n }\n return source;\n}\n\nfunction mergeSelections(\n left: true | RuntimeSelection,\n right: true | RuntimeSelection,\n): true | RuntimeSelection {\n if (left === true || right === true) return true;\n const merged = { ...left };\n for (const [key, value] of Object.entries(right))\n merged[key] = Object.hasOwn(left, key)\n ? mergeSelections(\n left[key] as true | RuntimeSelection,\n value as true | RuntimeSelection,\n )\n : value;\n return merged;\n}\n\nfunction readLocation(\n location: PlanLocation,\n props: Record<string, unknown>,\n options: Record<string, unknown>,\n resources: unknown,\n) {\n let value: any =\n location.from === 'props'\n ? props\n : location.from === 'options'\n ? options\n : resources;\n for (const key of location.path) value = value?.[key];\n return value;\n}\n\nfunction resolvePlan(\n plan: ObjectPlan,\n props: Record<string, unknown>,\n options: Record<string, unknown>,\n resources: unknown,\n) {\n const result: Record<string, unknown> = {};\n for (const [key, node] of Object.entries(plan.children)) {\n if (node.kind === 'object') {\n if (\n node.guards.some((group) =>\n group.every(\n (location) =>\n readLocation(location, props, options, resources) !== undefined,\n ),\n )\n ) {\n result[key] = resolvePlan(node, props, options, resources);\n }\n } else {\n if (\n node.guards?.some(\n (location) =>\n readLocation(location, props, options, resources) === undefined,\n )\n )\n continue;\n const value = readLocation(node, props, options, resources);\n if (node.selector) result[key] = node.selector(value);\n else if (\n value !== undefined ||\n node.definition?.visibility !== 'optional'\n )\n result[key] = value;\n }\n }\n return result;\n}\n\nexport function createReusableBuilder<\n const Resources extends readonly ResourceDefinition[],\n Options extends InPropsDefinition<Resources>,\n>(resources: Resources, options: Options): CreateReusable<Resources, Options>;\nexport function createReusableBuilder(\n resources: readonly ResourceDefinition[],\n options: InPropsObject | ((...args: any[]) => InPropsObject),\n) {\n const keys = resources.map((entry) =>\n typeof entry === 'string' ? entry : entry.value,\n );\n const resource = createProp.string.enum(keys as [string, ...string[]]);\n const resourcesAccessor = createLayoutResourcesAccessor(resources);\n\n function createReusable(definition: {\n props?: PropsContract<RuntimeSelection, InPropsObject>;\n select?: RuntimeSelection;\n overlap?: ReusableOverlap;\n fn: (props: Record<string, unknown>) => unknown;\n }) {\n const include = definition.props?.include ?? {};\n const select = definition.select ?? {};\n if (\n definition.overlap !== undefined &&\n definition.overlap !== 'preferProps' &&\n definition.overlap !== 'preferSelect'\n ) {\n throw new LayoutConfigurationError('Unknown reusable overlap policy.');\n }\n const optionDefinitions =\n typeof options === 'function'\n ? options({ name: createProp.string.literal('Reusable'), resource })\n : options;\n\n function compile(selection: RuntimeSelection, from: 'props' | 'options') {\n let plan = objectPlan({});\n for (const [key, value] of Object.entries(selection)) {\n let next: ObjectPlan;\n if (key === 'options') {\n if (\n value !== true &&\n typeof value !== 'function' &&\n (!value || typeof value !== 'object' || Array.isArray(value))\n ) {\n throw new LayoutConfigurationError(\n 'Invalid reusable options selection.',\n );\n }\n next =\n typeof value === 'function'\n ? objectPlan({\n options: {\n kind: 'value',\n source: 'option',\n from: 'options',\n path: [],\n selector: value as ValuePlan['selector'],\n },\n })\n : optionPlan(optionDefinitions, value, from);\n } else if (\n key === 'resources' &&\n (value === true || typeof value === 'function')\n ) {\n next = objectPlan({\n resources: {\n kind: 'value',\n source: 'resource',\n from: value === true && from === 'props' ? 'props' : 'resources',\n path: value === true && from === 'props' ? ['resources'] : [],\n selector:\n typeof value === 'function'\n ? (value as ValuePlan['selector'])\n : undefined,\n definition:\n value === true && from === 'props'\n ? createProp.array(resource)\n : undefined,\n },\n });\n } else\n throw new LayoutConfigurationError(\n `Invalid reusable source \"${key}\".`,\n );\n plan = mergePlans(plan, next);\n }\n return plan;\n }\n\n let included = compile(include, 'props');\n const custom = objectPlan(\n Object.fromEntries(\n Object.entries(definition.props?.custom ?? {}).map(([key, value]) => [\n key,\n {\n kind: 'value',\n source: 'custom',\n from: 'props',\n path: [key],\n definition: value,\n } as ValuePlan,\n ]),\n ),\n );\n included = mergePlans(included, custom);\n const selected = compile(select, 'options');\n const plan = mergePlans(included, selected, definition.overlap);\n const callerDefinitions = planDefinitions(\n withoutSharedCallerValues(included, selected),\n 'props',\n );\n // Identical true selections supplied by select are removed from the caller props contract.\n const effectiveCallerDefinitions = planDefinitions(plan, 'props');\n const sources = mergeSelections(\n sourceSelection(include.options, true),\n sourceSelection(select.options, false),\n );\n const sourceDefinitions =\n sources === true\n ? optionDefinitions\n : planDefinitions(\n optionPlan(optionDefinitions, sources, 'options'),\n 'options',\n );\n const needsOptions = Object.keys(sourceDefinitions).length > 0;\n if (needsOptions && Object.hasOwn(callerDefinitions, 'options')) {\n throw new LayoutConfigurationError(\n 'Reusable prop \"options\" is reserved for source values.',\n );\n }\n\n return function reusable(props: Record<string, unknown> = {}) {\n // Validate configured caller props too when an explicit overlap policy discards their output.\n const definitions = definition.overlap\n ? callerDefinitions\n : effectiveCallerDefinitions;\n validateProps(definitions, props);\n if (\n needsOptions &&\n props.options !== undefined &&\n (props.options === null ||\n typeof props.options !== 'object' ||\n Array.isArray(props.options))\n ) {\n throw new LayoutConfigurationError(\n 'Reusable source options must be an object.',\n );\n }\n const values = (props.options ?? {}) as Record<string, unknown>;\n validateProps(sourceDefinitions, values);\n return definition.fn(resolvePlan(plan, props, values, resourcesAccessor));\n };\n }\n return createReusable as unknown;\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import { CreateReusable, ReusableArguments, ReusableDefinition, ReusableFunction, ReusableInclude, ReusableInput, ReusableOptionSelection, ReusableOverlap, ReusableProps, ReusableResolved, ReusableSelected } from "./reusable-types.cjs";
@@ -0,0 +1 @@
1
+ import { CreateReusable, ReusableArguments, ReusableDefinition, ReusableFunction, ReusableInclude, ReusableInput, ReusableOptionSelection, ReusableOverlap, ReusableProps, ReusableResolved, ReusableSelected } from "./reusable-types.mjs";
@@ -0,0 +1,213 @@
1
+ import { LayoutConfigurationError } from "../errors/layout-configuration-error.mjs";
2
+ import { createLayoutResourcesAccessor } from "./define-layout.mjs";
3
+ import { createProp, validateProps } from "@jfdevelops/react-layout-validator";
4
+
5
+ //#region src/create-config/create-reusable.ts
6
+ function objectPlan(children, optional = false, guards = [[]]) {
7
+ return {
8
+ kind: "object",
9
+ children,
10
+ optional,
11
+ guards
12
+ };
13
+ }
14
+ function optionPlan(definitions, selection, from, path = [], optionalPaths = []) {
15
+ const entries = selection === true ? Object.fromEntries(Object.keys(definitions).map((key) => [key, true])) : selection;
16
+ const children = {};
17
+ for (const [key, value] of Object.entries(entries ?? {})) {
18
+ if (!Object.hasOwn(definitions, key)) throw new LayoutConfigurationError(`Unknown reusable option "${key}".`);
19
+ const definition = definitions[key];
20
+ const location = {
21
+ from,
22
+ path: [...path, key]
23
+ };
24
+ if (typeof value === "function") children[key] = {
25
+ ...location,
26
+ from: "options",
27
+ guards: optionalPaths.map((path) => ({
28
+ from: "options",
29
+ path
30
+ })),
31
+ kind: "value",
32
+ source: "option",
33
+ selector: value,
34
+ definition
35
+ };
36
+ else if ("properties" in definition && "type" in definition && definition.type === "object" && (value === true || value && typeof value === "object")) children[key] = {
37
+ ...optionPlan(definition.properties, value, from, location.path, definition.visibility === "optional" ? [...optionalPaths, location.path] : optionalPaths),
38
+ optional: definition.visibility === "optional"
39
+ };
40
+ else if (value === true) children[key] = {
41
+ ...location,
42
+ guards: optionalPaths.map((path) => ({
43
+ from,
44
+ path
45
+ })),
46
+ kind: "value",
47
+ source: "option",
48
+ definition
49
+ };
50
+ else throw new LayoutConfigurationError(`Invalid reusable selection for "${key}".`);
51
+ }
52
+ const origins = /* @__PURE__ */ new Set();
53
+ function collectOrigins(node) {
54
+ if (node.kind === "value") origins.add(node.from);
55
+ else Object.values(node.children).forEach(collectOrigins);
56
+ }
57
+ Object.values(children).forEach(collectOrigins);
58
+ if (!origins.size) origins.add(from);
59
+ return objectPlan(children, false, [...origins].map((origin) => optionalPaths.map((path) => ({
60
+ from: origin,
61
+ path
62
+ }))));
63
+ }
64
+ function sameSelection(left, right) {
65
+ return left.source === right.source && left.selector === right.selector && left.path.join(".") === right.path.join(".") && (left.source === "option" || left.from === right.from);
66
+ }
67
+ function mergePlans(left, right, overlap, path = []) {
68
+ const children = { ...left.children };
69
+ for (const [key, other] of Object.entries(right.children)) {
70
+ const current = children[key];
71
+ if (!current) {
72
+ children[key] = other;
73
+ continue;
74
+ }
75
+ if (current.kind === "object" && other.kind === "object") children[key] = mergePlans(current, other, overlap, [...path, key]);
76
+ else if (current.kind === "value" && other.kind === "value" && sameSelection(current, other)) children[key] = other.from === "options" ? other : current;
77
+ else if (overlap) children[key] = overlap === "preferProps" ? current : other;
78
+ else throw new LayoutConfigurationError(`Ambiguous reusable property "${[...path, key].join(".")}". Rename one result or set overlap to "preferProps" or "preferSelect".`);
79
+ }
80
+ return {
81
+ kind: "object",
82
+ children,
83
+ optional: left.optional && right.optional,
84
+ guards: [...left.guards, ...right.guards]
85
+ };
86
+ }
87
+ function withoutSharedCallerValues(left, right) {
88
+ const children = { ...left.children };
89
+ for (const [key, other] of Object.entries(right.children)) {
90
+ const current = children[key];
91
+ if (current?.kind === "object" && other.kind === "object") children[key] = withoutSharedCallerValues(current, other);
92
+ else if (current?.kind === "value" && other.kind === "value" && sameSelection(current, other) && other.from === "options") delete children[key];
93
+ }
94
+ return {
95
+ ...left,
96
+ children
97
+ };
98
+ }
99
+ function planDefinitions(plan, from) {
100
+ const definitions = {};
101
+ for (const [key, value] of Object.entries(plan.children)) if (value.kind === "value") {
102
+ if (value.from === from && value.definition) definitions[key] = value.definition;
103
+ } else {
104
+ const nested = planDefinitions(value, from);
105
+ if (Object.keys(nested).length) {
106
+ const definition = createProp.object(nested);
107
+ definitions[key] = value.optional ? definition.optional() : definition;
108
+ }
109
+ }
110
+ return definitions;
111
+ }
112
+ function sourceSelection(selection, callbacksOnly) {
113
+ if (typeof selection === "function") return true;
114
+ if (selection === true) return callbacksOnly ? {} : true;
115
+ const source = {};
116
+ for (const [key, value] of Object.entries(selection ?? {})) {
117
+ const nested = sourceSelection(value, callbacksOnly);
118
+ if (nested === true || Object.keys(nested).length) source[key] = nested;
119
+ }
120
+ return source;
121
+ }
122
+ function mergeSelections(left, right) {
123
+ if (left === true || right === true) return true;
124
+ const merged = { ...left };
125
+ for (const [key, value] of Object.entries(right)) merged[key] = Object.hasOwn(left, key) ? mergeSelections(left[key], value) : value;
126
+ return merged;
127
+ }
128
+ function readLocation(location, props, options, resources) {
129
+ let value = location.from === "props" ? props : location.from === "options" ? options : resources;
130
+ for (const key of location.path) value = value?.[key];
131
+ return value;
132
+ }
133
+ function resolvePlan(plan, props, options, resources) {
134
+ const result = {};
135
+ for (const [key, node] of Object.entries(plan.children)) if (node.kind === "object") {
136
+ if (node.guards.some((group) => group.every((location) => readLocation(location, props, options, resources) !== void 0))) result[key] = resolvePlan(node, props, options, resources);
137
+ } else {
138
+ if (node.guards?.some((location) => readLocation(location, props, options, resources) === void 0)) continue;
139
+ const value = readLocation(node, props, options, resources);
140
+ if (node.selector) result[key] = node.selector(value);
141
+ else if (value !== void 0 || node.definition?.visibility !== "optional") result[key] = value;
142
+ }
143
+ return result;
144
+ }
145
+ function createReusableBuilder(resources, options) {
146
+ const keys = resources.map((entry) => typeof entry === "string" ? entry : entry.value);
147
+ const resource = createProp.string.enum(keys);
148
+ const resourcesAccessor = createLayoutResourcesAccessor(resources);
149
+ function createReusable(definition) {
150
+ const include = definition.props?.include ?? {};
151
+ const select = definition.select ?? {};
152
+ if (definition.overlap !== void 0 && definition.overlap !== "preferProps" && definition.overlap !== "preferSelect") throw new LayoutConfigurationError("Unknown reusable overlap policy.");
153
+ const optionDefinitions = typeof options === "function" ? options({
154
+ name: createProp.string.literal("Reusable"),
155
+ resource
156
+ }) : options;
157
+ function compile(selection, from) {
158
+ let plan = objectPlan({});
159
+ for (const [key, value] of Object.entries(selection)) {
160
+ let next;
161
+ if (key === "options") {
162
+ if (value !== true && typeof value !== "function" && (!value || typeof value !== "object" || Array.isArray(value))) throw new LayoutConfigurationError("Invalid reusable options selection.");
163
+ next = typeof value === "function" ? objectPlan({ options: {
164
+ kind: "value",
165
+ source: "option",
166
+ from: "options",
167
+ path: [],
168
+ selector: value
169
+ } }) : optionPlan(optionDefinitions, value, from);
170
+ } else if (key === "resources" && (value === true || typeof value === "function")) next = objectPlan({ resources: {
171
+ kind: "value",
172
+ source: "resource",
173
+ from: value === true && from === "props" ? "props" : "resources",
174
+ path: value === true && from === "props" ? ["resources"] : [],
175
+ selector: typeof value === "function" ? value : void 0,
176
+ definition: value === true && from === "props" ? createProp.array(resource) : void 0
177
+ } });
178
+ else throw new LayoutConfigurationError(`Invalid reusable source "${key}".`);
179
+ plan = mergePlans(plan, next);
180
+ }
181
+ return plan;
182
+ }
183
+ let included = compile(include, "props");
184
+ const custom = objectPlan(Object.fromEntries(Object.entries(definition.props?.custom ?? {}).map(([key, value]) => [key, {
185
+ kind: "value",
186
+ source: "custom",
187
+ from: "props",
188
+ path: [key],
189
+ definition: value
190
+ }])));
191
+ included = mergePlans(included, custom);
192
+ const selected = compile(select, "options");
193
+ const plan = mergePlans(included, selected, definition.overlap);
194
+ const callerDefinitions = planDefinitions(withoutSharedCallerValues(included, selected), "props");
195
+ const effectiveCallerDefinitions = planDefinitions(plan, "props");
196
+ const sources = mergeSelections(sourceSelection(include.options, true), sourceSelection(select.options, false));
197
+ const sourceDefinitions = sources === true ? optionDefinitions : planDefinitions(optionPlan(optionDefinitions, sources, "options"), "options");
198
+ const needsOptions = Object.keys(sourceDefinitions).length > 0;
199
+ if (needsOptions && Object.hasOwn(callerDefinitions, "options")) throw new LayoutConfigurationError("Reusable prop \"options\" is reserved for source values.");
200
+ return function reusable(props = {}) {
201
+ validateProps(definition.overlap ? callerDefinitions : effectiveCallerDefinitions, props);
202
+ if (needsOptions && props.options !== void 0 && (props.options === null || typeof props.options !== "object" || Array.isArray(props.options))) throw new LayoutConfigurationError("Reusable source options must be an object.");
203
+ const values = props.options ?? {};
204
+ validateProps(sourceDefinitions, values);
205
+ return definition.fn(resolvePlan(plan, props, values, resourcesAccessor));
206
+ };
207
+ }
208
+ return createReusable;
209
+ }
210
+
211
+ //#endregion
212
+ export { createReusableBuilder };
213
+ //# sourceMappingURL=create-reusable.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-reusable.mjs","names":[],"sources":["../../src/create-config/create-reusable.ts"],"sourcesContent":["import {\n createProp,\n validateProps,\n type AnyBuiltPropDefinition,\n} from '@jfdevelops/react-layout-validator';\nimport type { InPropsDefinition, InPropsObject, PropsContract } from '../props';\nimport type { ResourceDefinition } from '../resource';\nimport { LayoutConfigurationError } from '../errors';\nimport { createLayoutResourcesAccessor } from './define-layout';\nimport type { CreateReusable, ReusableOverlap } from './reusable-types';\nexport type * from './reusable-types';\n\ntype RuntimeSelection = Record<string, unknown>;\ntype PlanLocation = { from: 'props' | 'options' | 'resources'; path: string[] };\ntype ValuePlan = PlanLocation & {\n kind: 'value';\n // Optional ancestors remain tied to the value's original source after merging.\n guards?: PlanLocation[];\n source: 'option' | 'resource' | 'custom';\n selector?: (value: any) => unknown;\n definition?: AnyBuiltPropDefinition;\n};\ntype ObjectPlan = {\n kind: 'object';\n children: Record<string, Plan>;\n optional: boolean;\n guards: PlanLocation[][];\n};\ntype Plan = ValuePlan | ObjectPlan;\n\nfunction objectPlan(\n children: Record<string, Plan>,\n optional = false,\n guards: PlanLocation[][] = [[]],\n): ObjectPlan {\n return { kind: 'object', children, optional, guards };\n}\n\nfunction optionPlan(\n definitions: InPropsObject,\n selection: unknown,\n from: 'props' | 'options',\n path: string[] = [],\n optionalPaths: string[][] = [],\n): ObjectPlan {\n const entries =\n selection === true\n ? Object.fromEntries(Object.keys(definitions).map((key) => [key, true]))\n : (selection as RuntimeSelection);\n const children: Record<string, Plan> = {};\n for (const [key, value] of Object.entries(entries ?? {})) {\n if (!Object.hasOwn(definitions, key))\n throw new LayoutConfigurationError(`Unknown reusable option \"${key}\".`);\n const definition = definitions[key];\n const location: PlanLocation = { from, path: [...path, key] };\n if (typeof value === 'function') {\n children[key] = {\n ...location,\n from: 'options',\n guards: optionalPaths.map((path) => ({ from: 'options', path })),\n kind: 'value',\n source: 'option',\n selector: value as ValuePlan['selector'],\n definition,\n };\n } else if (\n 'properties' in definition &&\n 'type' in definition &&\n definition.type === 'object' &&\n (value === true || (value && typeof value === 'object'))\n ) {\n const nested = optionPlan(\n definition.properties as InPropsObject,\n value,\n from,\n location.path,\n definition.visibility === 'optional'\n ? [...optionalPaths, location.path]\n : optionalPaths,\n );\n children[key] = {\n ...nested,\n optional: definition.visibility === 'optional',\n };\n } else if (value === true) {\n children[key] = {\n ...location,\n guards: optionalPaths.map((path) => ({ from, path })),\n kind: 'value',\n source: 'option',\n definition,\n };\n } else\n throw new LayoutConfigurationError(\n `Invalid reusable selection for \"${key}\".`,\n );\n }\n const origins = new Set<PlanLocation['from']>();\n function collectOrigins(node: Plan) {\n if (node.kind === 'value') origins.add(node.from);\n else Object.values(node.children).forEach(collectOrigins);\n }\n Object.values(children).forEach(collectOrigins);\n if (!origins.size) origins.add(from);\n return objectPlan(\n children,\n false,\n [...origins].map((origin) =>\n optionalPaths.map((path) => ({ from: origin, path })),\n ),\n );\n}\n\nfunction sameSelection(left: ValuePlan, right: ValuePlan) {\n return (\n left.source === right.source &&\n left.selector === right.selector &&\n left.path.join('.') === right.path.join('.') &&\n (left.source === 'option' || left.from === right.from)\n );\n}\n\nfunction mergePlans(\n left: ObjectPlan,\n right: ObjectPlan,\n overlap?: ReusableOverlap,\n path: string[] = [],\n): ObjectPlan {\n const children = { ...left.children };\n for (const [key, other] of Object.entries(right.children)) {\n const current = children[key];\n if (!current) {\n children[key] = other;\n continue;\n }\n if (current.kind === 'object' && other.kind === 'object') {\n children[key] = mergePlans(current, other, overlap, [...path, key]);\n } else if (\n current.kind === 'value' &&\n other.kind === 'value' &&\n sameSelection(current, other)\n ) {\n // A shared option selection uses one source value and executes only once.\n children[key] = other.from === 'options' ? other : current;\n } else if (overlap)\n children[key] = overlap === 'preferProps' ? current : other;\n else\n throw new LayoutConfigurationError(\n `Ambiguous reusable property \"${[...path, key].join(\n '.',\n )}\". Rename one result or set overlap to \"preferProps\" or \"preferSelect\".`,\n );\n }\n return {\n kind: 'object',\n children,\n optional: left.optional && right.optional,\n guards: [...left.guards, ...right.guards],\n };\n}\n\nfunction withoutSharedCallerValues(\n left: ObjectPlan,\n right: ObjectPlan,\n): ObjectPlan {\n const children = { ...left.children };\n for (const [key, other] of Object.entries(right.children)) {\n const current = children[key];\n if (current?.kind === 'object' && other.kind === 'object')\n children[key] = withoutSharedCallerValues(current, other);\n else if (\n current?.kind === 'value' &&\n other.kind === 'value' &&\n sameSelection(current, other) &&\n other.from === 'options'\n )\n delete children[key];\n }\n return { ...left, children };\n}\n\nfunction planDefinitions(\n plan: ObjectPlan,\n from: 'props' | 'options',\n): InPropsObject {\n const definitions: InPropsObject = {};\n for (const [key, value] of Object.entries(plan.children)) {\n if (value.kind === 'value') {\n if (value.from === from && value.definition)\n definitions[key] = value.definition;\n } else {\n const nested = planDefinitions(value, from);\n if (Object.keys(nested).length) {\n const definition = createProp.object(nested);\n definitions[key] = value.optional ? definition.optional() : definition;\n }\n }\n }\n return definitions;\n}\n\nfunction sourceSelection(\n selection: unknown,\n callbacksOnly: boolean,\n): true | RuntimeSelection {\n if (typeof selection === 'function') return true;\n if (selection === true) return callbacksOnly ? {} : true;\n const source: RuntimeSelection = {};\n for (const [key, value] of Object.entries(\n (selection ?? {}) as RuntimeSelection,\n )) {\n const nested = sourceSelection(value, callbacksOnly);\n if (nested === true || Object.keys(nested).length) source[key] = nested;\n }\n return source;\n}\n\nfunction mergeSelections(\n left: true | RuntimeSelection,\n right: true | RuntimeSelection,\n): true | RuntimeSelection {\n if (left === true || right === true) return true;\n const merged = { ...left };\n for (const [key, value] of Object.entries(right))\n merged[key] = Object.hasOwn(left, key)\n ? mergeSelections(\n left[key] as true | RuntimeSelection,\n value as true | RuntimeSelection,\n )\n : value;\n return merged;\n}\n\nfunction readLocation(\n location: PlanLocation,\n props: Record<string, unknown>,\n options: Record<string, unknown>,\n resources: unknown,\n) {\n let value: any =\n location.from === 'props'\n ? props\n : location.from === 'options'\n ? options\n : resources;\n for (const key of location.path) value = value?.[key];\n return value;\n}\n\nfunction resolvePlan(\n plan: ObjectPlan,\n props: Record<string, unknown>,\n options: Record<string, unknown>,\n resources: unknown,\n) {\n const result: Record<string, unknown> = {};\n for (const [key, node] of Object.entries(plan.children)) {\n if (node.kind === 'object') {\n if (\n node.guards.some((group) =>\n group.every(\n (location) =>\n readLocation(location, props, options, resources) !== undefined,\n ),\n )\n ) {\n result[key] = resolvePlan(node, props, options, resources);\n }\n } else {\n if (\n node.guards?.some(\n (location) =>\n readLocation(location, props, options, resources) === undefined,\n )\n )\n continue;\n const value = readLocation(node, props, options, resources);\n if (node.selector) result[key] = node.selector(value);\n else if (\n value !== undefined ||\n node.definition?.visibility !== 'optional'\n )\n result[key] = value;\n }\n }\n return result;\n}\n\nexport function createReusableBuilder<\n const Resources extends readonly ResourceDefinition[],\n Options extends InPropsDefinition<Resources>,\n>(resources: Resources, options: Options): CreateReusable<Resources, Options>;\nexport function createReusableBuilder(\n resources: readonly ResourceDefinition[],\n options: InPropsObject | ((...args: any[]) => InPropsObject),\n) {\n const keys = resources.map((entry) =>\n typeof entry === 'string' ? entry : entry.value,\n );\n const resource = createProp.string.enum(keys as [string, ...string[]]);\n const resourcesAccessor = createLayoutResourcesAccessor(resources);\n\n function createReusable(definition: {\n props?: PropsContract<RuntimeSelection, InPropsObject>;\n select?: RuntimeSelection;\n overlap?: ReusableOverlap;\n fn: (props: Record<string, unknown>) => unknown;\n }) {\n const include = definition.props?.include ?? {};\n const select = definition.select ?? {};\n if (\n definition.overlap !== undefined &&\n definition.overlap !== 'preferProps' &&\n definition.overlap !== 'preferSelect'\n ) {\n throw new LayoutConfigurationError('Unknown reusable overlap policy.');\n }\n const optionDefinitions =\n typeof options === 'function'\n ? options({ name: createProp.string.literal('Reusable'), resource })\n : options;\n\n function compile(selection: RuntimeSelection, from: 'props' | 'options') {\n let plan = objectPlan({});\n for (const [key, value] of Object.entries(selection)) {\n let next: ObjectPlan;\n if (key === 'options') {\n if (\n value !== true &&\n typeof value !== 'function' &&\n (!value || typeof value !== 'object' || Array.isArray(value))\n ) {\n throw new LayoutConfigurationError(\n 'Invalid reusable options selection.',\n );\n }\n next =\n typeof value === 'function'\n ? objectPlan({\n options: {\n kind: 'value',\n source: 'option',\n from: 'options',\n path: [],\n selector: value as ValuePlan['selector'],\n },\n })\n : optionPlan(optionDefinitions, value, from);\n } else if (\n key === 'resources' &&\n (value === true || typeof value === 'function')\n ) {\n next = objectPlan({\n resources: {\n kind: 'value',\n source: 'resource',\n from: value === true && from === 'props' ? 'props' : 'resources',\n path: value === true && from === 'props' ? ['resources'] : [],\n selector:\n typeof value === 'function'\n ? (value as ValuePlan['selector'])\n : undefined,\n definition:\n value === true && from === 'props'\n ? createProp.array(resource)\n : undefined,\n },\n });\n } else\n throw new LayoutConfigurationError(\n `Invalid reusable source \"${key}\".`,\n );\n plan = mergePlans(plan, next);\n }\n return plan;\n }\n\n let included = compile(include, 'props');\n const custom = objectPlan(\n Object.fromEntries(\n Object.entries(definition.props?.custom ?? {}).map(([key, value]) => [\n key,\n {\n kind: 'value',\n source: 'custom',\n from: 'props',\n path: [key],\n definition: value,\n } as ValuePlan,\n ]),\n ),\n );\n included = mergePlans(included, custom);\n const selected = compile(select, 'options');\n const plan = mergePlans(included, selected, definition.overlap);\n const callerDefinitions = planDefinitions(\n withoutSharedCallerValues(included, selected),\n 'props',\n );\n // Identical true selections supplied by select are removed from the caller props contract.\n const effectiveCallerDefinitions = planDefinitions(plan, 'props');\n const sources = mergeSelections(\n sourceSelection(include.options, true),\n sourceSelection(select.options, false),\n );\n const sourceDefinitions =\n sources === true\n ? optionDefinitions\n : planDefinitions(\n optionPlan(optionDefinitions, sources, 'options'),\n 'options',\n );\n const needsOptions = Object.keys(sourceDefinitions).length > 0;\n if (needsOptions && Object.hasOwn(callerDefinitions, 'options')) {\n throw new LayoutConfigurationError(\n 'Reusable prop \"options\" is reserved for source values.',\n );\n }\n\n return function reusable(props: Record<string, unknown> = {}) {\n // Validate configured caller props too when an explicit overlap policy discards their output.\n const definitions = definition.overlap\n ? callerDefinitions\n : effectiveCallerDefinitions;\n validateProps(definitions, props);\n if (\n needsOptions &&\n props.options !== undefined &&\n (props.options === null ||\n typeof props.options !== 'object' ||\n Array.isArray(props.options))\n ) {\n throw new LayoutConfigurationError(\n 'Reusable source options must be an object.',\n );\n }\n const values = (props.options ?? {}) as Record<string, unknown>;\n validateProps(sourceDefinitions, values);\n return definition.fn(resolvePlan(plan, props, values, resourcesAccessor));\n };\n }\n return createReusable as unknown;\n}\n"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
- const require_render_state_context = require('./render-state-context.cjs');
1
+ const require_invalid_config = require('../errors/invalid-config.cjs');
2
+ const require_missing_resource_provider = require('../errors/missing-resource-provider.cjs');
2
3
  const require_layout_configuration_error = require('../errors/layout-configuration-error.cjs');
3
4
  const require_resource_state_error = require('../errors/resource-state-error.cjs');
4
5
  const require_lazy_resource_error = require('../errors/lazy-resource-error.cjs');
6
+ const require_custom_props = require('../custom-props.cjs');
7
+ const require_render_state_context = require('./render-state-context.cjs');
5
8
  const require_lazy_boundary = require('../lazy/lazy-boundary.cjs');
6
9
  const require_fallback_props = require('../lazy/fallback-props.cjs');
7
10
  const require_types = require('../lazy/types.cjs');
8
- const require_invalid_config = require('../errors/invalid-config.cjs');
9
- const require_missing_resource_provider = require('../errors/missing-resource-provider.cjs');
10
11
  const require_capitalize = require('../utils/capitalize.cjs');
11
12
  const require_state_composable = require('./state-composable.cjs');
12
13
  const require_merge_layout_props = require('./merge-layout-props.cjs');
@@ -23,10 +24,10 @@ const require_render_state = require('./render-state.cjs');
23
24
  const require_create_for_resources = require('./for-resources/create-for-resources.cjs');
24
25
  const require_shell_context = require('./shell-context.cjs');
25
26
  let _jfdevelops_react_layout_composables = require("@jfdevelops/react-layout-composables");
27
+ let _jfdevelops_react_layout_validator = require("@jfdevelops/react-layout-validator");
26
28
  let react = require("react");
27
29
  let react_jsx_runtime = require("react/jsx-runtime");
28
30
  let _jfdevelops_react_layout_devtools_core = require("@jfdevelops/react-layout-devtools-core");
29
- let _jfdevelops_react_layout_validator = require("@jfdevelops/react-layout-validator");
30
31
 
31
32
  //#region src/create-config/define-layout.tsx
32
33
  const RenderStateRetryContext = (0, react.createContext)(void 0);
@@ -131,6 +132,7 @@ function resolveLayoutOptionDefaults(defaults, options) {
131
132
  function optionalStateChildren(props) {
132
133
  if (!props) return props;
133
134
  const children = props.custom?.children;
135
+ const stateChildren = children && typeof children !== "string" && children.visibility === "required" && "optional" in children && typeof children.optional === "function" ? children.optional() : children;
134
136
  const childrenInclude = props.include?.children;
135
137
  return {
136
138
  ...props,
@@ -146,7 +148,7 @@ function optionalStateChildren(props) {
146
148
  },
147
149
  custom: props.custom && {
148
150
  ...props.custom,
149
- ...children ? { children: children.visibility === "required" ? children.optional?.() ?? children : children } : {}
151
+ ...children ? { children: stateChildren } : {}
150
152
  }
151
153
  };
152
154
  }
@@ -301,7 +303,7 @@ function defineResourceLayoutImpl(options, inheritedStateScope, inheritedInspect
301
303
  });
302
304
  const render = defaultState.render;
303
305
  const layoutProps = require_merge_layout_props.mergeLayoutProps(legacyLayoutProps, defaultState.props);
304
- const customLayoutProps = layoutProps?.custom;
306
+ const customLayoutProps = require_custom_props.normalizeCustomProps(layoutProps?.custom ?? {});
305
307
  const includeLayoutProps = layoutProps?.include;
306
308
  const layoutOptionValues = layoutOptionProps;
307
309
  const resolvedLayoutProps = { ...customLayoutProps };
@@ -666,7 +668,7 @@ function defineResourceLayoutImpl(options, inheritedStateScope, inheritedInspect
666
668
  for (const { props: presetPropDefinitions } of (0, _jfdevelops_react_layout_composables.collectComposablePresetEntries)(resolvedComposables)) Object.assign(resolvedInProps, presetPropDefinitions);
667
669
  return {
668
670
  ...resolvedInProps,
669
- ...require_merge_layout_props.mergeLayoutProps(layout.props, defaultState?.props)?.custom
671
+ ...require_custom_props.normalizeCustomProps(require_merge_layout_props.mergeLayoutProps(layout.props, defaultState?.props)?.custom ?? {})
670
672
  };
671
673
  }
672
674
  const { createLayoutForResourceBuilder, forResource } = require_for_resource.createForResource({
@@ -747,7 +749,7 @@ function createResourceLayoutShellComponent(resources, inProps, shell, shellId)
747
749
  }) : inProps);
748
750
  const includeShellProps = shell.props?.include;
749
751
  const includeShellPropKeys = Object.keys(includeShellProps ?? {});
750
- const shellCustomDefinitions = { ...shell.props?.custom ?? {} };
752
+ const shellCustomDefinitions = require_custom_props.normalizeCustomProps(shell.props?.custom ?? {});
751
753
  function syncShellComposableDisplayNames(stable, resource) {
752
754
  if (!shell.composables) return;
753
755
  const named = (0, _jfdevelops_react_layout_composables.resolveLayoutComposables)(shell.composables, {
@@ -834,6 +836,7 @@ function createResourceLayoutShellComponent(resources, inProps, shell, shellId)
834
836
  ...validatedCustomProps,
835
837
  ...renderIncludedProps
836
838
  };
839
+ if (typeof shell.props?.custom?.children !== "function") renderProps.children = outlet == null ? outlet : shellChildren;
837
840
  const renderContext = {
838
841
  composables: resolvedComposables,
839
842
  resource,