@streamline-pulse/formkrafter-core 0.15.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@ The framework-agnostic heart of FormKrafter: form **specs**, immutable **mutatio
4
4
 
5
5
  ## The spec
6
6
 
7
- A form is a tree of `BrickSpec` nodes. Each brick has a `type` (`input`, `panel`, `collection`, `output`, `action`), an `id` (which registered brick renders it), `configs` (with a unique `uid` and a data `key`), plus optional `validations`, `rules`, `styles`, and `children`.
7
+ A form is a tree of `BrickSpec` nodes. Each brick has a `type` (`input`, `panel`, `collection`, `output`, `action`), an `id` (which registered brick renders it), `configs` (with a data `key`), plus optional `validations`, `rules`, `styles`, and `children`.
8
8
 
9
9
  ```mermaid
10
10
  flowchart TD
@@ -40,7 +40,7 @@ flowchart LR
40
40
  H -->|redo → apply patches| S1[spec']
41
41
  ```
42
42
 
43
- Available ops: `addBrick`, `removeBrick`, `moveBrick`, `duplicateBrick` (fresh uids), `updateBrickConfigs`, `updateBrickStyles`, `updateBrickValidations`, `updateBrickRules`. Addressing helpers: `getBrickAt(spec, path)`, `pointerOfUid(spec, uid)`, `iterateBricks(spec)`.
43
+ Available ops: `addBrick`, `removeBrick`, `moveBrick`, `duplicateBrick`, `updateBrickConfigs`, `updateBrickStyles`, `updateBrickValidations`, `updateBrickRules`. Addressing helpers: `getBrickAt(spec, path)`, `pointerFromPath(path)`, `iterateBricks(spec)`.
44
44
 
45
45
  Patches are plain RFC 6902 — persist them, sync them, audit them.
46
46
 
@@ -8,8 +8,8 @@ import type { BrickType } from "../utils/brick-type";
8
8
  import type { BrickBaseConfigs, CommonBrickProps } from "../utils/common-brick-props";
9
9
  import type { BrickMoldDropType } from "../utils/drop-type";
10
10
  export interface BrickProps<DataType, Configs extends BrickBaseConfigs, Styles> extends CommonBrickProps<Configs, Styles> {
11
- onConfigsChange?: (configs: BrickBaseConfigs & Record<string, unknown>, uid?: string) => void;
12
- onStylesChange?: (styles: Record<string, unknown>, uid?: string) => void;
11
+ onConfigsChange?: (configs: BrickBaseConfigs & Record<string, unknown>, path?: string) => void;
12
+ onStylesChange?: (styles: Record<string, unknown>, path?: string) => void;
13
13
  data?: DataType;
14
14
  dataMap?: Record<string, unknown>;
15
15
  rootSpec?: BrickSpec;
@@ -26,9 +26,9 @@ export interface BrickProps<DataType, Configs extends BrickBaseConfigs, Styles>
26
26
  brickSpec?: BrickSpec;
27
27
  editable?: boolean;
28
28
  validations?: Validation[];
29
- onValidationsChange?: (validations: Validation[], uid?: string) => void;
29
+ onValidationsChange?: (validations: Validation[], path?: string) => void;
30
30
  rules?: Rule[];
31
- onRulesChange?: (rules: Rule[], uid?: string) => void;
31
+ onRulesChange?: (rules: Rule[], path?: string) => void;
32
32
  utils: Utils;
33
33
  }
34
34
  export declare abstract class Brick<DataType, Configs extends BrickBaseConfigs, Styles extends Record<string, unknown>> {
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ export { DataSourceService, FetchDataSourceService } from "./services/data_sourc
27
27
  export { FileLike, UploadedFile, FileUploadService, FileUploadOptions, Base64FileUploadService, UrlFileUploadService, UrlFileUploadDefaults } from "./services/file_upload_service";
28
28
  export { LocalizedText, isLocalizedObject, resolveLocalizedText, resolveLocalizedRecord } from "./utils/localized-text";
29
29
  export { FkTranslations, setFkTranslations, fkT, fkTOr, frFkTranslations } from "./i18n";
30
- export { pointerFromPath, pointerOfUid, getBrickAt } from "./ops/pointer";
30
+ export { pointerFromPath, getBrickAt } from "./ops/pointer";
31
31
  export { SpecUpdate, addBrick, removeBrick, moveBrick, duplicateBrick, updateBrickConfigs, updateBrickStyles, updateBrickValidations, updateBrickRules } from "./ops/ops";
32
32
  export { SpecHistory } from "./ops/history";
33
33
  export type { Operation } from "fast-json-patch";
package/dist/index.js CHANGED
@@ -7125,6 +7125,7 @@ var en = {
7125
7125
  "panel.content": "Content",
7126
7126
  "panel.dataKey": "Data key",
7127
7127
  "panel.url": "URL",
7128
+ "panel.responsePath": "Response path (optional)",
7128
7129
  "panel.headers": "Headers ({token} reads form data)",
7129
7130
  "panel.searchParam": "Server search param",
7130
7131
  "panel.labelKey": "Label key",
@@ -7259,6 +7260,7 @@ var frFkTranslations = {
7259
7260
  "panel.content": "Contenu",
7260
7261
  "panel.dataKey": "Clé de données",
7261
7262
  "panel.url": "URL",
7263
+ "panel.responsePath": "Chemin dans la réponse (optionnel)",
7262
7264
  "panel.headers": "En-têtes ({token} lit les données du formulaire)",
7263
7265
  "panel.searchParam": "Paramètre de recherche serveur",
7264
7266
  "panel.labelKey": "Clé du libellé",
@@ -7710,7 +7712,68 @@ class SandboxJsRunnerService {
7710
7712
  }
7711
7713
  }
7712
7714
 
7715
+ // lib/utils/remote.ts
7716
+ function resolvePath(source, path) {
7717
+ if (Object.prototype.hasOwnProperty.call(source, path))
7718
+ return source[path];
7719
+ let current = source;
7720
+ for (const segment of path.split(".")) {
7721
+ if (current === null || typeof current !== "object")
7722
+ return;
7723
+ if (!Object.prototype.hasOwnProperty.call(current, segment))
7724
+ return;
7725
+ current = current[segment];
7726
+ }
7727
+ return current;
7728
+ }
7729
+ function interpolateTemplate(template, dataMap) {
7730
+ return template.replace(/\{([\w.]+)\}/g, (_, token) => {
7731
+ const value = dataMap && resolvePath(dataMap, token);
7732
+ return value === undefined || value === null ? "" : String(value);
7733
+ });
7734
+ }
7735
+ function parseHeaderLines(raw, dataMap) {
7736
+ if (typeof raw !== "string" || !raw.trim())
7737
+ return;
7738
+ const headers = {};
7739
+ for (const line of raw.split(`
7740
+ `)) {
7741
+ const separator = line.indexOf(":");
7742
+ if (separator <= 0)
7743
+ continue;
7744
+ const name = line.slice(0, separator).trim();
7745
+ const value = interpolateTemplate(line.slice(separator + 1).trim(), dataMap);
7746
+ if (name)
7747
+ headers[name] = value;
7748
+ }
7749
+ return Object.keys(headers).length ? headers : undefined;
7750
+ }
7751
+ function appendSearchParam(url, param, term) {
7752
+ if (!term)
7753
+ return url;
7754
+ const separator = url.includes("?") ? "&" : "?";
7755
+ return `${url}${separator}${encodeURIComponent(param)}=${encodeURIComponent(term)}`;
7756
+ }
7757
+
7713
7758
  // lib/services/data_source_service.ts
7759
+ function optionsFromPayload(json, url, path) {
7760
+ if (path) {
7761
+ const picked = json !== null && typeof json === "object" ? resolvePath(json, path) : undefined;
7762
+ if (!Array.isArray(picked)) {
7763
+ throw new Error(`Data source has no array at "${path}": ${url}`);
7764
+ }
7765
+ return picked;
7766
+ }
7767
+ if (Array.isArray(json))
7768
+ return json;
7769
+ if (json !== null && typeof json === "object") {
7770
+ const envelope = json.data;
7771
+ if (Array.isArray(envelope))
7772
+ return envelope;
7773
+ }
7774
+ throw new Error(`Data source did not return an array: ${url}`);
7775
+ }
7776
+
7714
7777
  class FetchDataSourceService {
7715
7778
  defaults;
7716
7779
  cache = new Map;
@@ -7724,7 +7787,7 @@ class FetchDataSourceService {
7724
7787
  init.headers = headers;
7725
7788
  if (this.defaults.credentials)
7726
7789
  init.credentials = this.defaults.credentials;
7727
- const key = `${url}|${JSON.stringify(init)}`;
7790
+ const key = `${url}|${JSON.stringify(init)}|${options?.path ?? ""}`;
7728
7791
  let pending = this.cache.get(key);
7729
7792
  if (!pending) {
7730
7793
  pending = fetch(url, Object.keys(init).length ? init : undefined).then((response) => {
@@ -7732,12 +7795,7 @@ class FetchDataSourceService {
7732
7795
  throw new Error(`Data source request failed (${response.status}): ${url}`);
7733
7796
  }
7734
7797
  return response.json();
7735
- }).then((json) => {
7736
- if (!Array.isArray(json)) {
7737
- throw new Error(`Data source did not return an array: ${url}`);
7738
- }
7739
- return json;
7740
- }).catch((error) => {
7798
+ }).then((json) => optionsFromPayload(json, url, options?.path)).catch((error) => {
7741
7799
  this.cache.delete(key);
7742
7800
  throw error;
7743
7801
  });
@@ -8148,35 +8206,6 @@ function stripUidsFromPatches(patches) {
8148
8206
  value: stripPatchValue(patch.value, patch.path)
8149
8207
  } : patch);
8150
8208
  }
8151
- // lib/utils/remote.ts
8152
- function interpolateTemplate(template, dataMap) {
8153
- return template.replace(/\{(\w+)\}/g, (_, token) => {
8154
- const value = dataMap?.[token];
8155
- return value === undefined || value === null ? "" : String(value);
8156
- });
8157
- }
8158
- function parseHeaderLines(raw, dataMap) {
8159
- if (typeof raw !== "string" || !raw.trim())
8160
- return;
8161
- const headers = {};
8162
- for (const line of raw.split(`
8163
- `)) {
8164
- const separator = line.indexOf(":");
8165
- if (separator <= 0)
8166
- continue;
8167
- const name = line.slice(0, separator).trim();
8168
- const value = interpolateTemplate(line.slice(separator + 1).trim(), dataMap);
8169
- if (name)
8170
- headers[name] = value;
8171
- }
8172
- return Object.keys(headers).length ? headers : undefined;
8173
- }
8174
- function appendSearchParam(url, param, term) {
8175
- if (!term)
8176
- return url;
8177
- const separator = url.includes("?") ? "&" : "?";
8178
- return `${url}${separator}${encodeURIComponent(param)}=${encodeURIComponent(term)}`;
8179
- }
8180
8209
  // lib/brick/brick.ts
8181
8210
  class Brick {
8182
8211
  type;
@@ -8414,19 +8443,14 @@ ${js}})();`;
8414
8443
  function pointerFromPath(path) {
8415
8444
  return path.split(".").slice(1).map((segment) => `/children/${segment}`).join("");
8416
8445
  }
8417
- function pointerOfUid(spec, uid) {
8418
- if (spec.configs?.uid === uid)
8419
- return "";
8420
- for (const [index, child] of (spec.children ?? []).entries()) {
8421
- const childPointer = pointerOfUid(child, uid);
8422
- if (childPointer !== undefined)
8423
- return `/children/${index}${childPointer}`;
8424
- }
8425
- return;
8426
- }
8427
8446
  function getBrickAt(spec, path) {
8447
+ const [root, ...segments] = path.split(".");
8448
+ if (root !== "0")
8449
+ return;
8428
8450
  let current = spec;
8429
- for (const segment of path.split(".").slice(1)) {
8451
+ for (const segment of segments) {
8452
+ if (!/^\d+$/.test(segment))
8453
+ return;
8430
8454
  current = current?.children?.[Number(segment)];
8431
8455
  }
8432
8456
  return current;
@@ -8448,16 +8472,10 @@ var requireBrickAt = (spec, path) => {
8448
8472
  throw new Error(`No brick at path "${path}"`);
8449
8473
  return brick;
8450
8474
  };
8451
- var requireBrickByUid = (spec, uid) => {
8452
- const pointer = pointerOfUid(spec, uid);
8453
- if (pointer === undefined)
8454
- throw new Error(`No brick with uid "${uid}"`);
8455
- let brick = spec;
8456
- for (const segment of pointer.split("/children/").slice(1)) {
8457
- brick = brick.children[Number(segment)];
8458
- }
8459
- return { pointer, brick };
8460
- };
8475
+ var requireBrickForUpdate = (spec, path) => ({
8476
+ pointer: pointerFromPath(path),
8477
+ brick: requireBrickAt(spec, path)
8478
+ });
8461
8479
  var toJsonValue = (value) => JSON.parse(JSON.stringify(value));
8462
8480
  function addBrick(spec, brick, parentPath, index) {
8463
8481
  const parent = requireBrickAt(spec, parentPath);
@@ -8527,22 +8545,22 @@ var setBrickSection = (spec, brickPointer, section, value, previous) => {
8527
8545
  }
8528
8546
  return apply(spec, [{ op: "replace", path: pointer, value }], [{ op: "replace", path: pointer, value: previous }]);
8529
8547
  };
8530
- function updateBrickConfigs(spec, uid, configs) {
8531
- const { pointer, brick } = requireBrickByUid(spec, uid);
8548
+ function updateBrickConfigs(spec, path, configs) {
8549
+ const { pointer, brick } = requireBrickForUpdate(spec, path);
8532
8550
  const merged = { ...brick.configs, ...configs };
8533
8551
  return setBrickSection(spec, pointer, "configs", merged, brick.configs);
8534
8552
  }
8535
- function updateBrickStyles(spec, uid, styles) {
8536
- const { pointer, brick } = requireBrickByUid(spec, uid);
8553
+ function updateBrickStyles(spec, path, styles) {
8554
+ const { pointer, brick } = requireBrickForUpdate(spec, path);
8537
8555
  const merged = { ...brick.styles, ...styles };
8538
8556
  return setBrickSection(spec, pointer, "styles", merged, brick.styles);
8539
8557
  }
8540
- function updateBrickValidations(spec, uid, validations) {
8541
- const { pointer, brick } = requireBrickByUid(spec, uid);
8558
+ function updateBrickValidations(spec, path, validations) {
8559
+ const { pointer, brick } = requireBrickForUpdate(spec, path);
8542
8560
  return setBrickSection(spec, pointer, "validations", validations, brick.validations);
8543
8561
  }
8544
- function updateBrickRules(spec, uid, rules) {
8545
- const { pointer, brick } = requireBrickByUid(spec, uid);
8562
+ function updateBrickRules(spec, path, rules) {
8563
+ const { pointer, brick } = requireBrickForUpdate(spec, path);
8546
8564
  return setBrickSection(spec, pointer, "rules", rules, brick.rules);
8547
8565
  }
8548
8566
  // lib/ops/history.ts
@@ -9181,7 +9199,6 @@ export {
9181
9199
  resolveLocalizedRecord,
9182
9200
  removeBrick,
9183
9201
  registerValidationMessages,
9184
- pointerOfUid,
9185
9202
  pointerFromPath,
9186
9203
  parseHeaderLines,
9187
9204
  normalizeOptions,
@@ -9219,5 +9236,5 @@ export {
9219
9236
  Base64FileUploadService
9220
9237
  };
9221
9238
 
9222
- //# debugId=F8E3FDC2C406A49364756E2164756E21
9239
+ //# debugId=7CC5CCE3A23FDF4A64756E2164756E21
9223
9240
  //# sourceMappingURL=index.js.map