pte-interpolation-core 1.1.1 → 1.2.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 @@
4
4
 
5
5
  ![Demo](https://raw.githubusercontent.com/jordanl17/sanity-pte-interpolation/main/.github/assets/demo.png)
6
6
 
7
- Framework-agnostic utilities for [Portable Text](https://portabletext.org/) variable interpolation. Extract variable keys from PTE blocks and resolve them to plain strings - with zero dependencies.
7
+ Framework-agnostic utilities for [Portable Text](https://portabletext.org/) variable interpolation. Extract variable keys from PTE blocks and resolve them to plain strings - with zero dependencies. Use this package when you need plain string output without a React dependency: email templates, PDF generation, Node.js scripts, SMS or push notifications, or any non-React framework (Vue, Svelte, Angular, etc.). For React rendering with rich text output, use [`pte-interpolation-react`](https://www.npmjs.com/package/pte-interpolation-react) instead - it re-exports everything from this package.
8
8
 
9
9
  Part of [sanity-pte-interpolation](https://github.com/jordanl17/sanity-pte-interpolation). For adding variable picker inline blocks to Sanity Studio, see [`sanity-plugin-pte-interpolation`](https://www.npmjs.com/package/sanity-plugin-pte-interpolation). For React rendering with rich text output, see [`pte-interpolation-react`](https://www.npmjs.com/package/pte-interpolation-react).
10
10
 
@@ -16,18 +16,6 @@ npm install pte-interpolation-core
16
16
 
17
17
  No peer dependencies required.
18
18
 
19
- ## When to Use
20
-
21
- Use this package when you need plain string output from interpolated Portable Text - without a React dependency. Common use cases include:
22
-
23
- - Email templates (server-side rendering)
24
- - PDF generation
25
- - Node.js scripts and background jobs
26
- - SMS or push notification text
27
- - Any non-React framework (Vue, Svelte, Angular, etc.)
28
-
29
- If you are rendering in React and want rich text output, use [`pte-interpolation-react`](https://www.npmjs.com/package/pte-interpolation-react) instead - it re-exports everything from this package, so you get both APIs without installing core separately.
30
-
31
19
  ## Usage
32
20
 
33
21
  ### Extract variable keys
@@ -38,7 +26,7 @@ If you are rendering in React and want rich text output, use [`pte-interpolation
38
26
  import {extractVariableKeys} from 'pte-interpolation-core'
39
27
 
40
28
  const keys = extractVariableKeys(blocks)
41
- // ['firstName', 'email']
29
+ // ['firstName', 'vouchersRemaining']
42
30
  ```
43
31
 
44
32
  ### Interpolate to a plain string
@@ -49,10 +37,10 @@ const keys = extractVariableKeys(blocks)
49
37
  import {interpolateToString} from 'pte-interpolation-core'
50
38
 
51
39
  const text = interpolateToString(blocks, {
52
- firstName: 'Alice',
53
- email: 'alice@example.com',
40
+ firstName: 'Sarah',
41
+ vouchersRemaining: '3',
54
42
  })
55
- // "Hello, Alice! Your email is alice@example.com."
43
+ // "Hi, Sarah! You have 3 vouchers remaining."
56
44
  ```
57
45
 
58
46
  ### Custom fallback for missing values
@@ -61,23 +49,37 @@ By default, unresolved variables render as `{variableKey}` (e.g. `{firstName}`).
61
49
 
62
50
  ```ts
63
51
  const text = interpolateToString(blocks, {}, (variableKey) => `[${variableKey}]`)
64
- // "Hello, [firstName]! Your email is [email]."
52
+ // "Hi, [firstName]! You have [vouchersRemaining] vouchers remaining."
65
53
  ```
66
54
 
67
- ## Authoring Variables in Sanity Studio
55
+ ### Detect missing variables
56
+
57
+ `getMissingVariableKeys` returns the variable keys present in PTE content but absent from the provided values map - useful for validating before sending emails, notifications, or other interpolated content:
58
+
59
+ ```ts
60
+ import {getMissingVariableKeys} from 'pte-interpolation-core'
61
+
62
+ const missing = getMissingVariableKeys(blocks, {firstName: 'Sarah'})
63
+ // ['vouchersRemaining']
64
+ ```
65
+
66
+ ## Related Packages
68
67
 
69
68
  This package handles **resolution** of variable blocks that already exist in Portable Text. To add the variable picker to Sanity Studio's Portable Text Editor, use [`sanity-plugin-pte-interpolation`](https://www.npmjs.com/package/sanity-plugin-pte-interpolation):
70
69
 
71
70
  ```ts
71
+ import {defineField} from 'sanity'
72
72
  import {interpolationVariables} from 'sanity-plugin-pte-interpolation'
73
73
 
74
74
  defineField({
75
- name: 'body',
75
+ name: 'message',
76
76
  type: 'array',
77
77
  of: [
78
78
  interpolationVariables([
79
79
  {id: 'firstName', name: 'First name'},
80
- {id: 'email', name: 'Email address'},
80
+ {id: 'vouchersRemaining', name: 'Vouchers remaining'},
81
+ {id: 'totalVouchers', name: 'Total vouchers'},
82
+ {id: 'expiryDate', name: 'Expiry date'},
81
83
  ]),
82
84
  ],
83
85
  })
@@ -91,9 +93,9 @@ Variable blocks in stored Portable Text look like this:
91
93
  {
92
94
  "_type": "block",
93
95
  "children": [
94
- {"_type": "span", "text": "Hello, "},
96
+ {"_type": "span", "text": "Hi, "},
95
97
  {"_type": "pteInterpolationVariable", "variableKey": "firstName"},
96
- {"_type": "span", "text": "!"}
98
+ {"_type": "span", "text": ","}
97
99
  ]
98
100
  }
99
101
  ```
@@ -112,6 +114,17 @@ Returns the unique variable keys from an array of PTE blocks, in first-occurrenc
112
114
 
113
115
  Returns `string[]`.
114
116
 
117
+ ### `getMissingVariableKeys(blocks, values)`
118
+
119
+ Returns the variable keys present in PTE content but absent from the provided values map. Keys are deduplicated and returned in first-occurrence order. An empty string `""` is considered a provided value.
120
+
121
+ | Parameter | Type | Description |
122
+ | --------- | ------------------------- | ----------------------------------- |
123
+ | `blocks` | `PortableTextBlockLike[]` | Portable Text blocks to scan |
124
+ | `values` | `Record<string, string>` | Map of variable IDs to their values |
125
+
126
+ Returns `string[]`.
127
+
115
128
  ### `interpolateToString(blocks, values, fallback?)`
116
129
 
117
130
  Resolves PTE blocks to a plain string, replacing variable blocks with the corresponding values. Multiple blocks are joined with newlines.
package/dist/index.cjs CHANGED
@@ -9,6 +9,9 @@ function extractVariableKeys(blocks) {
9
9
  return typeof variableKey != "string" || seen.has(variableKey) ? accumulated : (seen.add(variableKey), [...accumulated, variableKey]);
10
10
  }, keys), []);
11
11
  }
12
+ function getMissingVariableKeys(blocks, values) {
13
+ return extractVariableKeys(blocks).filter((key) => values[key] === void 0);
14
+ }
12
15
  function defaultFallback(variableKey) {
13
16
  return `{${variableKey}}`;
14
17
  }
@@ -24,5 +27,6 @@ function interpolateToString(blocks, values, fallback = defaultFallback) {
24
27
  }
25
28
  exports.VARIABLE_TYPE_PREFIX = VARIABLE_TYPE_PREFIX;
26
29
  exports.extractVariableKeys = extractVariableKeys;
30
+ exports.getMissingVariableKeys = getMissingVariableKeys;
27
31
  exports.interpolateToString = interpolateToString;
28
32
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/constants.ts","../src/extractVariableKeys.ts","../src/interpolateToString.ts"],"sourcesContent":["/** @public */\nexport const VARIABLE_TYPE_PREFIX = 'pteInterpolationVariable'\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {PortableTextBlockLike} from './types'\n\n/** @public */\nexport function extractVariableKeys(blocks: PortableTextBlockLike[]): string[] {\n const seen = new Set<string>()\n\n return blocks.reduce<string[]>((keys, block) => {\n const children = block.children ?? []\n\n return children.reduce((accumulated, child) => {\n if (child._type !== VARIABLE_TYPE_PREFIX) return accumulated\n\n const variableKey = child.variableKey\n if (typeof variableKey !== 'string') return accumulated\n if (seen.has(variableKey)) return accumulated\n\n seen.add(variableKey)\n return [...accumulated, variableKey]\n }, keys)\n }, [])\n}\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {InterpolationFallback, InterpolationValues, PortableTextBlockLike} from './types'\n\nfunction defaultFallback(variableKey: string): string {\n return `{${variableKey}}`\n}\n\n/** @public */\nexport function interpolateToString(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n fallback: InterpolationFallback = defaultFallback,\n): string {\n return blocks\n .map((block) => {\n const children = block.children ?? []\n\n return children\n .map((child) => {\n if (child._type === VARIABLE_TYPE_PREFIX) {\n const variableKey = child.variableKey as string\n return values[variableKey] !== undefined ? values[variableKey] : fallback(variableKey)\n }\n\n return typeof child.text === 'string' ? child.text : ''\n })\n .join('')\n })\n .join('\\n')\n}\n"],"names":[],"mappings":";;AACO,MAAM,uBAAuB;ACG7B,SAAS,oBAAoB,QAA2C;AAC7E,QAAM,2BAAW,IAAA;AAEjB,SAAO,OAAO,OAAiB,CAAC,MAAM,WACnB,MAAM,YAAY,CAAA,GAEnB,OAAO,CAAC,aAAa,UAAU;AAC7C,QAAI,MAAM,UAAU,qBAAsB,QAAO;AAEjD,UAAM,cAAc,MAAM;AAE1B,WADI,OAAO,eAAgB,YACvB,KAAK,IAAI,WAAW,IAAU,eAElC,KAAK,IAAI,WAAW,GACb,CAAC,GAAG,aAAa,WAAW;AAAA,EACrC,GAAG,IAAI,GACN,EAAE;AACP;AClBA,SAAS,gBAAgB,aAA6B;AACpD,SAAO,IAAI,WAAW;AACxB;AAGO,SAAS,oBACd,QACA,QACA,WAAkC,iBAC1B;AACR,SAAO,OACJ,IAAI,CAAC,WACa,MAAM,YAAY,CAAA,GAGhC,IAAI,CAAC,UAAU;AACd,QAAI,MAAM,UAAU,sBAAsB;AACxC,YAAM,cAAc,MAAM;AAC1B,aAAO,OAAO,WAAW,MAAM,SAAY,OAAO,WAAW,IAAI,SAAS,WAAW;AAAA,IACvF;AAEA,WAAO,OAAO,MAAM,QAAS,WAAW,MAAM,OAAO;AAAA,EACvD,CAAC,EACA,KAAK,EAAE,CACX,EACA,KAAK;AAAA,CAAI;AACd;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/constants.ts","../src/extractVariableKeys.ts","../src/getMissingVariableKeys.ts","../src/interpolateToString.ts"],"sourcesContent":["/** @public */\nexport const VARIABLE_TYPE_PREFIX = 'pteInterpolationVariable'\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {PortableTextBlockLike} from './types'\n\n/** @public */\nexport function extractVariableKeys(blocks: PortableTextBlockLike[]): string[] {\n const seen = new Set<string>()\n\n return blocks.reduce<string[]>((keys, block) => {\n const children = block.children ?? []\n\n return children.reduce((accumulated, child) => {\n if (child._type !== VARIABLE_TYPE_PREFIX) return accumulated\n\n const variableKey = child.variableKey\n if (typeof variableKey !== 'string') return accumulated\n if (seen.has(variableKey)) return accumulated\n\n seen.add(variableKey)\n return [...accumulated, variableKey]\n }, keys)\n }, [])\n}\n","import {extractVariableKeys} from './extractVariableKeys'\nimport type {InterpolationValues, PortableTextBlockLike} from './types'\n\n/** @public */\nexport function getMissingVariableKeys(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n): string[] {\n return extractVariableKeys(blocks).filter((key) => values[key] === undefined)\n}\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {InterpolationFallback, InterpolationValues, PortableTextBlockLike} from './types'\n\nfunction defaultFallback(variableKey: string): string {\n return `{${variableKey}}`\n}\n\n/** @public */\nexport function interpolateToString(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n fallback: InterpolationFallback = defaultFallback,\n): string {\n return blocks\n .map((block) => {\n const children = block.children ?? []\n\n return children\n .map((child) => {\n if (child._type === VARIABLE_TYPE_PREFIX) {\n const variableKey = child.variableKey as string\n return values[variableKey] !== undefined ? values[variableKey] : fallback(variableKey)\n }\n\n return typeof child.text === 'string' ? child.text : ''\n })\n .join('')\n })\n .join('\\n')\n}\n"],"names":[],"mappings":";;AACO,MAAM,uBAAuB;ACG7B,SAAS,oBAAoB,QAA2C;AAC7E,QAAM,2BAAW,IAAA;AAEjB,SAAO,OAAO,OAAiB,CAAC,MAAM,WACnB,MAAM,YAAY,CAAA,GAEnB,OAAO,CAAC,aAAa,UAAU;AAC7C,QAAI,MAAM,UAAU,qBAAsB,QAAO;AAEjD,UAAM,cAAc,MAAM;AAE1B,WADI,OAAO,eAAgB,YACvB,KAAK,IAAI,WAAW,IAAU,eAElC,KAAK,IAAI,WAAW,GACb,CAAC,GAAG,aAAa,WAAW;AAAA,EACrC,GAAG,IAAI,GACN,EAAE;AACP;ACjBO,SAAS,uBACd,QACA,QACU;AACV,SAAO,oBAAoB,MAAM,EAAE,OAAO,CAAC,QAAQ,OAAO,GAAG,MAAM,MAAS;AAC9E;ACNA,SAAS,gBAAgB,aAA6B;AACpD,SAAO,IAAI,WAAW;AACxB;AAGO,SAAS,oBACd,QACA,QACA,WAAkC,iBAC1B;AACR,SAAO,OACJ,IAAI,CAAC,WACa,MAAM,YAAY,CAAA,GAGhC,IAAI,CAAC,UAAU;AACd,QAAI,MAAM,UAAU,sBAAsB;AACxC,YAAM,cAAc,MAAM;AAC1B,aAAO,OAAO,WAAW,MAAM,SAAY,OAAO,WAAW,IAAI,SAAS,WAAW;AAAA,IACvF;AAEA,WAAO,OAAO,MAAM,QAAS,WAAW,MAAM,OAAO;AAAA,EACvD,CAAC,EACA,KAAK,EAAE,CACX,EACA,KAAK;AAAA,CAAI;AACd;;;;;"}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,12 @@
1
1
  /** @public */
2
2
  export declare function extractVariableKeys(blocks: PortableTextBlockLike[]): string[]
3
3
 
4
+ /** @public */
5
+ export declare function getMissingVariableKeys(
6
+ blocks: PortableTextBlockLike[],
7
+ values: InterpolationValues,
8
+ ): string[]
9
+
4
10
  /** @public */
5
11
  export declare function interpolateToString(
6
12
  blocks: PortableTextBlockLike[],
package/dist/index.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  /** @public */
2
2
  export declare function extractVariableKeys(blocks: PortableTextBlockLike[]): string[]
3
3
 
4
+ /** @public */
5
+ export declare function getMissingVariableKeys(
6
+ blocks: PortableTextBlockLike[],
7
+ values: InterpolationValues,
8
+ ): string[]
9
+
4
10
  /** @public */
5
11
  export declare function interpolateToString(
6
12
  blocks: PortableTextBlockLike[],
package/dist/index.js CHANGED
@@ -7,6 +7,9 @@ function extractVariableKeys(blocks) {
7
7
  return typeof variableKey != "string" || seen.has(variableKey) ? accumulated : (seen.add(variableKey), [...accumulated, variableKey]);
8
8
  }, keys), []);
9
9
  }
10
+ function getMissingVariableKeys(blocks, values) {
11
+ return extractVariableKeys(blocks).filter((key) => values[key] === void 0);
12
+ }
10
13
  function defaultFallback(variableKey) {
11
14
  return `{${variableKey}}`;
12
15
  }
@@ -23,6 +26,7 @@ function interpolateToString(blocks, values, fallback = defaultFallback) {
23
26
  export {
24
27
  VARIABLE_TYPE_PREFIX,
25
28
  extractVariableKeys,
29
+ getMissingVariableKeys,
26
30
  interpolateToString
27
31
  };
28
32
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/constants.ts","../src/extractVariableKeys.ts","../src/interpolateToString.ts"],"sourcesContent":["/** @public */\nexport const VARIABLE_TYPE_PREFIX = 'pteInterpolationVariable'\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {PortableTextBlockLike} from './types'\n\n/** @public */\nexport function extractVariableKeys(blocks: PortableTextBlockLike[]): string[] {\n const seen = new Set<string>()\n\n return blocks.reduce<string[]>((keys, block) => {\n const children = block.children ?? []\n\n return children.reduce((accumulated, child) => {\n if (child._type !== VARIABLE_TYPE_PREFIX) return accumulated\n\n const variableKey = child.variableKey\n if (typeof variableKey !== 'string') return accumulated\n if (seen.has(variableKey)) return accumulated\n\n seen.add(variableKey)\n return [...accumulated, variableKey]\n }, keys)\n }, [])\n}\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {InterpolationFallback, InterpolationValues, PortableTextBlockLike} from './types'\n\nfunction defaultFallback(variableKey: string): string {\n return `{${variableKey}}`\n}\n\n/** @public */\nexport function interpolateToString(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n fallback: InterpolationFallback = defaultFallback,\n): string {\n return blocks\n .map((block) => {\n const children = block.children ?? []\n\n return children\n .map((child) => {\n if (child._type === VARIABLE_TYPE_PREFIX) {\n const variableKey = child.variableKey as string\n return values[variableKey] !== undefined ? values[variableKey] : fallback(variableKey)\n }\n\n return typeof child.text === 'string' ? child.text : ''\n })\n .join('')\n })\n .join('\\n')\n}\n"],"names":[],"mappings":"AACO,MAAM,uBAAuB;ACG7B,SAAS,oBAAoB,QAA2C;AAC7E,QAAM,2BAAW,IAAA;AAEjB,SAAO,OAAO,OAAiB,CAAC,MAAM,WACnB,MAAM,YAAY,CAAA,GAEnB,OAAO,CAAC,aAAa,UAAU;AAC7C,QAAI,MAAM,UAAU,qBAAsB,QAAO;AAEjD,UAAM,cAAc,MAAM;AAE1B,WADI,OAAO,eAAgB,YACvB,KAAK,IAAI,WAAW,IAAU,eAElC,KAAK,IAAI,WAAW,GACb,CAAC,GAAG,aAAa,WAAW;AAAA,EACrC,GAAG,IAAI,GACN,EAAE;AACP;AClBA,SAAS,gBAAgB,aAA6B;AACpD,SAAO,IAAI,WAAW;AACxB;AAGO,SAAS,oBACd,QACA,QACA,WAAkC,iBAC1B;AACR,SAAO,OACJ,IAAI,CAAC,WACa,MAAM,YAAY,CAAA,GAGhC,IAAI,CAAC,UAAU;AACd,QAAI,MAAM,UAAU,sBAAsB;AACxC,YAAM,cAAc,MAAM;AAC1B,aAAO,OAAO,WAAW,MAAM,SAAY,OAAO,WAAW,IAAI,SAAS,WAAW;AAAA,IACvF;AAEA,WAAO,OAAO,MAAM,QAAS,WAAW,MAAM,OAAO;AAAA,EACvD,CAAC,EACA,KAAK,EAAE,CACX,EACA,KAAK;AAAA,CAAI;AACd;"}
1
+ {"version":3,"file":"index.js","sources":["../src/constants.ts","../src/extractVariableKeys.ts","../src/getMissingVariableKeys.ts","../src/interpolateToString.ts"],"sourcesContent":["/** @public */\nexport const VARIABLE_TYPE_PREFIX = 'pteInterpolationVariable'\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {PortableTextBlockLike} from './types'\n\n/** @public */\nexport function extractVariableKeys(blocks: PortableTextBlockLike[]): string[] {\n const seen = new Set<string>()\n\n return blocks.reduce<string[]>((keys, block) => {\n const children = block.children ?? []\n\n return children.reduce((accumulated, child) => {\n if (child._type !== VARIABLE_TYPE_PREFIX) return accumulated\n\n const variableKey = child.variableKey\n if (typeof variableKey !== 'string') return accumulated\n if (seen.has(variableKey)) return accumulated\n\n seen.add(variableKey)\n return [...accumulated, variableKey]\n }, keys)\n }, [])\n}\n","import {extractVariableKeys} from './extractVariableKeys'\nimport type {InterpolationValues, PortableTextBlockLike} from './types'\n\n/** @public */\nexport function getMissingVariableKeys(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n): string[] {\n return extractVariableKeys(blocks).filter((key) => values[key] === undefined)\n}\n","import {VARIABLE_TYPE_PREFIX} from './constants'\nimport type {InterpolationFallback, InterpolationValues, PortableTextBlockLike} from './types'\n\nfunction defaultFallback(variableKey: string): string {\n return `{${variableKey}}`\n}\n\n/** @public */\nexport function interpolateToString(\n blocks: PortableTextBlockLike[],\n values: InterpolationValues,\n fallback: InterpolationFallback = defaultFallback,\n): string {\n return blocks\n .map((block) => {\n const children = block.children ?? []\n\n return children\n .map((child) => {\n if (child._type === VARIABLE_TYPE_PREFIX) {\n const variableKey = child.variableKey as string\n return values[variableKey] !== undefined ? values[variableKey] : fallback(variableKey)\n }\n\n return typeof child.text === 'string' ? child.text : ''\n })\n .join('')\n })\n .join('\\n')\n}\n"],"names":[],"mappings":"AACO,MAAM,uBAAuB;ACG7B,SAAS,oBAAoB,QAA2C;AAC7E,QAAM,2BAAW,IAAA;AAEjB,SAAO,OAAO,OAAiB,CAAC,MAAM,WACnB,MAAM,YAAY,CAAA,GAEnB,OAAO,CAAC,aAAa,UAAU;AAC7C,QAAI,MAAM,UAAU,qBAAsB,QAAO;AAEjD,UAAM,cAAc,MAAM;AAE1B,WADI,OAAO,eAAgB,YACvB,KAAK,IAAI,WAAW,IAAU,eAElC,KAAK,IAAI,WAAW,GACb,CAAC,GAAG,aAAa,WAAW;AAAA,EACrC,GAAG,IAAI,GACN,EAAE;AACP;ACjBO,SAAS,uBACd,QACA,QACU;AACV,SAAO,oBAAoB,MAAM,EAAE,OAAO,CAAC,QAAQ,OAAO,GAAG,MAAM,MAAS;AAC9E;ACNA,SAAS,gBAAgB,aAA6B;AACpD,SAAO,IAAI,WAAW;AACxB;AAGO,SAAS,oBACd,QACA,QACA,WAAkC,iBAC1B;AACR,SAAO,OACJ,IAAI,CAAC,WACa,MAAM,YAAY,CAAA,GAGhC,IAAI,CAAC,UAAU;AACd,QAAI,MAAM,UAAU,sBAAsB;AACxC,YAAM,cAAc,MAAM;AAC1B,aAAO,OAAO,WAAW,MAAM,SAAY,OAAO,WAAW,IAAI,SAAS,WAAW;AAAA,IACvF;AAEA,WAAO,OAAO,MAAM,QAAS,WAAW,MAAM,OAAO;AAAA,EACvD,CAAC,EACA,KAAK,EAAE,CACX,EACA,KAAK;AAAA,CAAI;AACd;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pte-interpolation-core",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Framework-agnostic utilities for Portable Text variable interpolation",
@@ -85,9 +85,7 @@ export const blockWithNonStringVariableKey: PortableTextBlockLike[] = [
85
85
  {
86
86
  _type: 'block',
87
87
  _key: 'block-1',
88
- children: [
89
- {_type: 'pteInterpolationVariable', _key: 'var-1', variableKey: 123 as unknown as string},
90
- ],
88
+ children: [{_type: 'pteInterpolationVariable', _key: 'var-1', variableKey: 123} as never],
91
89
  },
92
90
  ]
93
91
 
@@ -0,0 +1,88 @@
1
+ import {describe, expect, it} from 'vitest'
2
+ import {getMissingVariableKeys} from '../getMissingVariableKeys'
3
+ import {
4
+ blockWithNoChildren,
5
+ blockWithNonStringVariableKey,
6
+ consecutiveVariablesBlock,
7
+ duplicateVariableBlock,
8
+ emptyBlocksContent,
9
+ multiBlockContent,
10
+ multipleVariablesBlock,
11
+ plainTextBlock,
12
+ singleVariableBlock,
13
+ } from './fixtures'
14
+
15
+ describe('getMissingVariableKeys', () => {
16
+ it('returns empty array for empty blocks', () => {
17
+ expect(getMissingVariableKeys(emptyBlocksContent, {})).toEqual([])
18
+ })
19
+
20
+ it('returns empty array when no variables exist', () => {
21
+ expect(getMissingVariableKeys(plainTextBlock, {})).toEqual([])
22
+ })
23
+
24
+ it('returns empty array when all variables provided', () => {
25
+ expect(getMissingVariableKeys(singleVariableBlock, {firstName: 'Alice'})).toEqual([])
26
+ })
27
+
28
+ it('returns empty array when all multiple variables provided', () => {
29
+ expect(
30
+ getMissingVariableKeys(multipleVariablesBlock, {
31
+ firstName: 'Alice',
32
+ lastName: 'Smith',
33
+ email: 'a@b.com',
34
+ }),
35
+ ).toEqual([])
36
+ })
37
+
38
+ it('returns missing key when value not provided', () => {
39
+ expect(getMissingVariableKeys(singleVariableBlock, {})).toEqual(['firstName'])
40
+ })
41
+
42
+ it('returns only missing keys when some values provided', () => {
43
+ expect(getMissingVariableKeys(multipleVariablesBlock, {firstName: 'Alice'})).toEqual([
44
+ 'lastName',
45
+ 'email',
46
+ ])
47
+ })
48
+
49
+ it('does not treat empty string as missing', () => {
50
+ expect(getMissingVariableKeys(singleVariableBlock, {firstName: ''})).toEqual([])
51
+ })
52
+
53
+ it('returns missing keys across multiple blocks', () => {
54
+ expect(getMissingVariableKeys(multiBlockContent, {firstName: 'Alice'})).toEqual(['email'])
55
+ })
56
+
57
+ it('deduplicates missing keys', () => {
58
+ expect(getMissingVariableKeys(duplicateVariableBlock, {})).toEqual(['firstName'])
59
+ })
60
+
61
+ it('handles blocks with no children property', () => {
62
+ expect(getMissingVariableKeys(blockWithNoChildren, {})).toEqual([])
63
+ })
64
+
65
+ it('skips children with non-string variableKey', () => {
66
+ expect(getMissingVariableKeys(blockWithNonStringVariableKey, {})).toEqual([])
67
+ })
68
+
69
+ it('returns missing keys for consecutive variables', () => {
70
+ expect(getMissingVariableKeys(consecutiveVariablesBlock, {firstName: 'Alice'})).toEqual([
71
+ 'lastName',
72
+ ])
73
+ })
74
+
75
+ it('ignores extra values not in blocks', () => {
76
+ expect(
77
+ getMissingVariableKeys(singleVariableBlock, {firstName: 'Alice', extraKey: 'ignored'}),
78
+ ).toEqual([])
79
+ })
80
+
81
+ it('preserves first-occurrence order of missing keys', () => {
82
+ expect(getMissingVariableKeys(multipleVariablesBlock, {})).toEqual([
83
+ 'firstName',
84
+ 'lastName',
85
+ 'email',
86
+ ])
87
+ })
88
+ })
@@ -0,0 +1,10 @@
1
+ import {extractVariableKeys} from './extractVariableKeys'
2
+ import type {InterpolationValues, PortableTextBlockLike} from './types'
3
+
4
+ /** @public */
5
+ export function getMissingVariableKeys(
6
+ blocks: PortableTextBlockLike[],
7
+ values: InterpolationValues,
8
+ ): string[] {
9
+ return extractVariableKeys(blocks).filter((key) => values[key] === undefined)
10
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export {VARIABLE_TYPE_PREFIX} from './constants'
2
2
  export {extractVariableKeys} from './extractVariableKeys'
3
+ export {getMissingVariableKeys} from './getMissingVariableKeys'
3
4
  export {interpolateToString} from './interpolateToString'
4
5
  export type {
5
6
  InterpolationFallback,