@jfdevelops/react-layout 0.17.5 → 0.18.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.
Files changed (153) hide show
  1. package/dist/create-config/component-keys.cjs +44 -0
  2. package/dist/create-config/component-keys.cjs.map +1 -0
  3. package/dist/create-config/component-keys.mjs +39 -0
  4. package/dist/create-config/component-keys.mjs.map +1 -0
  5. package/dist/create-config/define-layout.cjs +16 -1
  6. package/dist/create-config/define-layout.cjs.map +1 -1
  7. package/dist/create-config/define-layout.d.cts +5 -3
  8. package/dist/create-config/define-layout.d.cts.map +1 -1
  9. package/dist/create-config/define-layout.d.mts +5 -3
  10. package/dist/create-config/define-layout.d.mts.map +1 -1
  11. package/dist/create-config/define-layout.mjs +16 -1
  12. package/dist/create-config/define-layout.mjs.map +1 -1
  13. package/dist/create-config/for-paths/builder.cjs +192 -0
  14. package/dist/create-config/for-paths/builder.cjs.map +1 -0
  15. package/dist/create-config/for-paths/builder.d.cts +77 -0
  16. package/dist/create-config/for-paths/builder.d.cts.map +1 -0
  17. package/dist/create-config/for-paths/builder.d.mts +77 -0
  18. package/dist/create-config/for-paths/builder.d.mts.map +1 -0
  19. package/dist/create-config/for-paths/builder.mjs +192 -0
  20. package/dist/create-config/for-paths/builder.mjs.map +1 -0
  21. package/dist/create-config/for-paths/get-component-for-path.cjs +55 -0
  22. package/dist/create-config/for-paths/get-component-for-path.cjs.map +1 -0
  23. package/dist/create-config/for-paths/get-component-for-path.d.cts +55 -0
  24. package/dist/create-config/for-paths/get-component-for-path.d.cts.map +1 -0
  25. package/dist/create-config/for-paths/get-component-for-path.d.mts +55 -0
  26. package/dist/create-config/for-paths/get-component-for-path.d.mts.map +1 -0
  27. package/dist/create-config/for-paths/get-component-for-path.mjs +55 -0
  28. package/dist/create-config/for-paths/get-component-for-path.mjs.map +1 -0
  29. package/dist/create-config/for-paths/index.d.cts +2 -0
  30. package/dist/create-config/for-paths/index.d.mts +2 -0
  31. package/dist/create-config/get-component.cjs +60 -11
  32. package/dist/create-config/get-component.cjs.map +1 -1
  33. package/dist/create-config/get-component.d.cts +75 -6
  34. package/dist/create-config/get-component.d.cts.map +1 -1
  35. package/dist/create-config/get-component.d.mts +75 -6
  36. package/dist/create-config/get-component.d.mts.map +1 -1
  37. package/dist/create-config/get-component.mjs +61 -11
  38. package/dist/create-config/get-component.mjs.map +1 -1
  39. package/dist/create-config/index.d.cts +6 -1
  40. package/dist/create-config/index.d.mts +6 -1
  41. package/dist/create-config/is-sub-resource-key.cjs +15 -0
  42. package/dist/create-config/is-sub-resource-key.cjs.map +1 -0
  43. package/dist/create-config/is-sub-resource-key.d.cts +30 -0
  44. package/dist/create-config/is-sub-resource-key.d.cts.map +1 -0
  45. package/dist/create-config/is-sub-resource-key.d.mts +30 -0
  46. package/dist/create-config/is-sub-resource-key.d.mts.map +1 -0
  47. package/dist/create-config/is-sub-resource-key.mjs +15 -0
  48. package/dist/create-config/is-sub-resource-key.mjs.map +1 -0
  49. package/dist/create-config/paths/generate.cjs +77 -0
  50. package/dist/create-config/paths/generate.cjs.map +1 -0
  51. package/dist/create-config/paths/generate.mjs +77 -0
  52. package/dist/create-config/paths/generate.mjs.map +1 -0
  53. package/dist/create-config/paths/index.d.cts +2 -0
  54. package/dist/create-config/paths/index.d.mts +2 -0
  55. package/dist/create-config/paths/introspect.cjs +123 -0
  56. package/dist/create-config/paths/introspect.cjs.map +1 -0
  57. package/dist/create-config/paths/introspect.mjs +118 -0
  58. package/dist/create-config/paths/introspect.mjs.map +1 -0
  59. package/dist/create-config/paths/resolve.cjs +130 -0
  60. package/dist/create-config/paths/resolve.cjs.map +1 -0
  61. package/dist/create-config/paths/resolve.mjs +129 -0
  62. package/dist/create-config/paths/resolve.mjs.map +1 -0
  63. package/dist/create-config/paths/types.d.cts +104 -0
  64. package/dist/create-config/paths/types.d.cts.map +1 -0
  65. package/dist/create-config/paths/types.d.mts +104 -0
  66. package/dist/create-config/paths/types.d.mts.map +1 -0
  67. package/dist/create-config/paths/variables.cjs +32 -0
  68. package/dist/create-config/paths/variables.cjs.map +1 -0
  69. package/dist/create-config/paths/variables.d.cts +32 -0
  70. package/dist/create-config/paths/variables.d.cts.map +1 -0
  71. package/dist/create-config/paths/variables.d.mts +32 -0
  72. package/dist/create-config/paths/variables.d.mts.map +1 -0
  73. package/dist/create-config/paths/variables.mjs +29 -0
  74. package/dist/create-config/paths/variables.mjs.map +1 -0
  75. package/dist/create-config/types.d.cts +28 -8
  76. package/dist/create-config/types.d.cts.map +1 -1
  77. package/dist/create-config/types.d.mts +28 -8
  78. package/dist/create-config/types.d.mts.map +1 -1
  79. package/dist/errors/invalid-component.cjs +21 -0
  80. package/dist/errors/invalid-component.cjs.map +1 -0
  81. package/dist/errors/invalid-component.d.cts +18 -0
  82. package/dist/errors/invalid-component.d.cts.map +1 -0
  83. package/dist/errors/invalid-component.d.mts +18 -0
  84. package/dist/errors/invalid-component.d.mts.map +1 -0
  85. package/dist/errors/invalid-component.mjs +21 -0
  86. package/dist/errors/invalid-component.mjs.map +1 -0
  87. package/dist/errors/invalid-config.cjs +13 -0
  88. package/dist/errors/invalid-config.cjs.map +1 -0
  89. package/dist/errors/invalid-config.d.cts +15 -0
  90. package/dist/errors/invalid-config.d.cts.map +1 -0
  91. package/dist/errors/invalid-config.d.mts +15 -0
  92. package/dist/errors/invalid-config.d.mts.map +1 -0
  93. package/dist/errors/invalid-config.mjs +13 -0
  94. package/dist/errors/invalid-config.mjs.map +1 -0
  95. package/dist/errors/invalid-path.cjs +18 -0
  96. package/dist/errors/invalid-path.cjs.map +1 -0
  97. package/dist/errors/invalid-path.d.cts +16 -0
  98. package/dist/errors/invalid-path.d.cts.map +1 -0
  99. package/dist/errors/invalid-path.d.mts +16 -0
  100. package/dist/errors/invalid-path.d.mts.map +1 -0
  101. package/dist/errors/invalid-path.mjs +18 -0
  102. package/dist/errors/invalid-path.mjs.map +1 -0
  103. package/dist/errors/invalid-resource.cjs +18 -0
  104. package/dist/errors/invalid-resource.cjs.map +1 -0
  105. package/dist/errors/invalid-resource.d.cts +16 -0
  106. package/dist/errors/invalid-resource.d.cts.map +1 -0
  107. package/dist/errors/invalid-resource.d.mts +16 -0
  108. package/dist/errors/invalid-resource.d.mts.map +1 -0
  109. package/dist/errors/invalid-resource.mjs +18 -0
  110. package/dist/errors/invalid-resource.mjs.map +1 -0
  111. package/dist/errors/invalid-sub-resource.cjs +18 -0
  112. package/dist/errors/invalid-sub-resource.cjs.map +1 -0
  113. package/dist/errors/invalid-sub-resource.d.cts +17 -0
  114. package/dist/errors/invalid-sub-resource.d.cts.map +1 -0
  115. package/dist/errors/invalid-sub-resource.d.mts +17 -0
  116. package/dist/errors/invalid-sub-resource.d.mts.map +1 -0
  117. package/dist/errors/invalid-sub-resource.mjs +18 -0
  118. package/dist/errors/invalid-sub-resource.mjs.map +1 -0
  119. package/dist/errors/missing-path-variable.cjs +18 -0
  120. package/dist/errors/missing-path-variable.cjs.map +1 -0
  121. package/dist/errors/missing-path-variable.d.cts +16 -0
  122. package/dist/errors/missing-path-variable.d.cts.map +1 -0
  123. package/dist/errors/missing-path-variable.d.mts +16 -0
  124. package/dist/errors/missing-path-variable.d.mts.map +1 -0
  125. package/dist/errors/missing-path-variable.mjs +18 -0
  126. package/dist/errors/missing-path-variable.mjs.map +1 -0
  127. package/dist/errors/react-layout-error.cjs +56 -0
  128. package/dist/errors/react-layout-error.cjs.map +1 -0
  129. package/dist/errors/react-layout-error.d.cts +46 -0
  130. package/dist/errors/react-layout-error.d.cts.map +1 -0
  131. package/dist/errors/react-layout-error.d.mts +46 -0
  132. package/dist/errors/react-layout-error.d.mts.map +1 -0
  133. package/dist/errors/react-layout-error.mjs +54 -0
  134. package/dist/errors/react-layout-error.mjs.map +1 -0
  135. package/dist/index.cjs +15 -0
  136. package/dist/index.d.cts +13 -1
  137. package/dist/index.d.mts +13 -1
  138. package/dist/index.mjs +8 -1
  139. package/dist/props.d.cts +1 -1
  140. package/dist/props.d.cts.map +1 -1
  141. package/dist/props.d.mts +1 -1
  142. package/dist/props.d.mts.map +1 -1
  143. package/dist/resource.cjs.map +1 -1
  144. package/dist/resource.d.cts +2 -2
  145. package/dist/resource.d.cts.map +1 -1
  146. package/dist/resource.d.mts +2 -2
  147. package/dist/resource.d.mts.map +1 -1
  148. package/dist/resource.mjs.map +1 -1
  149. package/dist/utils.d.cts +2 -1
  150. package/dist/utils.d.cts.map +1 -1
  151. package/dist/utils.d.mts +2 -1
  152. package/dist/utils.d.mts.map +1 -1
  153. package/package.json +1 -1
@@ -1,35 +1,75 @@
1
+ const require_invalid_config = require('../errors/invalid-config.cjs');
2
+ const require_invalid_path = require('../errors/invalid-path.cjs');
3
+ const require_invalid_resource = require('../errors/invalid-resource.cjs');
4
+ const require_invalid_sub_resource = require('../errors/invalid-sub-resource.cjs');
5
+ const require_invalid_component = require('../errors/invalid-component.cjs');
6
+ const require_component_keys = require('./component-keys.cjs');
7
+ const require_introspect = require('./paths/introspect.cjs');
8
+ const require_get_component_for_path = require('./for-paths/get-component-for-path.cjs');
9
+ const require_builder = require('./for-paths/builder.cjs');
10
+ const require_is_sub_resource_key = require('./is-sub-resource-key.cjs');
1
11
 
2
12
  //#region src/create-config/get-component.ts
13
+ function isResourceConfigEntry(value) {
14
+ return typeof value === "object" && value !== null;
15
+ }
3
16
  function resolveResourceConfigEntry(entry, subResource) {
4
- if (typeof subResource === "string") {
5
- const next = entry.subResources?.[subResource];
6
- if (!next) throw new Error(`Sub-resource "${subResource}" is not configured`);
7
- return next;
8
- }
9
- const next = entry.subResources?.[subResource.resource];
10
- if (!next) throw new Error(`Sub-resource "${subResource.resource}" is not configured`);
17
+ const key = typeof subResource === "string" ? subResource : subResource.value;
18
+ const next = entry[key];
19
+ if (!isResourceConfigEntry(next)) throw new require_invalid_sub_resource.InvalidSubResourceError({
20
+ subResource: key,
21
+ validSubResources: require_component_keys.readSubResourceKeys(entry)
22
+ });
23
+ if (typeof subResource === "string") return next;
11
24
  return resolveResourceConfigEntry(next, subResource.subResource);
12
25
  }
13
26
  function readResourceConfigComponent(entry, componentKey) {
14
27
  if (componentKey === "new" || componentKey === "detail") {
15
28
  const branch = entry[componentKey];
16
- if (!branch?.component) throw new Error(`Missing "${componentKey}.component" configuration`);
29
+ if (!branch?.component) throw new require_invalid_component.InvalidComponentError({
30
+ component: `${componentKey}.component`,
31
+ validComponents: require_component_keys.readComponentKeys(entry)
32
+ });
17
33
  return branch.component;
18
34
  }
19
35
  const value = entry[componentKey];
20
- if (!value) throw new Error(`Missing "${componentKey}" configuration`);
36
+ if (!value) throw new require_invalid_component.InvalidComponentError({
37
+ component: componentKey,
38
+ validComponents: require_component_keys.readComponentKeys(entry)
39
+ });
21
40
  return value;
22
41
  }
23
42
  function getComponentFromOptions(config, options) {
24
43
  const { resource, component: componentKey = "component" } = options;
25
44
  const resourceEntry = config[resource];
26
- if (!resourceEntry) throw new Error(`Resource "${resource}" is not configured`);
45
+ if (!resourceEntry) throw new require_invalid_resource.InvalidResourceError({
46
+ resource,
47
+ validResources: require_introspect.collectConfigResources(config)
48
+ });
27
49
  let entry = resourceEntry;
28
50
  if ("subResource" in options && options.subResource !== void 0) entry = resolveResourceConfigEntry(entry, options.subResource);
29
51
  return readResourceConfigComponent(entry, componentKey);
30
52
  }
53
+ function getComponentFromPath(config, path) {
54
+ let cursor = config;
55
+ for (const segment of path.split(".")) {
56
+ if (!isResourceConfigEntry(cursor)) throw new require_invalid_path.InvalidPathError({
57
+ path,
58
+ reason: `"${segment}" cannot be read because the value before it is not a config branch`
59
+ });
60
+ const next = cursor[segment];
61
+ if (next === void 0 || next === null) throw new require_invalid_path.InvalidPathError({
62
+ path,
63
+ reason: `"${segment}" is not configured`
64
+ });
65
+ cursor = next;
66
+ }
67
+ if (isResourceConfigEntry(cursor) && "component" in cursor) return readResourceConfigComponent(cursor, "component");
68
+ return cursor;
69
+ }
31
70
  function createGetComponent(config) {
32
71
  function getComponent(options) {
72
+ if (typeof options === "string") return getComponentFromPath(config, options);
33
73
  return getComponentFromOptions(config, options);
34
74
  }
35
75
  const forResource = (bound) => {
@@ -41,9 +81,18 @@ function createGetComponent(config) {
41
81
  return Object.assign(getComponent, { forResource });
42
82
  }
43
83
  function createResourceConfig(config) {
84
+ const configRecord = config;
85
+ if (require_introspect.collectConfigResources(configRecord).length === 0) throw new require_invalid_config.InvalidConfigError({
86
+ reason: "A resource config must configure at least one resource",
87
+ config
88
+ });
44
89
  return {
45
90
  config,
46
- getComponent: createGetComponent(config)
91
+ getComponent: createGetComponent(config),
92
+ createGetComponent: ((path) => require_get_component_for_path.createGetComponentForPath(configRecord, path)),
93
+ forPaths: require_builder.createForPaths(configRecord),
94
+ isSubResourceKey: require_is_sub_resource_key.createIsSubResourceKey(configRecord),
95
+ subResources: require_introspect.collectAllSubResourceKeys(configRecord)
47
96
  };
48
97
  }
49
98
 
@@ -1 +1 @@
1
- {"version":3,"file":"get-component.cjs","names":[],"sources":["../../src/create-config/get-component.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport type {\n LayoutResourceKey,\n ResourceDefinition,\n SubResourceDefinitionsFor,\n SubResourceParamForResource,\n} from '../resource';\nimport type {\n ResourceConfigComponentKey,\n ResourceConfigComponents,\n ResourceConfigEntry,\n ResourceConfigMap,\n ResourceConfigInput,\n} from './types';\n\ntype ResourceHasLayoutSubResources<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n> = [SubResourceDefinitionsFor<Resources, Resource>] extends [readonly []]\n ? false\n : true;\n\ntype SubResourceOptionForGenerics<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined,\n> = [SubResource] extends [undefined]\n ? ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? {\n subResource?: SubResourceParamForResource<Resources, Resource>;\n }\n : {}\n : ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? { subResource?: SubResource }\n : {};\n\n/** Options for one layout resource passed to {@link GetComponent}. */\nexport type GetComponentOptionsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = SubResourceOptionForGenerics<Resources, Resource, SubResource> & {\n resource: Resource;\n /**\n * The component to get.\n *\n * @default 'component'\n */\n component?: ResourceConfigComponentKey;\n};\n\n/** Union of valid `getComponent` option shapes for each declared layout resource. */\nexport type GetComponentOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentOptionsForResource<Resources, Resource>\n : never\n : never;\n\n/** `subResource` bound by {@link GetComponentForResource}. */\nexport type SubResourceFromGetComponentBound<Bound> = Bound extends {\n subResource: infer SubResource;\n}\n ? SubResource\n : undefined;\n\n/** Options for {@link GetComponentForResource} — binds `resource` and optional `subResource`. */\nexport type GetComponentForResourceOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = {\n resource: Resource;\n} & SubResourceOptionForGenerics<Resources, Resource, SubResource>;\n\n/** Valid bind shapes for {@link GetComponentForResource}. */\nexport type GetComponentForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentForResourceOptions<Resources, Resource>\n : never\n : never;\n\ntype GetComponentForResourceOptionsForBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = GetComponentForResourceOptions<\n Resources,\n Bound['resource'],\n SubResourceFromGetComponentBound<Bound>\n>;\n\n/**\n * Rejects bind objects with keys (e.g. `subResource`) that are invalid for the\n * given `resource`. Union assignability alone is too permissive for excess keys.\n */\nexport type ValidateForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = Bound extends GetComponentForResourceOptionsForBound<Resources, Bound>\n ? keyof Bound extends keyof GetComponentForResourceOptionsForBound<\n Resources,\n Bound\n >\n ? Bound\n : never\n : never;\n\n/** `resource` inferred from a {@link GetComponentForResource} bind argument. */\nexport type ResourceFromGetComponentBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound,\n> = Bound extends {\n resource: infer Resource extends LayoutResourceKey<Resources>;\n}\n ? Resource\n : never;\n\n/** Reusable getter returned by {@link GetComponentForResource} (only `component` remains). */\nexport type GetComponentAtBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = (\n options?: Pick<\n GetComponentOptionsForResource<Resources, Resource, SubResource>,\n 'component'\n >,\n) => JSX.Element;\n\nexport type GetComponentForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <\n const Bound extends {\n resource: LayoutResourceKey<Resources>;\n },\n>(\n bound: ValidateForResourceBound<Resources, Bound>,\n) => GetComponentAtBound<\n Resources,\n ResourceFromGetComponentBound<Resources, Bound>,\n SubResourceFromGetComponentBound<Bound>\n>;\n\nexport interface GetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n <const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ): JSX.Element;\n forResource: GetComponentForResource<Resources>;\n}\n\nexport interface CreatedResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n config: ResourceConfigMap<Resources>;\n getComponent: GetComponent<Resources>;\n}\n\nexport type CreateResourceConfigFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <const Config extends ResourceConfigMap<Resources>>(\n config: ResourceConfigInput<Resources, Config>,\n) => CreatedResourceConfig<Resources>;\n\ntype SubResourceParam =\n | string\n | {\n resource: string;\n subResource: SubResourceParam;\n };\n\nfunction resolveResourceConfigEntry(\n entry: ResourceConfigEntry,\n subResource: SubResourceParam,\n): ResourceConfigEntry {\n if (typeof subResource === 'string') {\n const next = entry.subResources?.[subResource];\n if (!next) {\n throw new Error(`Sub-resource \"${subResource}\" is not configured`);\n }\n return next;\n }\n\n const next = entry.subResources?.[subResource.resource];\n if (!next) {\n throw new Error(`Sub-resource \"${subResource.resource}\" is not configured`);\n }\n\n return resolveResourceConfigEntry(next, subResource.subResource);\n}\n\nfunction readResourceConfigComponent(\n entry: ResourceConfigComponents,\n componentKey: ResourceConfigComponentKey,\n): JSX.Element {\n if (componentKey === 'new' || componentKey === 'detail') {\n const branch = entry[componentKey];\n\n if (!branch?.component) {\n throw new Error(`Missing \"${componentKey}.component\" configuration`);\n }\n\n return branch.component;\n }\n\n const value = entry[componentKey];\n\n if (!value) {\n throw new Error(`Missing \"${componentKey}\" configuration`);\n }\n\n return value;\n}\n\nfunction getComponentFromOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n config: ResourceConfigMap<Resources>,\n options: GetComponentOptions<Resources>,\n): JSX.Element {\n const { resource, component: componentKey = 'component' } = options;\n const resourceEntry = config[resource];\n\n if (!resourceEntry) {\n throw new Error(`Resource \"${resource}\" is not configured`);\n }\n\n let entry: ResourceConfigEntry = resourceEntry;\n\n if ('subResource' in options && options.subResource !== undefined) {\n entry = resolveResourceConfigEntry(entry, options.subResource);\n }\n\n return readResourceConfigComponent(entry, componentKey);\n}\n\nexport function createGetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): GetComponent<Resources> {\n function getComponent<const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ) {\n return getComponentFromOptions(config, options);\n }\n\n const forResource: GetComponentForResource<Resources> = (bound) => {\n return (options) =>\n getComponentFromOptions(config, {\n ...bound,\n ...options,\n } as unknown as GetComponentOptions<Resources>);\n };\n\n return Object.assign(getComponent, { forResource });\n}\n\nexport function createResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): CreatedResourceConfig<Resources> {\n return {\n config,\n getComponent: createGetComponent(config),\n };\n}\n"],"mappings":";;AAyLA,SAAS,2BACP,OACA,aACqB;CACrB,IAAI,OAAO,gBAAgB,UAAU;EACnC,MAAM,OAAO,MAAM,eAAe;EAClC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iBAAiB,YAAY,oBAAoB;EAEnE,OAAO;CACT;CAEA,MAAM,OAAO,MAAM,eAAe,YAAY;CAC9C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iBAAiB,YAAY,SAAS,oBAAoB;CAG5E,OAAO,2BAA2B,MAAM,YAAY,WAAW;AACjE;AAEA,SAAS,4BACP,OACA,cACa;CACb,IAAI,iBAAiB,SAAS,iBAAiB,UAAU;EACvD,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,QAAQ,WACX,MAAM,IAAI,MAAM,YAAY,aAAa,0BAA0B;EAGrE,OAAO,OAAO;CAChB;CAEA,MAAM,QAAQ,MAAM;CAEpB,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,YAAY,aAAa,gBAAgB;CAG3D,OAAO;AACT;AAEA,SAAS,wBAGP,QACA,SACa;CACb,MAAM,EAAE,UAAU,WAAW,eAAe,gBAAgB;CAC5D,MAAM,gBAAgB,OAAO;CAE7B,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,aAAa,SAAS,oBAAoB;CAG5D,IAAI,QAA6B;CAEjC,IAAI,iBAAiB,WAAW,QAAQ,gBAAgB,QACtD,QAAQ,2BAA2B,OAAO,QAAQ,WAAW;CAG/D,OAAO,4BAA4B,OAAO,YAAY;AACxD;AAEA,SAAgB,mBAEd,QAA+D;CAC/D,SAAS,aACP,SACA;EACA,OAAO,wBAAwB,QAAQ,OAAO;CAChD;CAEA,MAAM,eAAmD,UAAU;EACjE,QAAQ,YACN,wBAAwB,QAAQ;GAC9B,GAAG;GACH,GAAG;EACL,CAA8C;CAClD;CAEA,OAAO,OAAO,OAAO,cAAc,EAAE,YAAY,CAAC;AACpD;AAEA,SAAgB,qBAEd,QAAwE;CACxE,OAAO;EACL;EACA,cAAc,mBAAmB,MAAM;CACzC;AACF"}
1
+ {"version":3,"file":"get-component.cjs","names":["InvalidSubResourceError","readSubResourceKeys","InvalidComponentError","readComponentKeys","InvalidResourceError","collectConfigResources","InvalidPathError","InvalidConfigError","createGetComponentForPath","createForPaths","createIsSubResourceKey","collectAllSubResourceKeys"],"sources":["../../src/create-config/get-component.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport {\n InvalidComponentError,\n InvalidConfigError,\n InvalidPathError,\n InvalidResourceError,\n InvalidSubResourceError,\n} from '../errors';\nimport type {\n LayoutResourceKey,\n ResourceDefinition,\n ResourceDefinitionForKey,\n SubResourceDefinitionsFor,\n SubResourceParamForResource,\n} from '../resource';\nimport {\n createForPaths,\n createGetComponentForPath,\n type CreateGetComponentForPath,\n type ForPaths,\n} from './for-paths';\nimport {\n createIsSubResourceKey,\n type IsSubResourceKey,\n} from './is-sub-resource-key';\nimport {\n readComponentKeys,\n readSubResourceKeys,\n} from './component-keys';\nimport {\n collectAllSubResourceKeys,\n collectConfigResources,\n} from './paths';\nimport type {\n ConfigSubResourceKeys,\n ParameterizedResourcePath,\n} from './paths';\nimport type {\n BaseResourceConfigComponents,\n ResourceConfigComponentKey,\n ResourceConfigComponents,\n ResourceConfigEntry,\n ResourceConfigMap,\n ResourceConfigInput,\n SharedResourceConfigOptions,\n} from './types';\n\ntype ResourceHasLayoutSubResources<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n> = [SubResourceDefinitionsFor<Resources, Resource>] extends [readonly []]\n ? false\n : true;\n\ntype SubResourceOptionForGenerics<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined,\n> = [SubResource] extends [undefined]\n ? ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? {\n subResource?: SubResourceParamForResource<Resources, Resource>;\n }\n : {}\n : ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? { subResource?: SubResource }\n : {};\n\n/** Options for one layout resource passed to {@link GetComponent}. */\nexport type GetComponentOptionsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = SubResourceOptionForGenerics<Resources, Resource, SubResource> & {\n resource: Resource;\n /**\n * The component to get.\n *\n * @default 'component'\n */\n component?: ResourceConfigComponentKey;\n};\n\n/** Union of valid `getComponent` option shapes for each declared layout resource. */\nexport type GetComponentOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentOptionsForResource<Resources, Resource>\n : never\n : never;\n\ntype ComponentSlotPathKey = keyof BaseResourceConfigComponents;\n\n/** `detail.errorComponent`, `new.component`, … — component slots inside a shared branch. */\ntype SharedBranchPath = {\n [Branch in keyof SharedResourceConfigOptions]: `${Branch}.${ComponentSlotPathKey}`;\n}[keyof SharedResourceConfigOptions];\n\ntype NestedSubResourceDefinitions<Def extends ResourceDefinition> = Def extends {\n subResources: infer Nested extends ReadonlyArray<ResourceDefinition>;\n}\n ? Nested\n : readonly [];\n\ntype SubResourceEntryPaths<\n SubDefs extends ReadonlyArray<ResourceDefinition>,\n DepthAcc extends readonly unknown[],\n> =\n LayoutResourceKey<SubDefs> extends infer Key extends string\n ? Key extends LayoutResourceKey<SubDefs>\n ?\n | Key\n | `${Key}.${ResourceConfigEntryPath<\n NestedSubResourceDefinitions<\n ResourceDefinitionForKey<SubDefs, Key>\n >,\n readonly [...DepthAcc, unknown]\n >}`\n : never\n : never;\n\n/** Dot-separated keys below one config node: component slots and nested sub-resources. */\ntype ResourceConfigEntryPath<\n SubDefs extends ReadonlyArray<ResourceDefinition>,\n DepthAcc extends readonly unknown[] = readonly [],\n> =\n | ComponentSlotPathKey\n | SharedBranchPath\n | ([SubDefs] extends [readonly []]\n ? never\n : DepthAcc['length'] extends 6\n ? never\n : SubResourceEntryPaths<SubDefs, DepthAcc>);\n\n/**\n * Deep config paths accepted by {@link GetComponent}, e.g.\n * `'templates.deleted.expired.errorComponent'`. Sub-resource segments come from the\n * layout tree, so only declared sub-resources are allowed at each depth.\n */\nexport type ResourceConfigPath<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource extends string\n ? Resource extends LayoutResourceKey<Resources>\n ?\n | Resource\n | `${Resource}.${ResourceConfigEntryPath<\n SubResourceDefinitionsFor<Resources, Resource>\n >}`\n : never\n : never;\n\n/** `subResource` bound by {@link GetComponentForResource}. */\nexport type SubResourceFromGetComponentBound<Bound> = Bound extends {\n subResource: infer SubResource;\n}\n ? SubResource\n : undefined;\n\n/** Options for {@link GetComponentForResource} — binds `resource` and optional `subResource`. */\nexport type GetComponentForResourceOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = {\n resource: Resource;\n} & SubResourceOptionForGenerics<Resources, Resource, SubResource>;\n\n/** Valid bind shapes for {@link GetComponentForResource}. */\nexport type GetComponentForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentForResourceOptions<Resources, Resource>\n : never\n : never;\n\ntype GetComponentForResourceOptionsForBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = GetComponentForResourceOptions<\n Resources,\n Bound['resource'],\n SubResourceFromGetComponentBound<Bound>\n>;\n\n/**\n * Rejects bind objects with keys (e.g. `subResource`) that are invalid for the\n * given `resource`. Union assignability alone is too permissive for excess keys.\n */\nexport type ValidateForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = Bound extends GetComponentForResourceOptionsForBound<Resources, Bound>\n ? keyof Bound extends keyof GetComponentForResourceOptionsForBound<\n Resources,\n Bound\n >\n ? Bound\n : never\n : never;\n\n/** `resource` inferred from a {@link GetComponentForResource} bind argument. */\nexport type ResourceFromGetComponentBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound,\n> = Bound extends {\n resource: infer Resource extends LayoutResourceKey<Resources>;\n}\n ? Resource\n : never;\n\n/** Reusable getter returned by {@link GetComponentForResource} (only `component` remains). */\nexport type GetComponentAtBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = (\n options?: Pick<\n GetComponentOptionsForResource<Resources, Resource, SubResource>,\n 'component'\n >,\n) => JSX.Element;\n\nexport type GetComponentForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <\n const Bound extends {\n resource: LayoutResourceKey<Resources>;\n },\n>(\n bound: ValidateForResourceBound<Resources, Bound>,\n) => GetComponentAtBound<\n Resources,\n ResourceFromGetComponentBound<Resources, Bound>,\n SubResourceFromGetComponentBound<Bound>\n>;\n\nexport interface GetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n /** Looks up a component by resource / optional sub-resource / optional component slot. */\n <const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ): JSX.Element;\n /**\n * Looks up a component by a deep config path.\n * A path ending on a branch (e.g. `'templates.deleted.expired'`) returns that branch's\n * `component`; a path ending on a slot returns that slot.\n */\n <const Path extends ResourceConfigPath<Resources>>(path: Path): JSX.Element;\n forResource: GetComponentForResource<Resources>;\n}\n\nexport interface CreatedResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends ResourceConfigMap<Resources> = ResourceConfigMap<Resources>,\n> {\n config: Config;\n getComponent: GetComponent<Resources>;\n /**\n * Creates a reusable getter bound to one path. Variables the path leaves open become\n * the getter's arguments.\n *\n * @example\n * ```ts\n * const getDetail = createGetComponent('$resource.detail.$component');\n *\n * getDetail({ resource: 'templates', component: 'errorComponent' });\n * ```\n */\n createGetComponent: CreateGetComponentForPath<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /**\n * Builds a component for one or more paths. Declare which params the component takes,\n * then render it.\n *\n * @example\n * ```ts\n * const ResourceDetail = forPaths('$resource.detail.$component')\n * .addPathParams()\n * .render(({ params, getComponentForPath }) =>\n * getComponentForPath('$resource.detail.$component')(params),\n * );\n * ```\n */\n forPaths: ForPaths<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /** Narrows an unknown value to a sub-resource key configured for a path or resource. */\n isSubResourceKey: IsSubResourceKey<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /** Every sub-resource key configured in this config, at any depth. */\n subResources: ReadonlyArray<ConfigSubResourceKeys<Resources, Config>>;\n}\n\ntype ComponentTypesFromEntry<Entry> = Entry extends JSX.Element\n ? never\n : Entry extends object\n ?\n | Extract<keyof Entry, ResourceConfigComponentKey>\n | {\n [Key in keyof Entry]: NonNullable<Entry[Key]> extends JSX.Element\n ? never\n : ComponentTypesFromEntry<NonNullable<Entry[Key]>>;\n }[keyof Entry]\n : never;\n\n/**\n * Component selector keys actually defined anywhere in a created resource config.\n *\n * @example\n * ```ts\n * ComponentTypes<typeof resourceConfig>\n * // ^? may resolve to:`'component' | 'errorComponent' | 'detail'`.\n * ```\n */\nexport type ComponentTypes<Created> = Created extends {\n config: infer Config extends object;\n}\n ? {\n [Resource in keyof Config]: ComponentTypesFromEntry<\n NonNullable<Config[Resource]>\n >;\n }[keyof Config]\n : never;\n\nexport type CreateResourceConfigFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <const Config extends ResourceConfigMap<Resources>>(\n config: ResourceConfigInput<Resources, Config>,\n) => CreatedResourceConfig<Resources, Config>;\n\ntype SubResourceParam =\n | string\n | {\n value: string;\n subResource: SubResourceParam;\n };\n\nfunction isResourceConfigEntry(value: unknown): value is ResourceConfigEntry {\n return typeof value === 'object' && value !== null;\n}\n\nfunction resolveResourceConfigEntry(\n entry: ResourceConfigEntry,\n subResource: SubResourceParam,\n): ResourceConfigEntry {\n const key = typeof subResource === 'string' ? subResource : subResource.value;\n const next = entry[key];\n\n if (!isResourceConfigEntry(next)) {\n throw new InvalidSubResourceError({\n subResource: key,\n validSubResources: readSubResourceKeys(entry),\n });\n }\n\n if (typeof subResource === 'string') {\n return next;\n }\n\n return resolveResourceConfigEntry(next, subResource.subResource);\n}\n\nfunction readResourceConfigComponent(\n entry: ResourceConfigComponents,\n componentKey: ResourceConfigComponentKey,\n): JSX.Element {\n if (componentKey === 'new' || componentKey === 'detail') {\n const branch = entry[componentKey];\n\n if (!branch?.component) {\n throw new InvalidComponentError({\n component: `${componentKey}.component`,\n validComponents: readComponentKeys(entry),\n });\n }\n\n return branch.component;\n }\n\n const value = entry[componentKey];\n\n if (!value) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: readComponentKeys(entry),\n });\n }\n\n return value;\n}\n\nfunction getComponentFromOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n config: ResourceConfigMap<Resources>,\n options: GetComponentOptions<Resources>,\n): JSX.Element {\n const { resource, component: componentKey = 'component' } = options;\n const resourceEntry = config[resource];\n\n if (!resourceEntry) {\n throw new InvalidResourceError({\n resource,\n validResources: collectConfigResources(config as Record<string, unknown>),\n });\n }\n\n let entry = resourceEntry as ResourceConfigEntry;\n\n if ('subResource' in options && options.subResource !== undefined) {\n entry = resolveResourceConfigEntry(entry, options.subResource);\n }\n\n return readResourceConfigComponent(entry, componentKey);\n}\n\nfunction getComponentFromPath<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>, path: string): JSX.Element {\n let cursor: unknown = config;\n\n for (const segment of path.split('.')) {\n if (!isResourceConfigEntry(cursor)) {\n throw new InvalidPathError({\n path,\n reason: `\"${segment}\" cannot be read because the value before it is not a config branch`,\n });\n }\n\n const next: unknown = (cursor as Record<string, unknown>)[segment];\n\n if (next === undefined || next === null) {\n throw new InvalidPathError({\n path,\n reason: `\"${segment}\" is not configured`,\n });\n }\n\n cursor = next;\n }\n\n if (isResourceConfigEntry(cursor) && 'component' in cursor) {\n return readResourceConfigComponent(cursor, 'component');\n }\n\n return cursor as JSX.Element;\n}\n\nexport function createGetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): GetComponent<Resources> {\n function getComponent(options: GetComponentOptions<Resources>): JSX.Element;\n function getComponent(path: ResourceConfigPath<Resources>): JSX.Element;\n function getComponent(\n options: GetComponentOptions<Resources> | ResourceConfigPath<Resources>,\n ): JSX.Element {\n if (typeof options === 'string') {\n return getComponentFromPath(config, options);\n }\n\n return getComponentFromOptions(config, options);\n }\n\n const forResource: GetComponentForResource<Resources> = (bound) => {\n return (options) =>\n getComponentFromOptions(config, {\n ...bound,\n ...options,\n } as unknown as GetComponentOptions<Resources>);\n };\n\n return Object.assign(getComponent, { forResource });\n}\n\nexport function createResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n const Config extends ResourceConfigMap<Resources>,\n>(\n config: ResourceConfigInput<Resources, Config>,\n): CreatedResourceConfig<Resources, Config> {\n const configRecord = config as Record<string, unknown>;\n\n if (collectConfigResources(configRecord).length === 0) {\n throw new InvalidConfigError({\n reason: 'A resource config must configure at least one resource',\n config,\n });\n }\n\n type Created = CreatedResourceConfig<Resources, Config>;\n\n return {\n config,\n getComponent: createGetComponent(config),\n createGetComponent: ((path: string) =>\n createGetComponentForPath(\n configRecord,\n path,\n )) as unknown as Created['createGetComponent'],\n forPaths: createForPaths(configRecord) as unknown as Created['forPaths'],\n isSubResourceKey: createIsSubResourceKey(\n configRecord,\n ) as unknown as Created['isSubResourceKey'],\n subResources: collectAllSubResourceKeys(\n configRecord,\n ) as unknown as Created['subResources'],\n };\n}\n"],"mappings":";;;;;;;;;;;;AAuWA,SAAS,sBAAsB,OAA8C;CAC3E,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,2BACP,OACA,aACqB;CACrB,MAAM,MAAM,OAAO,gBAAgB,WAAW,cAAc,YAAY;CACxE,MAAM,OAAO,MAAM;CAEnB,IAAI,CAAC,sBAAsB,IAAI,GAC7B,MAAM,IAAIA,qDAAwB;EAChC,aAAa;EACb,mBAAmBC,2CAAoB,KAAK;CAC9C,CAAC;CAGH,IAAI,OAAO,gBAAgB,UACzB,OAAO;CAGT,OAAO,2BAA2B,MAAM,YAAY,WAAW;AACjE;AAEA,SAAS,4BACP,OACA,cACa;CACb,IAAI,iBAAiB,SAAS,iBAAiB,UAAU;EACvD,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,QAAQ,WACX,MAAM,IAAIC,gDAAsB;GAC9B,WAAW,GAAG,aAAa;GAC3B,iBAAiBC,yCAAkB,KAAK;EAC1C,CAAC;EAGH,OAAO,OAAO;CAChB;CAEA,MAAM,QAAQ,MAAM;CAEpB,IAAI,CAAC,OACH,MAAM,IAAID,gDAAsB;EAC9B,WAAW;EACX,iBAAiBC,yCAAkB,KAAK;CAC1C,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,wBAGP,QACA,SACa;CACb,MAAM,EAAE,UAAU,WAAW,eAAe,gBAAgB;CAC5D,MAAM,gBAAgB,OAAO;CAE7B,IAAI,CAAC,eACH,MAAM,IAAIC,8CAAqB;EAC7B;EACA,gBAAgBC,0CAAuB,MAAiC;CAC1E,CAAC;CAGH,IAAI,QAAQ;CAEZ,IAAI,iBAAiB,WAAW,QAAQ,gBAAgB,QACtD,QAAQ,2BAA2B,OAAO,QAAQ,WAAW;CAG/D,OAAO,4BAA4B,OAAO,YAAY;AACxD;AAEA,SAAS,qBAEP,QAAsC,MAA2B;CACjE,IAAI,SAAkB;CAEtB,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,GAAG;EACrC,IAAI,CAAC,sBAAsB,MAAM,GAC/B,MAAM,IAAIC,sCAAiB;GACzB;GACA,QAAQ,IAAI,QAAQ;EACtB,CAAC;EAGH,MAAM,OAAiB,OAAmC;EAE1D,IAAI,SAAS,UAAa,SAAS,MACjC,MAAM,IAAIA,sCAAiB;GACzB;GACA,QAAQ,IAAI,QAAQ;EACtB,CAAC;EAGH,SAAS;CACX;CAEA,IAAI,sBAAsB,MAAM,KAAK,eAAe,QAClD,OAAO,4BAA4B,QAAQ,WAAW;CAGxD,OAAO;AACT;AAEA,SAAgB,mBAEd,QAA+D;CAG/D,SAAS,aACP,SACa;EACb,IAAI,OAAO,YAAY,UACrB,OAAO,qBAAqB,QAAQ,OAAO;EAG7C,OAAO,wBAAwB,QAAQ,OAAO;CAChD;CAEA,MAAM,eAAmD,UAAU;EACjE,QAAQ,YACN,wBAAwB,QAAQ;GAC9B,GAAG;GACH,GAAG;EACL,CAA8C;CAClD;CAEA,OAAO,OAAO,OAAO,cAAc,EAAE,YAAY,CAAC;AACpD;AAEA,SAAgB,qBAId,QAC0C;CAC1C,MAAM,eAAe;CAErB,IAAID,0CAAuB,YAAY,EAAE,WAAW,GAClD,MAAM,IAAIE,0CAAmB;EAC3B,QAAQ;EACR;CACF,CAAC;CAKH,OAAO;EACL;EACA,cAAc,mBAAmB,MAAM;EACvC,sBAAsB,SACpBC,yDACE,cACA,IACF;EACF,UAAUC,+BAAe,YAAY;EACrC,kBAAkBC,mDAChB,YACF;EACA,cAAcC,6CACZ,YACF;CACF;AACF"}
@@ -1,5 +1,9 @@
1
- import { LayoutResourceKey, ResourceDefinition, SubResourceDefinitionsFor, SubResourceParamForResource } from "../resource.cjs";
2
- import { ResourceConfigComponentKey, ResourceConfigInput, ResourceConfigMap } from "./types.cjs";
1
+ import { LayoutResourceKey, ResourceDefinition, ResourceDefinitionForKey, SubResourceDefinitionsFor, SubResourceParamForResource } from "../resource.cjs";
2
+ import { BaseResourceConfigComponents, ResourceConfigComponentKey, ResourceConfigInput, ResourceConfigMap, SharedResourceConfigOptions } from "./types.cjs";
3
+ import { ConfigSubResourceKeys, ParameterizedResourcePath } from "./paths/types.cjs";
4
+ import { CreateGetComponentForPath } from "./for-paths/get-component-for-path.cjs";
5
+ import { ForPaths } from "./for-paths/builder.cjs";
6
+ import { IsSubResourceKey } from "./is-sub-resource-key.cjs";
3
7
  import { JSX } from "react";
4
8
 
5
9
  //#region src/create-config/get-component.d.ts
@@ -21,6 +25,21 @@ type GetComponentOptionsForResource<Resources extends ReadonlyArray<ResourceDefi
21
25
  };
22
26
  /** Union of valid `getComponent` option shapes for each declared layout resource. */
23
27
  type GetComponentOptions<Resources extends ReadonlyArray<ResourceDefinition>> = LayoutResourceKey<Resources> extends infer Resource ? Resource extends LayoutResourceKey<Resources> ? GetComponentOptionsForResource<Resources, Resource> : never : never;
28
+ type ComponentSlotPathKey = keyof BaseResourceConfigComponents;
29
+ /** `detail.errorComponent`, `new.component`, … — component slots inside a shared branch. */
30
+ type SharedBranchPath = { [Branch in keyof SharedResourceConfigOptions]: `${Branch}.${ComponentSlotPathKey}` }[keyof SharedResourceConfigOptions];
31
+ type NestedSubResourceDefinitions<Def extends ResourceDefinition> = Def extends {
32
+ subResources: infer Nested extends ReadonlyArray<ResourceDefinition>;
33
+ } ? Nested : readonly [];
34
+ type SubResourceEntryPaths<SubDefs extends ReadonlyArray<ResourceDefinition>, DepthAcc extends readonly unknown[]> = LayoutResourceKey<SubDefs> extends infer Key extends string ? Key extends LayoutResourceKey<SubDefs> ? Key | `${Key}.${ResourceConfigEntryPath<NestedSubResourceDefinitions<ResourceDefinitionForKey<SubDefs, Key>>, readonly [...DepthAcc, unknown]>}` : never : never;
35
+ /** Dot-separated keys below one config node: component slots and nested sub-resources. */
36
+ type ResourceConfigEntryPath<SubDefs extends ReadonlyArray<ResourceDefinition>, DepthAcc extends readonly unknown[] = readonly []> = ComponentSlotPathKey | SharedBranchPath | ([SubDefs] extends [readonly []] ? never : DepthAcc['length'] extends 6 ? never : SubResourceEntryPaths<SubDefs, DepthAcc>);
37
+ /**
38
+ * Deep config paths accepted by {@link GetComponent}, e.g.
39
+ * `'templates.deleted.expired.errorComponent'`. Sub-resource segments come from the
40
+ * layout tree, so only declared sub-resources are allowed at each depth.
41
+ */
42
+ type ResourceConfigPath<Resources extends ReadonlyArray<ResourceDefinition>> = LayoutResourceKey<Resources> extends infer Resource extends string ? Resource extends LayoutResourceKey<Resources> ? Resource | `${Resource}.${ResourceConfigEntryPath<SubResourceDefinitionsFor<Resources, Resource>>}` : never : never;
24
43
  /** `subResource` bound by {@link GetComponentForResource}. */
25
44
  type SubResourceFromGetComponentBound<Bound> = Bound extends {
26
45
  subResource: infer SubResource;
@@ -49,14 +68,64 @@ type GetComponentForResource<Resources extends ReadonlyArray<ResourceDefinition>
49
68
  resource: LayoutResourceKey<Resources>;
50
69
  }>(bound: ValidateForResourceBound<Resources, Bound>) => GetComponentAtBound<Resources, ResourceFromGetComponentBound<Resources, Bound>, SubResourceFromGetComponentBound<Bound>>;
51
70
  interface GetComponent<Resources extends ReadonlyArray<ResourceDefinition>> {
71
+ /** Looks up a component by resource / optional sub-resource / optional component slot. */
52
72
  <const Options extends GetComponentOptions<Resources>>(options: Options): JSX.Element;
73
+ /**
74
+ * Looks up a component by a deep config path.
75
+ * A path ending on a branch (e.g. `'templates.deleted.expired'`) returns that branch's
76
+ * `component`; a path ending on a slot returns that slot.
77
+ */
78
+ <const Path extends ResourceConfigPath<Resources>>(path: Path): JSX.Element;
53
79
  forResource: GetComponentForResource<Resources>;
54
80
  }
55
- interface CreatedResourceConfig<Resources extends ReadonlyArray<ResourceDefinition>> {
56
- config: ResourceConfigMap<Resources>;
81
+ interface CreatedResourceConfig<Resources extends ReadonlyArray<ResourceDefinition>, Config extends ResourceConfigMap<Resources> = ResourceConfigMap<Resources>> {
82
+ config: Config;
57
83
  getComponent: GetComponent<Resources>;
84
+ /**
85
+ * Creates a reusable getter bound to one path. Variables the path leaves open become
86
+ * the getter's arguments.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const getDetail = createGetComponent('$resource.detail.$component');
91
+ *
92
+ * getDetail({ resource: 'templates', component: 'errorComponent' });
93
+ * ```
94
+ */
95
+ createGetComponent: CreateGetComponentForPath<Resources, Config, ParameterizedResourcePath<Resources>>;
96
+ /**
97
+ * Builds a component for one or more paths. Declare which params the component takes,
98
+ * then render it.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const ResourceDetail = forPaths('$resource.detail.$component')
103
+ * .addPathParams()
104
+ * .render(({ params, getComponentForPath }) =>
105
+ * getComponentForPath('$resource.detail.$component')(params),
106
+ * );
107
+ * ```
108
+ */
109
+ forPaths: ForPaths<Resources, Config, ParameterizedResourcePath<Resources>>;
110
+ /** Narrows an unknown value to a sub-resource key configured for a path or resource. */
111
+ isSubResourceKey: IsSubResourceKey<Resources, Config, ParameterizedResourcePath<Resources>>;
112
+ /** Every sub-resource key configured in this config, at any depth. */
113
+ subResources: ReadonlyArray<ConfigSubResourceKeys<Resources, Config>>;
58
114
  }
59
- type CreateResourceConfigFn<Resources extends ReadonlyArray<ResourceDefinition>> = <const Config extends ResourceConfigMap<Resources>>(config: ResourceConfigInput<Resources, Config>) => CreatedResourceConfig<Resources>;
115
+ type ComponentTypesFromEntry<Entry> = Entry extends JSX.Element ? never : Entry extends object ? Extract<keyof Entry, ResourceConfigComponentKey> | { [Key in keyof Entry]: NonNullable<Entry[Key]> extends JSX.Element ? never : ComponentTypesFromEntry<NonNullable<Entry[Key]>> }[keyof Entry] : never;
116
+ /**
117
+ * Component selector keys actually defined anywhere in a created resource config.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * ComponentTypes<typeof resourceConfig>
122
+ * // ^? may resolve to:`'component' | 'errorComponent' | 'detail'`.
123
+ * ```
124
+ */
125
+ type ComponentTypes<Created> = Created extends {
126
+ config: infer Config extends object;
127
+ } ? { [Resource in keyof Config]: ComponentTypesFromEntry<NonNullable<Config[Resource]>> }[keyof Config] : never;
128
+ type CreateResourceConfigFn<Resources extends ReadonlyArray<ResourceDefinition>> = <const Config extends ResourceConfigMap<Resources>>(config: ResourceConfigInput<Resources, Config>) => CreatedResourceConfig<Resources, Config>;
60
129
  //#endregion
61
- export { CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound };
130
+ export { ComponentTypes, CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceConfigPath, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound };
62
131
  //# sourceMappingURL=get-component.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-component.d.cts","names":[],"sources":["../../src/create-config/get-component.ts"],"mappings":"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"}
1
+ {"version":3,"file":"get-component.d.cts","names":[],"sources":["../../src/create-config/get-component.ts"],"mappings":"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"}
@@ -1,5 +1,9 @@
1
- import { LayoutResourceKey, ResourceDefinition, SubResourceDefinitionsFor, SubResourceParamForResource } from "../resource.mjs";
2
- import { ResourceConfigComponentKey, ResourceConfigInput, ResourceConfigMap } from "./types.mjs";
1
+ import { LayoutResourceKey, ResourceDefinition, ResourceDefinitionForKey, SubResourceDefinitionsFor, SubResourceParamForResource } from "../resource.mjs";
2
+ import { BaseResourceConfigComponents, ResourceConfigComponentKey, ResourceConfigInput, ResourceConfigMap, SharedResourceConfigOptions } from "./types.mjs";
3
+ import { ConfigSubResourceKeys, ParameterizedResourcePath } from "./paths/types.mjs";
4
+ import { CreateGetComponentForPath } from "./for-paths/get-component-for-path.mjs";
5
+ import { ForPaths } from "./for-paths/builder.mjs";
6
+ import { IsSubResourceKey } from "./is-sub-resource-key.mjs";
3
7
  import { JSX } from "react";
4
8
 
5
9
  //#region src/create-config/get-component.d.ts
@@ -21,6 +25,21 @@ type GetComponentOptionsForResource<Resources extends ReadonlyArray<ResourceDefi
21
25
  };
22
26
  /** Union of valid `getComponent` option shapes for each declared layout resource. */
23
27
  type GetComponentOptions<Resources extends ReadonlyArray<ResourceDefinition>> = LayoutResourceKey<Resources> extends infer Resource ? Resource extends LayoutResourceKey<Resources> ? GetComponentOptionsForResource<Resources, Resource> : never : never;
28
+ type ComponentSlotPathKey = keyof BaseResourceConfigComponents;
29
+ /** `detail.errorComponent`, `new.component`, … — component slots inside a shared branch. */
30
+ type SharedBranchPath = { [Branch in keyof SharedResourceConfigOptions]: `${Branch}.${ComponentSlotPathKey}` }[keyof SharedResourceConfigOptions];
31
+ type NestedSubResourceDefinitions<Def extends ResourceDefinition> = Def extends {
32
+ subResources: infer Nested extends ReadonlyArray<ResourceDefinition>;
33
+ } ? Nested : readonly [];
34
+ type SubResourceEntryPaths<SubDefs extends ReadonlyArray<ResourceDefinition>, DepthAcc extends readonly unknown[]> = LayoutResourceKey<SubDefs> extends infer Key extends string ? Key extends LayoutResourceKey<SubDefs> ? Key | `${Key}.${ResourceConfigEntryPath<NestedSubResourceDefinitions<ResourceDefinitionForKey<SubDefs, Key>>, readonly [...DepthAcc, unknown]>}` : never : never;
35
+ /** Dot-separated keys below one config node: component slots and nested sub-resources. */
36
+ type ResourceConfigEntryPath<SubDefs extends ReadonlyArray<ResourceDefinition>, DepthAcc extends readonly unknown[] = readonly []> = ComponentSlotPathKey | SharedBranchPath | ([SubDefs] extends [readonly []] ? never : DepthAcc['length'] extends 6 ? never : SubResourceEntryPaths<SubDefs, DepthAcc>);
37
+ /**
38
+ * Deep config paths accepted by {@link GetComponent}, e.g.
39
+ * `'templates.deleted.expired.errorComponent'`. Sub-resource segments come from the
40
+ * layout tree, so only declared sub-resources are allowed at each depth.
41
+ */
42
+ type ResourceConfigPath<Resources extends ReadonlyArray<ResourceDefinition>> = LayoutResourceKey<Resources> extends infer Resource extends string ? Resource extends LayoutResourceKey<Resources> ? Resource | `${Resource}.${ResourceConfigEntryPath<SubResourceDefinitionsFor<Resources, Resource>>}` : never : never;
24
43
  /** `subResource` bound by {@link GetComponentForResource}. */
25
44
  type SubResourceFromGetComponentBound<Bound> = Bound extends {
26
45
  subResource: infer SubResource;
@@ -49,14 +68,64 @@ type GetComponentForResource<Resources extends ReadonlyArray<ResourceDefinition>
49
68
  resource: LayoutResourceKey<Resources>;
50
69
  }>(bound: ValidateForResourceBound<Resources, Bound>) => GetComponentAtBound<Resources, ResourceFromGetComponentBound<Resources, Bound>, SubResourceFromGetComponentBound<Bound>>;
51
70
  interface GetComponent<Resources extends ReadonlyArray<ResourceDefinition>> {
71
+ /** Looks up a component by resource / optional sub-resource / optional component slot. */
52
72
  <const Options extends GetComponentOptions<Resources>>(options: Options): JSX.Element;
73
+ /**
74
+ * Looks up a component by a deep config path.
75
+ * A path ending on a branch (e.g. `'templates.deleted.expired'`) returns that branch's
76
+ * `component`; a path ending on a slot returns that slot.
77
+ */
78
+ <const Path extends ResourceConfigPath<Resources>>(path: Path): JSX.Element;
53
79
  forResource: GetComponentForResource<Resources>;
54
80
  }
55
- interface CreatedResourceConfig<Resources extends ReadonlyArray<ResourceDefinition>> {
56
- config: ResourceConfigMap<Resources>;
81
+ interface CreatedResourceConfig<Resources extends ReadonlyArray<ResourceDefinition>, Config extends ResourceConfigMap<Resources> = ResourceConfigMap<Resources>> {
82
+ config: Config;
57
83
  getComponent: GetComponent<Resources>;
84
+ /**
85
+ * Creates a reusable getter bound to one path. Variables the path leaves open become
86
+ * the getter's arguments.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const getDetail = createGetComponent('$resource.detail.$component');
91
+ *
92
+ * getDetail({ resource: 'templates', component: 'errorComponent' });
93
+ * ```
94
+ */
95
+ createGetComponent: CreateGetComponentForPath<Resources, Config, ParameterizedResourcePath<Resources>>;
96
+ /**
97
+ * Builds a component for one or more paths. Declare which params the component takes,
98
+ * then render it.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const ResourceDetail = forPaths('$resource.detail.$component')
103
+ * .addPathParams()
104
+ * .render(({ params, getComponentForPath }) =>
105
+ * getComponentForPath('$resource.detail.$component')(params),
106
+ * );
107
+ * ```
108
+ */
109
+ forPaths: ForPaths<Resources, Config, ParameterizedResourcePath<Resources>>;
110
+ /** Narrows an unknown value to a sub-resource key configured for a path or resource. */
111
+ isSubResourceKey: IsSubResourceKey<Resources, Config, ParameterizedResourcePath<Resources>>;
112
+ /** Every sub-resource key configured in this config, at any depth. */
113
+ subResources: ReadonlyArray<ConfigSubResourceKeys<Resources, Config>>;
58
114
  }
59
- type CreateResourceConfigFn<Resources extends ReadonlyArray<ResourceDefinition>> = <const Config extends ResourceConfigMap<Resources>>(config: ResourceConfigInput<Resources, Config>) => CreatedResourceConfig<Resources>;
115
+ type ComponentTypesFromEntry<Entry> = Entry extends JSX.Element ? never : Entry extends object ? Extract<keyof Entry, ResourceConfigComponentKey> | { [Key in keyof Entry]: NonNullable<Entry[Key]> extends JSX.Element ? never : ComponentTypesFromEntry<NonNullable<Entry[Key]>> }[keyof Entry] : never;
116
+ /**
117
+ * Component selector keys actually defined anywhere in a created resource config.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * ComponentTypes<typeof resourceConfig>
122
+ * // ^? may resolve to:`'component' | 'errorComponent' | 'detail'`.
123
+ * ```
124
+ */
125
+ type ComponentTypes<Created> = Created extends {
126
+ config: infer Config extends object;
127
+ } ? { [Resource in keyof Config]: ComponentTypesFromEntry<NonNullable<Config[Resource]>> }[keyof Config] : never;
128
+ type CreateResourceConfigFn<Resources extends ReadonlyArray<ResourceDefinition>> = <const Config extends ResourceConfigMap<Resources>>(config: ResourceConfigInput<Resources, Config>) => CreatedResourceConfig<Resources, Config>;
60
129
  //#endregion
61
- export { CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound };
130
+ export { ComponentTypes, CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceConfigPath, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound };
62
131
  //# sourceMappingURL=get-component.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-component.d.mts","names":[],"sources":["../../src/create-config/get-component.ts"],"mappings":"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"}
1
+ {"version":3,"file":"get-component.d.mts","names":[],"sources":["../../src/create-config/get-component.ts"],"mappings":"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"}
@@ -1,34 +1,75 @@
1
+ import { InvalidConfigError } from "../errors/invalid-config.mjs";
2
+ import { InvalidPathError } from "../errors/invalid-path.mjs";
3
+ import { InvalidResourceError } from "../errors/invalid-resource.mjs";
4
+ import { InvalidSubResourceError } from "../errors/invalid-sub-resource.mjs";
5
+ import { InvalidComponentError } from "../errors/invalid-component.mjs";
6
+ import { readComponentKeys, readSubResourceKeys } from "./component-keys.mjs";
7
+ import { collectAllSubResourceKeys, collectConfigResources } from "./paths/introspect.mjs";
8
+ import { createGetComponentForPath } from "./for-paths/get-component-for-path.mjs";
9
+ import { createForPaths } from "./for-paths/builder.mjs";
10
+ import { createIsSubResourceKey } from "./is-sub-resource-key.mjs";
11
+
1
12
  //#region src/create-config/get-component.ts
13
+ function isResourceConfigEntry(value) {
14
+ return typeof value === "object" && value !== null;
15
+ }
2
16
  function resolveResourceConfigEntry(entry, subResource) {
3
- if (typeof subResource === "string") {
4
- const next = entry.subResources?.[subResource];
5
- if (!next) throw new Error(`Sub-resource "${subResource}" is not configured`);
6
- return next;
7
- }
8
- const next = entry.subResources?.[subResource.resource];
9
- if (!next) throw new Error(`Sub-resource "${subResource.resource}" is not configured`);
17
+ const key = typeof subResource === "string" ? subResource : subResource.value;
18
+ const next = entry[key];
19
+ if (!isResourceConfigEntry(next)) throw new InvalidSubResourceError({
20
+ subResource: key,
21
+ validSubResources: readSubResourceKeys(entry)
22
+ });
23
+ if (typeof subResource === "string") return next;
10
24
  return resolveResourceConfigEntry(next, subResource.subResource);
11
25
  }
12
26
  function readResourceConfigComponent(entry, componentKey) {
13
27
  if (componentKey === "new" || componentKey === "detail") {
14
28
  const branch = entry[componentKey];
15
- if (!branch?.component) throw new Error(`Missing "${componentKey}.component" configuration`);
29
+ if (!branch?.component) throw new InvalidComponentError({
30
+ component: `${componentKey}.component`,
31
+ validComponents: readComponentKeys(entry)
32
+ });
16
33
  return branch.component;
17
34
  }
18
35
  const value = entry[componentKey];
19
- if (!value) throw new Error(`Missing "${componentKey}" configuration`);
36
+ if (!value) throw new InvalidComponentError({
37
+ component: componentKey,
38
+ validComponents: readComponentKeys(entry)
39
+ });
20
40
  return value;
21
41
  }
22
42
  function getComponentFromOptions(config, options) {
23
43
  const { resource, component: componentKey = "component" } = options;
24
44
  const resourceEntry = config[resource];
25
- if (!resourceEntry) throw new Error(`Resource "${resource}" is not configured`);
45
+ if (!resourceEntry) throw new InvalidResourceError({
46
+ resource,
47
+ validResources: collectConfigResources(config)
48
+ });
26
49
  let entry = resourceEntry;
27
50
  if ("subResource" in options && options.subResource !== void 0) entry = resolveResourceConfigEntry(entry, options.subResource);
28
51
  return readResourceConfigComponent(entry, componentKey);
29
52
  }
53
+ function getComponentFromPath(config, path) {
54
+ let cursor = config;
55
+ for (const segment of path.split(".")) {
56
+ if (!isResourceConfigEntry(cursor)) throw new InvalidPathError({
57
+ path,
58
+ reason: `"${segment}" cannot be read because the value before it is not a config branch`
59
+ });
60
+ const next = cursor[segment];
61
+ if (next === void 0 || next === null) throw new InvalidPathError({
62
+ path,
63
+ reason: `"${segment}" is not configured`
64
+ });
65
+ cursor = next;
66
+ }
67
+ if (isResourceConfigEntry(cursor) && "component" in cursor) return readResourceConfigComponent(cursor, "component");
68
+ return cursor;
69
+ }
30
70
  function createGetComponent(config) {
31
71
  function getComponent(options) {
72
+ if (typeof options === "string") return getComponentFromPath(config, options);
32
73
  return getComponentFromOptions(config, options);
33
74
  }
34
75
  const forResource = (bound) => {
@@ -40,9 +81,18 @@ function createGetComponent(config) {
40
81
  return Object.assign(getComponent, { forResource });
41
82
  }
42
83
  function createResourceConfig(config) {
84
+ const configRecord = config;
85
+ if (collectConfigResources(configRecord).length === 0) throw new InvalidConfigError({
86
+ reason: "A resource config must configure at least one resource",
87
+ config
88
+ });
43
89
  return {
44
90
  config,
45
- getComponent: createGetComponent(config)
91
+ getComponent: createGetComponent(config),
92
+ createGetComponent: ((path) => createGetComponentForPath(configRecord, path)),
93
+ forPaths: createForPaths(configRecord),
94
+ isSubResourceKey: createIsSubResourceKey(configRecord),
95
+ subResources: collectAllSubResourceKeys(configRecord)
46
96
  };
47
97
  }
48
98
 
@@ -1 +1 @@
1
- {"version":3,"file":"get-component.mjs","names":[],"sources":["../../src/create-config/get-component.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport type {\n LayoutResourceKey,\n ResourceDefinition,\n SubResourceDefinitionsFor,\n SubResourceParamForResource,\n} from '../resource';\nimport type {\n ResourceConfigComponentKey,\n ResourceConfigComponents,\n ResourceConfigEntry,\n ResourceConfigMap,\n ResourceConfigInput,\n} from './types';\n\ntype ResourceHasLayoutSubResources<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n> = [SubResourceDefinitionsFor<Resources, Resource>] extends [readonly []]\n ? false\n : true;\n\ntype SubResourceOptionForGenerics<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined,\n> = [SubResource] extends [undefined]\n ? ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? {\n subResource?: SubResourceParamForResource<Resources, Resource>;\n }\n : {}\n : ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? { subResource?: SubResource }\n : {};\n\n/** Options for one layout resource passed to {@link GetComponent}. */\nexport type GetComponentOptionsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = SubResourceOptionForGenerics<Resources, Resource, SubResource> & {\n resource: Resource;\n /**\n * The component to get.\n *\n * @default 'component'\n */\n component?: ResourceConfigComponentKey;\n};\n\n/** Union of valid `getComponent` option shapes for each declared layout resource. */\nexport type GetComponentOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentOptionsForResource<Resources, Resource>\n : never\n : never;\n\n/** `subResource` bound by {@link GetComponentForResource}. */\nexport type SubResourceFromGetComponentBound<Bound> = Bound extends {\n subResource: infer SubResource;\n}\n ? SubResource\n : undefined;\n\n/** Options for {@link GetComponentForResource} — binds `resource` and optional `subResource`. */\nexport type GetComponentForResourceOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = {\n resource: Resource;\n} & SubResourceOptionForGenerics<Resources, Resource, SubResource>;\n\n/** Valid bind shapes for {@link GetComponentForResource}. */\nexport type GetComponentForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentForResourceOptions<Resources, Resource>\n : never\n : never;\n\ntype GetComponentForResourceOptionsForBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = GetComponentForResourceOptions<\n Resources,\n Bound['resource'],\n SubResourceFromGetComponentBound<Bound>\n>;\n\n/**\n * Rejects bind objects with keys (e.g. `subResource`) that are invalid for the\n * given `resource`. Union assignability alone is too permissive for excess keys.\n */\nexport type ValidateForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = Bound extends GetComponentForResourceOptionsForBound<Resources, Bound>\n ? keyof Bound extends keyof GetComponentForResourceOptionsForBound<\n Resources,\n Bound\n >\n ? Bound\n : never\n : never;\n\n/** `resource` inferred from a {@link GetComponentForResource} bind argument. */\nexport type ResourceFromGetComponentBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound,\n> = Bound extends {\n resource: infer Resource extends LayoutResourceKey<Resources>;\n}\n ? Resource\n : never;\n\n/** Reusable getter returned by {@link GetComponentForResource} (only `component` remains). */\nexport type GetComponentAtBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = (\n options?: Pick<\n GetComponentOptionsForResource<Resources, Resource, SubResource>,\n 'component'\n >,\n) => JSX.Element;\n\nexport type GetComponentForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <\n const Bound extends {\n resource: LayoutResourceKey<Resources>;\n },\n>(\n bound: ValidateForResourceBound<Resources, Bound>,\n) => GetComponentAtBound<\n Resources,\n ResourceFromGetComponentBound<Resources, Bound>,\n SubResourceFromGetComponentBound<Bound>\n>;\n\nexport interface GetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n <const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ): JSX.Element;\n forResource: GetComponentForResource<Resources>;\n}\n\nexport interface CreatedResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n config: ResourceConfigMap<Resources>;\n getComponent: GetComponent<Resources>;\n}\n\nexport type CreateResourceConfigFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <const Config extends ResourceConfigMap<Resources>>(\n config: ResourceConfigInput<Resources, Config>,\n) => CreatedResourceConfig<Resources>;\n\ntype SubResourceParam =\n | string\n | {\n resource: string;\n subResource: SubResourceParam;\n };\n\nfunction resolveResourceConfigEntry(\n entry: ResourceConfigEntry,\n subResource: SubResourceParam,\n): ResourceConfigEntry {\n if (typeof subResource === 'string') {\n const next = entry.subResources?.[subResource];\n if (!next) {\n throw new Error(`Sub-resource \"${subResource}\" is not configured`);\n }\n return next;\n }\n\n const next = entry.subResources?.[subResource.resource];\n if (!next) {\n throw new Error(`Sub-resource \"${subResource.resource}\" is not configured`);\n }\n\n return resolveResourceConfigEntry(next, subResource.subResource);\n}\n\nfunction readResourceConfigComponent(\n entry: ResourceConfigComponents,\n componentKey: ResourceConfigComponentKey,\n): JSX.Element {\n if (componentKey === 'new' || componentKey === 'detail') {\n const branch = entry[componentKey];\n\n if (!branch?.component) {\n throw new Error(`Missing \"${componentKey}.component\" configuration`);\n }\n\n return branch.component;\n }\n\n const value = entry[componentKey];\n\n if (!value) {\n throw new Error(`Missing \"${componentKey}\" configuration`);\n }\n\n return value;\n}\n\nfunction getComponentFromOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n config: ResourceConfigMap<Resources>,\n options: GetComponentOptions<Resources>,\n): JSX.Element {\n const { resource, component: componentKey = 'component' } = options;\n const resourceEntry = config[resource];\n\n if (!resourceEntry) {\n throw new Error(`Resource \"${resource}\" is not configured`);\n }\n\n let entry: ResourceConfigEntry = resourceEntry;\n\n if ('subResource' in options && options.subResource !== undefined) {\n entry = resolveResourceConfigEntry(entry, options.subResource);\n }\n\n return readResourceConfigComponent(entry, componentKey);\n}\n\nexport function createGetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): GetComponent<Resources> {\n function getComponent<const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ) {\n return getComponentFromOptions(config, options);\n }\n\n const forResource: GetComponentForResource<Resources> = (bound) => {\n return (options) =>\n getComponentFromOptions(config, {\n ...bound,\n ...options,\n } as unknown as GetComponentOptions<Resources>);\n };\n\n return Object.assign(getComponent, { forResource });\n}\n\nexport function createResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): CreatedResourceConfig<Resources> {\n return {\n config,\n getComponent: createGetComponent(config),\n };\n}\n"],"mappings":";AAyLA,SAAS,2BACP,OACA,aACqB;CACrB,IAAI,OAAO,gBAAgB,UAAU;EACnC,MAAM,OAAO,MAAM,eAAe;EAClC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iBAAiB,YAAY,oBAAoB;EAEnE,OAAO;CACT;CAEA,MAAM,OAAO,MAAM,eAAe,YAAY;CAC9C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,iBAAiB,YAAY,SAAS,oBAAoB;CAG5E,OAAO,2BAA2B,MAAM,YAAY,WAAW;AACjE;AAEA,SAAS,4BACP,OACA,cACa;CACb,IAAI,iBAAiB,SAAS,iBAAiB,UAAU;EACvD,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,QAAQ,WACX,MAAM,IAAI,MAAM,YAAY,aAAa,0BAA0B;EAGrE,OAAO,OAAO;CAChB;CAEA,MAAM,QAAQ,MAAM;CAEpB,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,YAAY,aAAa,gBAAgB;CAG3D,OAAO;AACT;AAEA,SAAS,wBAGP,QACA,SACa;CACb,MAAM,EAAE,UAAU,WAAW,eAAe,gBAAgB;CAC5D,MAAM,gBAAgB,OAAO;CAE7B,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,aAAa,SAAS,oBAAoB;CAG5D,IAAI,QAA6B;CAEjC,IAAI,iBAAiB,WAAW,QAAQ,gBAAgB,QACtD,QAAQ,2BAA2B,OAAO,QAAQ,WAAW;CAG/D,OAAO,4BAA4B,OAAO,YAAY;AACxD;AAEA,SAAgB,mBAEd,QAA+D;CAC/D,SAAS,aACP,SACA;EACA,OAAO,wBAAwB,QAAQ,OAAO;CAChD;CAEA,MAAM,eAAmD,UAAU;EACjE,QAAQ,YACN,wBAAwB,QAAQ;GAC9B,GAAG;GACH,GAAG;EACL,CAA8C;CAClD;CAEA,OAAO,OAAO,OAAO,cAAc,EAAE,YAAY,CAAC;AACpD;AAEA,SAAgB,qBAEd,QAAwE;CACxE,OAAO;EACL;EACA,cAAc,mBAAmB,MAAM;CACzC;AACF"}
1
+ {"version":3,"file":"get-component.mjs","names":[],"sources":["../../src/create-config/get-component.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport {\n InvalidComponentError,\n InvalidConfigError,\n InvalidPathError,\n InvalidResourceError,\n InvalidSubResourceError,\n} from '../errors';\nimport type {\n LayoutResourceKey,\n ResourceDefinition,\n ResourceDefinitionForKey,\n SubResourceDefinitionsFor,\n SubResourceParamForResource,\n} from '../resource';\nimport {\n createForPaths,\n createGetComponentForPath,\n type CreateGetComponentForPath,\n type ForPaths,\n} from './for-paths';\nimport {\n createIsSubResourceKey,\n type IsSubResourceKey,\n} from './is-sub-resource-key';\nimport {\n readComponentKeys,\n readSubResourceKeys,\n} from './component-keys';\nimport {\n collectAllSubResourceKeys,\n collectConfigResources,\n} from './paths';\nimport type {\n ConfigSubResourceKeys,\n ParameterizedResourcePath,\n} from './paths';\nimport type {\n BaseResourceConfigComponents,\n ResourceConfigComponentKey,\n ResourceConfigComponents,\n ResourceConfigEntry,\n ResourceConfigMap,\n ResourceConfigInput,\n SharedResourceConfigOptions,\n} from './types';\n\ntype ResourceHasLayoutSubResources<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n> = [SubResourceDefinitionsFor<Resources, Resource>] extends [readonly []]\n ? false\n : true;\n\ntype SubResourceOptionForGenerics<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined,\n> = [SubResource] extends [undefined]\n ? ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? {\n subResource?: SubResourceParamForResource<Resources, Resource>;\n }\n : {}\n : ResourceHasLayoutSubResources<Resources, Resource> extends true\n ? { subResource?: SubResource }\n : {};\n\n/** Options for one layout resource passed to {@link GetComponent}. */\nexport type GetComponentOptionsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = SubResourceOptionForGenerics<Resources, Resource, SubResource> & {\n resource: Resource;\n /**\n * The component to get.\n *\n * @default 'component'\n */\n component?: ResourceConfigComponentKey;\n};\n\n/** Union of valid `getComponent` option shapes for each declared layout resource. */\nexport type GetComponentOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentOptionsForResource<Resources, Resource>\n : never\n : never;\n\ntype ComponentSlotPathKey = keyof BaseResourceConfigComponents;\n\n/** `detail.errorComponent`, `new.component`, … — component slots inside a shared branch. */\ntype SharedBranchPath = {\n [Branch in keyof SharedResourceConfigOptions]: `${Branch}.${ComponentSlotPathKey}`;\n}[keyof SharedResourceConfigOptions];\n\ntype NestedSubResourceDefinitions<Def extends ResourceDefinition> = Def extends {\n subResources: infer Nested extends ReadonlyArray<ResourceDefinition>;\n}\n ? Nested\n : readonly [];\n\ntype SubResourceEntryPaths<\n SubDefs extends ReadonlyArray<ResourceDefinition>,\n DepthAcc extends readonly unknown[],\n> =\n LayoutResourceKey<SubDefs> extends infer Key extends string\n ? Key extends LayoutResourceKey<SubDefs>\n ?\n | Key\n | `${Key}.${ResourceConfigEntryPath<\n NestedSubResourceDefinitions<\n ResourceDefinitionForKey<SubDefs, Key>\n >,\n readonly [...DepthAcc, unknown]\n >}`\n : never\n : never;\n\n/** Dot-separated keys below one config node: component slots and nested sub-resources. */\ntype ResourceConfigEntryPath<\n SubDefs extends ReadonlyArray<ResourceDefinition>,\n DepthAcc extends readonly unknown[] = readonly [],\n> =\n | ComponentSlotPathKey\n | SharedBranchPath\n | ([SubDefs] extends [readonly []]\n ? never\n : DepthAcc['length'] extends 6\n ? never\n : SubResourceEntryPaths<SubDefs, DepthAcc>);\n\n/**\n * Deep config paths accepted by {@link GetComponent}, e.g.\n * `'templates.deleted.expired.errorComponent'`. Sub-resource segments come from the\n * layout tree, so only declared sub-resources are allowed at each depth.\n */\nexport type ResourceConfigPath<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource extends string\n ? Resource extends LayoutResourceKey<Resources>\n ?\n | Resource\n | `${Resource}.${ResourceConfigEntryPath<\n SubResourceDefinitionsFor<Resources, Resource>\n >}`\n : never\n : never;\n\n/** `subResource` bound by {@link GetComponentForResource}. */\nexport type SubResourceFromGetComponentBound<Bound> = Bound extends {\n subResource: infer SubResource;\n}\n ? SubResource\n : undefined;\n\n/** Options for {@link GetComponentForResource} — binds `resource` and optional `subResource`. */\nexport type GetComponentForResourceOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = {\n resource: Resource;\n} & SubResourceOptionForGenerics<Resources, Resource, SubResource>;\n\n/** Valid bind shapes for {@link GetComponentForResource}. */\nexport type GetComponentForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> =\n LayoutResourceKey<Resources> extends infer Resource\n ? Resource extends LayoutResourceKey<Resources>\n ? GetComponentForResourceOptions<Resources, Resource>\n : never\n : never;\n\ntype GetComponentForResourceOptionsForBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = GetComponentForResourceOptions<\n Resources,\n Bound['resource'],\n SubResourceFromGetComponentBound<Bound>\n>;\n\n/**\n * Rejects bind objects with keys (e.g. `subResource`) that are invalid for the\n * given `resource`. Union assignability alone is too permissive for excess keys.\n */\nexport type ValidateForResourceBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound extends { resource: LayoutResourceKey<Resources> },\n> = Bound extends GetComponentForResourceOptionsForBound<Resources, Bound>\n ? keyof Bound extends keyof GetComponentForResourceOptionsForBound<\n Resources,\n Bound\n >\n ? Bound\n : never\n : never;\n\n/** `resource` inferred from a {@link GetComponentForResource} bind argument. */\nexport type ResourceFromGetComponentBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Bound,\n> = Bound extends {\n resource: infer Resource extends LayoutResourceKey<Resources>;\n}\n ? Resource\n : never;\n\n/** Reusable getter returned by {@link GetComponentForResource} (only `component` remains). */\nexport type GetComponentAtBound<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Resource extends LayoutResourceKey<Resources>,\n SubResource extends\n | SubResourceParamForResource<Resources, Resource>\n | undefined = undefined,\n> = (\n options?: Pick<\n GetComponentOptionsForResource<Resources, Resource, SubResource>,\n 'component'\n >,\n) => JSX.Element;\n\nexport type GetComponentForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <\n const Bound extends {\n resource: LayoutResourceKey<Resources>;\n },\n>(\n bound: ValidateForResourceBound<Resources, Bound>,\n) => GetComponentAtBound<\n Resources,\n ResourceFromGetComponentBound<Resources, Bound>,\n SubResourceFromGetComponentBound<Bound>\n>;\n\nexport interface GetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> {\n /** Looks up a component by resource / optional sub-resource / optional component slot. */\n <const Options extends GetComponentOptions<Resources>>(\n options: Options,\n ): JSX.Element;\n /**\n * Looks up a component by a deep config path.\n * A path ending on a branch (e.g. `'templates.deleted.expired'`) returns that branch's\n * `component`; a path ending on a slot returns that slot.\n */\n <const Path extends ResourceConfigPath<Resources>>(path: Path): JSX.Element;\n forResource: GetComponentForResource<Resources>;\n}\n\nexport interface CreatedResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends ResourceConfigMap<Resources> = ResourceConfigMap<Resources>,\n> {\n config: Config;\n getComponent: GetComponent<Resources>;\n /**\n * Creates a reusable getter bound to one path. Variables the path leaves open become\n * the getter's arguments.\n *\n * @example\n * ```ts\n * const getDetail = createGetComponent('$resource.detail.$component');\n *\n * getDetail({ resource: 'templates', component: 'errorComponent' });\n * ```\n */\n createGetComponent: CreateGetComponentForPath<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /**\n * Builds a component for one or more paths. Declare which params the component takes,\n * then render it.\n *\n * @example\n * ```ts\n * const ResourceDetail = forPaths('$resource.detail.$component')\n * .addPathParams()\n * .render(({ params, getComponentForPath }) =>\n * getComponentForPath('$resource.detail.$component')(params),\n * );\n * ```\n */\n forPaths: ForPaths<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /** Narrows an unknown value to a sub-resource key configured for a path or resource. */\n isSubResourceKey: IsSubResourceKey<\n Resources,\n Config,\n ParameterizedResourcePath<Resources>\n >;\n /** Every sub-resource key configured in this config, at any depth. */\n subResources: ReadonlyArray<ConfigSubResourceKeys<Resources, Config>>;\n}\n\ntype ComponentTypesFromEntry<Entry> = Entry extends JSX.Element\n ? never\n : Entry extends object\n ?\n | Extract<keyof Entry, ResourceConfigComponentKey>\n | {\n [Key in keyof Entry]: NonNullable<Entry[Key]> extends JSX.Element\n ? never\n : ComponentTypesFromEntry<NonNullable<Entry[Key]>>;\n }[keyof Entry]\n : never;\n\n/**\n * Component selector keys actually defined anywhere in a created resource config.\n *\n * @example\n * ```ts\n * ComponentTypes<typeof resourceConfig>\n * // ^? may resolve to:`'component' | 'errorComponent' | 'detail'`.\n * ```\n */\nexport type ComponentTypes<Created> = Created extends {\n config: infer Config extends object;\n}\n ? {\n [Resource in keyof Config]: ComponentTypesFromEntry<\n NonNullable<Config[Resource]>\n >;\n }[keyof Config]\n : never;\n\nexport type CreateResourceConfigFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = <const Config extends ResourceConfigMap<Resources>>(\n config: ResourceConfigInput<Resources, Config>,\n) => CreatedResourceConfig<Resources, Config>;\n\ntype SubResourceParam =\n | string\n | {\n value: string;\n subResource: SubResourceParam;\n };\n\nfunction isResourceConfigEntry(value: unknown): value is ResourceConfigEntry {\n return typeof value === 'object' && value !== null;\n}\n\nfunction resolveResourceConfigEntry(\n entry: ResourceConfigEntry,\n subResource: SubResourceParam,\n): ResourceConfigEntry {\n const key = typeof subResource === 'string' ? subResource : subResource.value;\n const next = entry[key];\n\n if (!isResourceConfigEntry(next)) {\n throw new InvalidSubResourceError({\n subResource: key,\n validSubResources: readSubResourceKeys(entry),\n });\n }\n\n if (typeof subResource === 'string') {\n return next;\n }\n\n return resolveResourceConfigEntry(next, subResource.subResource);\n}\n\nfunction readResourceConfigComponent(\n entry: ResourceConfigComponents,\n componentKey: ResourceConfigComponentKey,\n): JSX.Element {\n if (componentKey === 'new' || componentKey === 'detail') {\n const branch = entry[componentKey];\n\n if (!branch?.component) {\n throw new InvalidComponentError({\n component: `${componentKey}.component`,\n validComponents: readComponentKeys(entry),\n });\n }\n\n return branch.component;\n }\n\n const value = entry[componentKey];\n\n if (!value) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: readComponentKeys(entry),\n });\n }\n\n return value;\n}\n\nfunction getComponentFromOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n config: ResourceConfigMap<Resources>,\n options: GetComponentOptions<Resources>,\n): JSX.Element {\n const { resource, component: componentKey = 'component' } = options;\n const resourceEntry = config[resource];\n\n if (!resourceEntry) {\n throw new InvalidResourceError({\n resource,\n validResources: collectConfigResources(config as Record<string, unknown>),\n });\n }\n\n let entry = resourceEntry as ResourceConfigEntry;\n\n if ('subResource' in options && options.subResource !== undefined) {\n entry = resolveResourceConfigEntry(entry, options.subResource);\n }\n\n return readResourceConfigComponent(entry, componentKey);\n}\n\nfunction getComponentFromPath<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>, path: string): JSX.Element {\n let cursor: unknown = config;\n\n for (const segment of path.split('.')) {\n if (!isResourceConfigEntry(cursor)) {\n throw new InvalidPathError({\n path,\n reason: `\"${segment}\" cannot be read because the value before it is not a config branch`,\n });\n }\n\n const next: unknown = (cursor as Record<string, unknown>)[segment];\n\n if (next === undefined || next === null) {\n throw new InvalidPathError({\n path,\n reason: `\"${segment}\" is not configured`,\n });\n }\n\n cursor = next;\n }\n\n if (isResourceConfigEntry(cursor) && 'component' in cursor) {\n return readResourceConfigComponent(cursor, 'component');\n }\n\n return cursor as JSX.Element;\n}\n\nexport function createGetComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(config: ResourceConfigMap<Resources>): GetComponent<Resources> {\n function getComponent(options: GetComponentOptions<Resources>): JSX.Element;\n function getComponent(path: ResourceConfigPath<Resources>): JSX.Element;\n function getComponent(\n options: GetComponentOptions<Resources> | ResourceConfigPath<Resources>,\n ): JSX.Element {\n if (typeof options === 'string') {\n return getComponentFromPath(config, options);\n }\n\n return getComponentFromOptions(config, options);\n }\n\n const forResource: GetComponentForResource<Resources> = (bound) => {\n return (options) =>\n getComponentFromOptions(config, {\n ...bound,\n ...options,\n } as unknown as GetComponentOptions<Resources>);\n };\n\n return Object.assign(getComponent, { forResource });\n}\n\nexport function createResourceConfig<\n Resources extends ReadonlyArray<ResourceDefinition>,\n const Config extends ResourceConfigMap<Resources>,\n>(\n config: ResourceConfigInput<Resources, Config>,\n): CreatedResourceConfig<Resources, Config> {\n const configRecord = config as Record<string, unknown>;\n\n if (collectConfigResources(configRecord).length === 0) {\n throw new InvalidConfigError({\n reason: 'A resource config must configure at least one resource',\n config,\n });\n }\n\n type Created = CreatedResourceConfig<Resources, Config>;\n\n return {\n config,\n getComponent: createGetComponent(config),\n createGetComponent: ((path: string) =>\n createGetComponentForPath(\n configRecord,\n path,\n )) as unknown as Created['createGetComponent'],\n forPaths: createForPaths(configRecord) as unknown as Created['forPaths'],\n isSubResourceKey: createIsSubResourceKey(\n configRecord,\n ) as unknown as Created['isSubResourceKey'],\n subResources: collectAllSubResourceKeys(\n configRecord,\n ) as unknown as Created['subResources'],\n };\n}\n"],"mappings":";;;;;;;;;;;;AAuWA,SAAS,sBAAsB,OAA8C;CAC3E,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,2BACP,OACA,aACqB;CACrB,MAAM,MAAM,OAAO,gBAAgB,WAAW,cAAc,YAAY;CACxE,MAAM,OAAO,MAAM;CAEnB,IAAI,CAAC,sBAAsB,IAAI,GAC7B,MAAM,IAAI,wBAAwB;EAChC,aAAa;EACb,mBAAmB,oBAAoB,KAAK;CAC9C,CAAC;CAGH,IAAI,OAAO,gBAAgB,UACzB,OAAO;CAGT,OAAO,2BAA2B,MAAM,YAAY,WAAW;AACjE;AAEA,SAAS,4BACP,OACA,cACa;CACb,IAAI,iBAAiB,SAAS,iBAAiB,UAAU;EACvD,MAAM,SAAS,MAAM;EAErB,IAAI,CAAC,QAAQ,WACX,MAAM,IAAI,sBAAsB;GAC9B,WAAW,GAAG,aAAa;GAC3B,iBAAiB,kBAAkB,KAAK;EAC1C,CAAC;EAGH,OAAO,OAAO;CAChB;CAEA,MAAM,QAAQ,MAAM;CAEpB,IAAI,CAAC,OACH,MAAM,IAAI,sBAAsB;EAC9B,WAAW;EACX,iBAAiB,kBAAkB,KAAK;CAC1C,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,wBAGP,QACA,SACa;CACb,MAAM,EAAE,UAAU,WAAW,eAAe,gBAAgB;CAC5D,MAAM,gBAAgB,OAAO;CAE7B,IAAI,CAAC,eACH,MAAM,IAAI,qBAAqB;EAC7B;EACA,gBAAgB,uBAAuB,MAAiC;CAC1E,CAAC;CAGH,IAAI,QAAQ;CAEZ,IAAI,iBAAiB,WAAW,QAAQ,gBAAgB,QACtD,QAAQ,2BAA2B,OAAO,QAAQ,WAAW;CAG/D,OAAO,4BAA4B,OAAO,YAAY;AACxD;AAEA,SAAS,qBAEP,QAAsC,MAA2B;CACjE,IAAI,SAAkB;CAEtB,KAAK,MAAM,WAAW,KAAK,MAAM,GAAG,GAAG;EACrC,IAAI,CAAC,sBAAsB,MAAM,GAC/B,MAAM,IAAI,iBAAiB;GACzB;GACA,QAAQ,IAAI,QAAQ;EACtB,CAAC;EAGH,MAAM,OAAiB,OAAmC;EAE1D,IAAI,SAAS,UAAa,SAAS,MACjC,MAAM,IAAI,iBAAiB;GACzB;GACA,QAAQ,IAAI,QAAQ;EACtB,CAAC;EAGH,SAAS;CACX;CAEA,IAAI,sBAAsB,MAAM,KAAK,eAAe,QAClD,OAAO,4BAA4B,QAAQ,WAAW;CAGxD,OAAO;AACT;AAEA,SAAgB,mBAEd,QAA+D;CAG/D,SAAS,aACP,SACa;EACb,IAAI,OAAO,YAAY,UACrB,OAAO,qBAAqB,QAAQ,OAAO;EAG7C,OAAO,wBAAwB,QAAQ,OAAO;CAChD;CAEA,MAAM,eAAmD,UAAU;EACjE,QAAQ,YACN,wBAAwB,QAAQ;GAC9B,GAAG;GACH,GAAG;EACL,CAA8C;CAClD;CAEA,OAAO,OAAO,OAAO,cAAc,EAAE,YAAY,CAAC;AACpD;AAEA,SAAgB,qBAId,QAC0C;CAC1C,MAAM,eAAe;CAErB,IAAI,uBAAuB,YAAY,EAAE,WAAW,GAClD,MAAM,IAAI,mBAAmB;EAC3B,QAAQ;EACR;CACF,CAAC;CAKH,OAAO;EACL;EACA,cAAc,mBAAmB,MAAM;EACvC,sBAAsB,SACpB,0BACE,cACA,IACF;EACF,UAAU,eAAe,YAAY;EACrC,kBAAkB,uBAChB,YACF;EACA,cAAc,0BACZ,YACF;CACF;AACF"}
@@ -1,4 +1,9 @@
1
1
  import { BaseResourceConfigComponents, ResourceConfig, ResourceConfigComponentKey, ResourceConfigComponents, ResourceConfigInput, ResourceConfigMap, SharedResourceConfigOptions, SubResourceConfig, SubResourceConfigComponentsFor } from "./types.cjs";
2
- import { CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound } from "./get-component.cjs";
2
+ import { ComponentPathVariable, ExtractPathVariables, PATH_VARIABLE_IDENTIFIER, PathHasVariables, PathVariable, ResourcePathVariable, SubResourcePathVariable } from "./paths/variables.cjs";
3
+ import { ConfigResourceKeys, ConfigSubResourceKeys, ParameterizedEntryPath, ParameterizedResourcePath, PathComponentKeys, PathResourceCandidates, PathSubResourceKeys, PathVariables, PathVariablesForResource, ResolveParameterizedPathValue, ResourceSubResourceKeys } from "./paths/types.cjs";
4
+ import { CreateGetComponentForPath, GetComponentForPath, GetComponentForPathApi, PathValueComponentGetter, PathVariableGuards, ResolvedPathValue } from "./for-paths/get-component-for-path.cjs";
5
+ import { ForPaths, ForPathsRenderContext, RenderedPathComponent, RenderedPathComponentHOF, TargetPathBuilder } from "./for-paths/builder.cjs";
6
+ import { IsSubResourceKey, IsSubResourceKeyOptions, IsSubResourceKeyResult } from "./is-sub-resource-key.cjs";
7
+ import { ComponentTypes, CreateResourceConfigFn, CreatedResourceConfig, GetComponent, GetComponentAtBound, GetComponentForResource, GetComponentForResourceOptions, GetComponentOptions, GetComponentOptionsForResource, ResourceConfigPath, ResourceFromGetComponentBound, SubResourceFromGetComponentBound, ValidateForResourceBound } from "./get-component.cjs";
3
8
  import { CreateResourceLinkConfig, CreateResourceLinkGroupInput, CreateResourceLinkGroupOptions, CreateResourceLinkOptions, CreateResourceLinksFn, CreateResourceLinksWithGroups, CreateResourceLinksWithGroupsFn, CreatedResourceHref, CreatedResourceLink, CreatedResourceLinkBase, InferHashFromResourceLinkHref, ResourceAnchorLinkFn, ResourceLinkHref } from "./create-resource-links.cjs";
4
9
  import { CreateResourceLayoutFn, CreateResourceLayoutMakeComposableOptions, DefineResourceLayout, DefineResourceLayoutFn, DefineResourceLayoutForResources, DefineResourceLayoutForResourcesFactory, defineResourceLayout } from "./define-layout.cjs";