restql 1.2.6 → 1.2.8

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
@@ -15,19 +15,19 @@ By specifying a set of properties to describe the paths.
15
15
 
16
16
  ### Package Manager
17
17
 
18
- #### npm
18
+ #### NPM
19
19
 
20
20
  ```sh
21
21
  npm install restql
22
22
  ```
23
23
 
24
- #### yarn
24
+ #### Yarn
25
25
 
26
26
  ```sh
27
27
  yarn add restql
28
28
  ```
29
29
 
30
- #### pnpm
30
+ #### PNPM
31
31
 
32
32
  ```sh
33
33
  pnpm add restql
@@ -41,7 +41,7 @@ pnpm add restql
41
41
  <script src="https://cdn.jsdelivr.net/npm/restql/dist/index.min.js"></script>
42
42
  ```
43
43
 
44
- #### unpkg
44
+ #### UNPKG
45
45
 
46
46
  ```html
47
47
  <script src="https://unpkg.com/restql/dist/index.min.js"></script>
package/dist/index.cjs CHANGED
@@ -2,20 +2,30 @@
2
2
 
3
3
  var esToolkit = require('es-toolkit');
4
4
 
5
- const responses = {};
5
+ const responses = /* @__PURE__ */ new Map();
6
6
  async function fetchResource(resource, options) {
7
7
  const key = `${resource}-${JSON.stringify(options)}`;
8
- if (!(key in responses)) {
9
- responses[key] = fetch(resource, options).then((response) => {
10
- responses[key] = response;
11
- return response;
8
+ if (!responses.has(key)) {
9
+ const response = fetch(resource, options).then((nextResponse) => {
10
+ if (!nextResponse.ok) {
11
+ responses.delete(key);
12
+ }
13
+ return nextResponse;
14
+ }).catch((error) => {
15
+ responses.delete(key);
16
+ throw error;
12
17
  });
18
+ responses.set(key, response);
13
19
  }
14
- return responses[key];
20
+ return responses.get(key);
15
21
  }
16
22
 
17
23
  function isResource(resource) {
18
- return Boolean(URL.parse(resource));
24
+ try {
25
+ return Boolean(new URL(resource));
26
+ } catch {
27
+ return false;
28
+ }
19
29
  }
20
30
 
21
31
  const PROP_DELIMITER = ".";
@@ -57,9 +67,6 @@ function objectSet(data, props) {
57
67
  }
58
68
 
59
69
  async function resolve(resource, resolver, options) {
60
- if (!resource) {
61
- return null;
62
- }
63
70
  if (!isResource(resource)) {
64
71
  throw new Error(`InvalidArgumentError: invalid resource \`${resource}\``);
65
72
  }
package/dist/index.js CHANGED
@@ -1,178 +1,263 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.restql = factory());
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
+ typeof define === 'function' && define.amd ? define(factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.restql = factory());
5
5
  })(this, (function () { 'use strict';
6
6
 
7
- function isPlainObject(value) {
8
- if (!value || typeof value !== 'object') {
9
- return false;
10
- }
11
- const proto = Object.getPrototypeOf(value);
12
- const hasObjectPrototype = proto === null ||
13
- proto === Object.prototype ||
14
- Object.getPrototypeOf(proto) === null;
15
- if (!hasObjectPrototype) {
16
- return false;
17
- }
18
- return Object.prototype.toString.call(value) === '[object Object]';
19
- }
7
+ //#region src/predicate/isPlainObject.ts
8
+ /**
9
+ * Checks if a given value is a plain object.
10
+ *
11
+ * @param {object} value - The value to check.
12
+ * @returns {value is Record<PropertyKey, any>} - True if the value is a plain object, otherwise false.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // ✅👇 True
17
+ *
18
+ * isPlainObject({ }); //
19
+ * isPlainObject({ key: 'value' }); // ✅
20
+ * isPlainObject({ key: new Date() }); // ✅
21
+ * isPlainObject(new Object()); // ✅
22
+ * isPlainObject(Object.create(null)); // ✅
23
+ * isPlainObject({ nested: { key: true} }); // ✅
24
+ * isPlainObject(new Proxy({}, {})); // ✅
25
+ * isPlainObject({ [Symbol('tag')]: 'A' }); // ✅
26
+ *
27
+ * // ✅👇 (cross-realms, node context, workers, ...)
28
+ * const runInNewContext = await import('node:vm').then(
29
+ * (mod) => mod.runInNewContext
30
+ * );
31
+ * isPlainObject(runInNewContext('({})')); // ✅
32
+ *
33
+ * // ❌👇 False
34
+ *
35
+ * class Test { };
36
+ * isPlainObject(new Test()) // ❌
37
+ * isPlainObject(10); // ❌
38
+ * isPlainObject(null); // ❌
39
+ * isPlainObject('hello'); // ❌
40
+ * isPlainObject([]); // ❌
41
+ * isPlainObject(new Date()); // ❌
42
+ * isPlainObject(new Uint8Array([1])); // ❌
43
+ * isPlainObject(Buffer.from('ABC')); // ❌
44
+ * isPlainObject(Promise.resolve({})); // ❌
45
+ * isPlainObject(Object.create({})); // ❌
46
+ * isPlainObject(new (class Cls {})); // ❌
47
+ * isPlainObject(globalThis); // ❌,
48
+ * ```
49
+ */
50
+ function isPlainObject(value) {
51
+ if (!value || typeof value !== "object") return false;
52
+ const proto = Object.getPrototypeOf(value);
53
+ if (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;
54
+ return Object.prototype.toString.call(value) === "[object Object]";
55
+ }
20
56
 
21
- function isUnsafeProperty(key) {
22
- return key === '__proto__';
23
- }
57
+ //#region src/_internal/isUnsafeProperty.ts
58
+ /**
59
+ * Checks if a property key is unsafe to modify directly.
60
+ *
61
+ * This function is used in functions like `merge` to prevent prototype pollution attacks
62
+ * by identifying property keys that could modify the object's prototype chain or constructor.
63
+ *
64
+ * @param key - The property key to check
65
+ * @returns `true` if the property is unsafe to modify directly, `false` otherwise
66
+ * @internal
67
+ */
68
+ function isUnsafeProperty(key) {
69
+ return key === "__proto__";
70
+ }
24
71
 
25
- function merge(target, source) {
26
- const sourceKeys = Object.keys(source);
27
- for (let i = 0; i < sourceKeys.length; i++) {
28
- const key = sourceKeys[i];
29
- if (isUnsafeProperty(key)) {
30
- continue;
31
- }
32
- const sourceValue = source[key];
33
- const targetValue = target[key];
34
- if (isMergeableValue(sourceValue) && isMergeableValue(targetValue)) {
35
- target[key] = merge(targetValue, sourceValue);
36
- }
37
- else if (Array.isArray(sourceValue)) {
38
- target[key] = merge([], sourceValue);
39
- }
40
- else if (isPlainObject(sourceValue)) {
41
- target[key] = merge({}, sourceValue);
42
- }
43
- else if (targetValue === undefined || sourceValue !== undefined) {
44
- target[key] = sourceValue;
45
- }
46
- }
47
- return target;
48
- }
49
- function isMergeableValue(value) {
50
- return isPlainObject(value) || Array.isArray(value);
51
- }
72
+ //#region src/object/merge.ts
73
+ /**
74
+ * Merges the properties of the source object into the target object.
75
+ *
76
+ * This function performs a deep merge, meaning nested objects and arrays are merged recursively.
77
+ * If a property in the source object is an array or an object and the corresponding property in the target object is also an array or object, they will be merged.
78
+ * If a property in the source object is undefined, it will not overwrite a defined property in the target object.
79
+ *
80
+ * Note that this function mutates the target object.
81
+ *
82
+ * @param {T} target - The target object into which the source object properties will be merged. This object is modified in place.
83
+ * @param {S} source - The source object whose properties will be merged into the target object.
84
+ * @returns {T & S} The updated target object with properties from the source object merged in.
85
+ *
86
+ * @template T - Type of the target object.
87
+ * @template S - Type of the source object.
88
+ *
89
+ * @example
90
+ * const target = { a: 1, b: { x: 1, y: 2 } };
91
+ * const source = { b: { y: 3, z: 4 }, c: 5 };
92
+ *
93
+ * const result = merge(target, source);
94
+ * console.log(result);
95
+ * // Output: { a: 1, b: { x: 1, y: 3, z: 4 }, c: 5 }
96
+ *
97
+ * @example
98
+ * const target = { a: [1, 2], b: { x: 1 } };
99
+ * const source = { a: [3], b: { y: 2 } };
100
+ *
101
+ * const result = merge(target, source);
102
+ * console.log(result);
103
+ * // Output: { a: [3, 2], b: { x: 1, y: 2 } }
104
+ *
105
+ * @example
106
+ * const target = { a: null };
107
+ * const source = { a: [1, 2, 3] };
108
+ *
109
+ * const result = merge(target, source);
110
+ * console.log(result);
111
+ * // Output: { a: [1, 2, 3] }
112
+ */
113
+ function merge(target, source) {
114
+ const sourceKeys = Object.keys(source);
115
+ for (let i = 0; i < sourceKeys.length; i++) {
116
+ const key = sourceKeys[i];
117
+ if (isUnsafeProperty(key)) continue;
118
+ const sourceValue = source[key];
119
+ const targetValue = target[key];
120
+ if (isMergeableValue(sourceValue) && isMergeableValue(targetValue)) target[key] = merge(targetValue, sourceValue);
121
+ else if (Array.isArray(sourceValue)) target[key] = merge([], sourceValue);
122
+ else if (isPlainObject(sourceValue)) target[key] = merge({}, sourceValue);
123
+ else if (targetValue === void 0 || sourceValue !== void 0) target[key] = sourceValue;
124
+ }
125
+ return target;
126
+ }
127
+ function isMergeableValue(value) {
128
+ return isPlainObject(value) || Array.isArray(value);
129
+ }
52
130
 
53
- const responses = {};
54
- async function fetchResource(resource, options) {
55
- const key = `${resource}-${JSON.stringify(options)}`;
56
- if (!(key in responses)) {
57
- responses[key] = fetch(resource, options).then((response) => {
58
- responses[key] = response;
59
- return response;
60
- });
61
- }
62
- return responses[key];
63
- }
131
+ const responses = /* @__PURE__ */ new Map();
132
+ async function fetchResource(resource, options) {
133
+ const key = `${resource}-${JSON.stringify(options)}`;
134
+ if (!responses.has(key)) {
135
+ const response = fetch(resource, options).then((nextResponse) => {
136
+ if (!nextResponse.ok) {
137
+ responses.delete(key);
138
+ }
139
+ return nextResponse;
140
+ }).catch((error) => {
141
+ responses.delete(key);
142
+ throw error;
143
+ });
144
+ responses.set(key, response);
145
+ }
146
+ return responses.get(key);
147
+ }
64
148
 
65
- function isResource(resource) {
66
- return Boolean(URL.parse(resource));
67
- }
149
+ function isResource(resource) {
150
+ try {
151
+ return Boolean(new URL(resource));
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
68
156
 
69
- const PROP_DELIMITER = ".";
70
- const REGEX_PROP_IS_ARR_IS_OPT = /^([^[\]?]+)(\[])?(\?)?$/;
71
- const constants = Object.freeze({
72
- PROP_DELIMITER,
73
- REGEX_PROP_IS_ARR_IS_OPT
74
- });
157
+ const PROP_DELIMITER = ".";
158
+ const REGEX_PROP_IS_ARR_IS_OPT = /^([^[\]?]+)(\[])?(\?)?$/;
159
+ const constants = Object.freeze({
160
+ PROP_DELIMITER,
161
+ REGEX_PROP_IS_ARR_IS_OPT
162
+ });
75
163
 
76
- function objectGet(obj, props) {
77
- const nextPropsArr = props.split(constants.PROP_DELIMITER);
78
- const [, prop, isArr, isOpt] = constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()) || [];
79
- const nextProps = nextPropsArr.join(constants.PROP_DELIMITER);
80
- if (!prop) {
81
- return obj;
82
- }
83
- if (!(prop in obj)) {
84
- if (isOpt) {
85
- return isArr ? [] : null;
86
- }
87
- throw new Error(`RuntimeError: could not get property \`${prop}\``);
88
- }
89
- const nextObjs = obj[prop];
90
- return isArr ? nextObjs.map(
91
- (nextObj) => objectGet(nextObj, nextProps)
92
- ) : objectGet(nextObjs, nextProps);
93
- }
164
+ function objectGet(obj, props) {
165
+ const nextPropsArr = props.split(constants.PROP_DELIMITER);
166
+ const [, prop, isArr, isOpt] = constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()) || [];
167
+ const nextProps = nextPropsArr.join(constants.PROP_DELIMITER);
168
+ if (!prop) {
169
+ return obj;
170
+ }
171
+ if (!(prop in obj)) {
172
+ if (isOpt) {
173
+ return isArr ? [] : null;
174
+ }
175
+ throw new Error(`RuntimeError: could not get property \`${prop}\``);
176
+ }
177
+ const nextObjs = obj[prop];
178
+ return isArr ? nextObjs.map(
179
+ (nextObj) => objectGet(nextObj, nextProps)
180
+ ) : objectGet(nextObjs, nextProps);
181
+ }
94
182
 
95
- function objectSet(data, props) {
96
- const nextPropsArr = props.split(constants.PROP_DELIMITER);
97
- const [, prop, isArr] = constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()) || [];
98
- const nextProps = nextPropsArr.join(constants.PROP_DELIMITER);
99
- if (!prop) {
100
- return data;
101
- }
102
- return {
103
- [prop]: isArr ? data.map((nextData) => objectSet(nextData, nextProps)) : objectSet(data, nextProps)
104
- };
105
- }
183
+ function objectSet(data, props) {
184
+ const nextPropsArr = props.split(constants.PROP_DELIMITER);
185
+ const [, prop, isArr] = constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()) || [];
186
+ const nextProps = nextPropsArr.join(constants.PROP_DELIMITER);
187
+ if (!prop) {
188
+ return data;
189
+ }
190
+ return {
191
+ [prop]: isArr ? data.map((nextData) => objectSet(nextData, nextProps)) : objectSet(data, nextProps)
192
+ };
193
+ }
106
194
 
107
- async function resolve(resource, resolver, options) {
108
- if (!resource) {
109
- return null;
110
- }
111
- if (!isResource(resource)) {
112
- throw new Error(`InvalidArgumentError: invalid resource \`${resource}\``);
113
- }
114
- const response = (await fetchResource(resource, options)).clone();
115
- if (!response.ok) {
116
- throw new Error(`RuntimeError: could not fetch resource \`${resource}\``);
117
- }
118
- const obj = await response.json();
119
- if (resolver === null) {
120
- return obj;
121
- }
122
- const resourcesObj = Object.keys(resolver).map((props) => ({
123
- [props]: objectGet(obj, props)
124
- }));
125
- const resourcesArr = Object.entries(
126
- resourcesObj.reduce((result, val) => ({ ...result, ...val }), {})
127
- );
128
- const responses = await Promise.all(
129
- resourcesArr.map(async ([props, resources]) => {
130
- const nextResolver = resolver[props];
131
- const data = Array.isArray(resources) ? await Promise.all(
132
- resources.map(
133
- async (nextResource) => resolve(nextResource, nextResolver, options)
134
- )
135
- ) : await resolve(resources, nextResolver, options);
136
- return [props, data];
137
- })
138
- );
139
- return responses.reduce(
140
- (result, [props, data]) => merge(result, objectSet(data, props)),
141
- obj
142
- );
143
- }
195
+ async function resolve(resource, resolver, options) {
196
+ if (!isResource(resource)) {
197
+ throw new Error(`InvalidArgumentError: invalid resource \`${resource}\``);
198
+ }
199
+ const response = (await fetchResource(resource, options)).clone();
200
+ if (!response.ok) {
201
+ throw new Error(`RuntimeError: could not fetch resource \`${resource}\``);
202
+ }
203
+ const obj = await response.json();
204
+ if (resolver === null) {
205
+ return obj;
206
+ }
207
+ const resourcesObj = Object.keys(resolver).map((props) => ({
208
+ [props]: objectGet(obj, props)
209
+ }));
210
+ const resourcesArr = Object.entries(
211
+ resourcesObj.reduce((result, val) => ({ ...result, ...val }), {})
212
+ );
213
+ const responses = await Promise.all(
214
+ resourcesArr.map(async ([props, resources]) => {
215
+ const nextResolver = resolver[props];
216
+ const data = Array.isArray(resources) ? await Promise.all(
217
+ resources.map(
218
+ async (nextResource) => resolve(nextResource, nextResolver, options)
219
+ )
220
+ ) : await resolve(resources, nextResolver, options);
221
+ return [props, data];
222
+ })
223
+ );
224
+ return responses.reduce(
225
+ (result, [props, data]) => merge(result, objectSet(data, props)),
226
+ obj
227
+ );
228
+ }
144
229
 
145
- function isObject(obj) {
146
- return obj !== null && typeof obj === "object" && !Array.isArray(obj);
147
- }
230
+ function isObject(obj) {
231
+ return obj !== null && typeof obj === "object" && !Array.isArray(obj);
232
+ }
148
233
 
149
- function isResolver(resolver) {
150
- if (resolver === null) {
151
- return true;
152
- }
153
- const keys = Object.keys(resolver);
154
- if (!keys.length) {
155
- return false;
156
- }
157
- return keys.map(
158
- (key) => !key.startsWith(constants.PROP_DELIMITER) && !key.endsWith(constants.PROP_DELIMITER) && isResolver(resolver[key])
159
- ).reduce((result, val) => result && val, true);
160
- }
234
+ function isResolver(resolver) {
235
+ if (resolver === null) {
236
+ return true;
237
+ }
238
+ const keys = Object.keys(resolver);
239
+ if (!keys.length) {
240
+ return false;
241
+ }
242
+ return keys.map(
243
+ (key) => !key.startsWith(constants.PROP_DELIMITER) && !key.endsWith(constants.PROP_DELIMITER) && isResolver(resolver[key])
244
+ ).reduce((result, val) => result && val, true);
245
+ }
161
246
 
162
- async function restql(resource, resolver, options = {}) {
163
- if (!isObject(resolver) || !isResolver(resolver)) {
164
- throw new Error(
165
- `InvalidArgumentError: invalid resolver \`${JSON.stringify(resolver)}\``
166
- );
167
- }
168
- if (!isObject(options)) {
169
- throw new Error(
170
- `InvalidArgumentError: invalid options \`${JSON.stringify(options)}\``
171
- );
172
- }
173
- return resolve(resource, resolver, options);
174
- }
247
+ async function restql(resource, resolver, options = {}) {
248
+ if (!isObject(resolver) || !isResolver(resolver)) {
249
+ throw new Error(
250
+ `InvalidArgumentError: invalid resolver \`${JSON.stringify(resolver)}\``
251
+ );
252
+ }
253
+ if (!isObject(options)) {
254
+ throw new Error(
255
+ `InvalidArgumentError: invalid options \`${JSON.stringify(options)}\``
256
+ );
257
+ }
258
+ return resolve(resource, resolver, options);
259
+ }
175
260
 
176
- return restql;
261
+ return restql;
177
262
 
178
263
  }));
package/dist/index.min.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(l,a){typeof exports=="object"&&typeof module<"u"?module.exports=a():typeof define=="function"&&define.amd?define(a):(l=typeof globalThis<"u"?globalThis:l||self,l.restql=a())})(this,(function(){"use strict";function l(e){if(!e||typeof e!="object")return!1;const n=Object.getPrototypeOf(e);return n===null||n===Object.prototype||Object.getPrototypeOf(n)===null?Object.prototype.toString.call(e)==="[object Object]":!1}function a(e){return e==="__proto__"}function y(e,n){const t=Object.keys(n);for(let r=0;r<t.length;r++){const o=t[r];if(a(o))continue;const i=n[o],c=e[o];d(i)&&d(c)?e[o]=y(c,i):Array.isArray(i)?e[o]=y([],i):l(i)?e[o]=y({},i):(c===void 0||i!==void 0)&&(e[o]=i)}return e}function d(e){return l(e)||Array.isArray(e)}const R={};async function j(e,n){const t=`${e}-${JSON.stringify(n)}`;return t in R||(R[t]=fetch(e,n).then(r=>(R[t]=r,r))),R[t]}function h(e){return!!URL.parse(e)}const b=/^([^[\]?]+)(\[])?(\?)?$/,f=Object.freeze({PROP_DELIMITER:".",REGEX_PROP_IS_ARR_IS_OPT:b});function O(e,n){const t=n.split(f.PROP_DELIMITER),[,r,o,i]=f.REGEX_PROP_IS_ARR_IS_OPT.exec(t.shift())||[],c=t.join(f.PROP_DELIMITER);if(!r)return e;if(!(r in e)){if(i)return o?[]:null;throw new Error(`RuntimeError: could not get property \`${r}\``)}const s=e[r];return o?s.map(u=>O(u,c)):O(s,c)}function P(e,n){const t=n.split(f.PROP_DELIMITER),[,r,o]=f.REGEX_PROP_IS_ARR_IS_OPT.exec(t.shift())||[],i=t.join(f.PROP_DELIMITER);return r?{[r]:o?e.map(c=>P(c,i)):P(e,i)}:e}async function E(e,n,t){if(!e)return null;if(!h(e))throw new Error(`InvalidArgumentError: invalid resource \`${e}\``);const r=(await j(e,t)).clone();if(!r.ok)throw new Error(`RuntimeError: could not fetch resource \`${e}\``);const o=await r.json();if(n===null)return o;const i=Object.keys(n).map(s=>({[s]:O(o,s)})),c=Object.entries(i.reduce((s,u)=>({...s,...u}),{}));return(await Promise.all(c.map(async([s,u])=>{const p=n[s],w=Array.isArray(u)?await Promise.all(u.map(async A=>E(A,p,t))):await E(u,p,t);return[s,w]}))).reduce((s,[u,p])=>y(s,P(p,u)),o)}function _(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function I(e){if(e===null)return!0;const n=Object.keys(e);return n.length?n.map(t=>!t.startsWith(f.PROP_DELIMITER)&&!t.endsWith(f.PROP_DELIMITER)&&I(e[t])).reduce((t,r)=>t&&r,!0):!1}async function m(e,n,t={}){if(!_(n)||!I(n))throw new Error(`InvalidArgumentError: invalid resolver \`${JSON.stringify(n)}\``);if(!_(t))throw new Error(`InvalidArgumentError: invalid options \`${JSON.stringify(t)}\``);return E(e,n,t)}return m}));
1
+ (function(l,a){typeof exports=="object"&&typeof module<"u"?module.exports=a():typeof define=="function"&&define.amd?define(a):(l=typeof globalThis<"u"?globalThis:l||self,l.restql=a())})(this,(function(){"use strict";function l(e){if(!e||typeof e!="object")return!1;const r=Object.getPrototypeOf(e);return r===null||r===Object.prototype||Object.getPrototypeOf(r)===null?Object.prototype.toString.call(e)==="[object Object]":!1}function a(e){return e==="__proto__"}function R(e,r){const t=Object.keys(r);for(let o=0;o<t.length;o++){const n=t[o];if(a(n))continue;const i=r[n],c=e[n];d(i)&&d(c)?e[n]=R(c,i):Array.isArray(i)?e[n]=R([],i):l(i)?e[n]=R({},i):(c===void 0||i!==void 0)&&(e[n]=i)}return e}function d(e){return l(e)||Array.isArray(e)}const y=new Map;async function h(e,r){const t=`${e}-${JSON.stringify(r)}`;if(!y.has(t)){const o=fetch(e,r).then(n=>(n.ok||y.delete(t),n)).catch(n=>{throw y.delete(t),n});y.set(t,o)}return y.get(t)}function j(e){try{return!!new URL(e)}catch{return!1}}const m=/^([^[\]?]+)(\[])?(\?)?$/,f=Object.freeze({PROP_DELIMITER:".",REGEX_PROP_IS_ARR_IS_OPT:m});function p(e,r){const t=r.split(f.PROP_DELIMITER),[,o,n,i]=f.REGEX_PROP_IS_ARR_IS_OPT.exec(t.shift())||[],c=t.join(f.PROP_DELIMITER);if(!o)return e;if(!(o in e)){if(i)return n?[]:null;throw new Error(`RuntimeError: could not get property \`${o}\``)}const s=e[o];return n?s.map(u=>p(u,c)):p(s,c)}function O(e,r){const t=r.split(f.PROP_DELIMITER),[,o,n]=f.REGEX_PROP_IS_ARR_IS_OPT.exec(t.shift())||[],i=t.join(f.PROP_DELIMITER);return o?{[o]:n?e.map(c=>O(c,i)):O(e,i)}:e}async function P(e,r,t){if(!j(e))throw new Error(`InvalidArgumentError: invalid resource \`${e}\``);const o=(await h(e,t)).clone();if(!o.ok)throw new Error(`RuntimeError: could not fetch resource \`${e}\``);const n=await o.json();if(r===null)return n;const i=Object.keys(r).map(s=>({[s]:p(n,s)})),c=Object.entries(i.reduce((s,u)=>({...s,...u}),{}));return(await Promise.all(c.map(async([s,u])=>{const E=r[s],b=Array.isArray(u)?await Promise.all(u.map(async A=>P(A,E,t))):await P(u,E,t);return[s,b]}))).reduce((s,[u,E])=>R(s,O(E,u)),n)}function _(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function I(e){if(e===null)return!0;const r=Object.keys(e);return r.length?r.map(t=>!t.startsWith(f.PROP_DELIMITER)&&!t.endsWith(f.PROP_DELIMITER)&&I(e[t])).reduce((t,o)=>t&&o,!0):!1}async function w(e,r,t={}){if(!_(r)||!I(r))throw new Error(`InvalidArgumentError: invalid resolver \`${JSON.stringify(r)}\``);if(!_(t))throw new Error(`InvalidArgumentError: invalid options \`${JSON.stringify(t)}\``);return P(e,r,t)}return w}));
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.min.js","sources":["../node_modules/.pnpm/es-toolkit@1.45.1/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs","../node_modules/.pnpm/es-toolkit@1.45.1/node_modules/es-toolkit/dist/_internal/isUnsafeProperty.mjs","../node_modules/.pnpm/es-toolkit@1.45.1/node_modules/es-toolkit/dist/object/merge.mjs","../src/utils/fetchResource.ts","../src/utils/isResource.ts","../src/constants.ts","../src/utils/objectGet.ts","../src/utils/objectSet.ts","../src/resolve.ts","../src/utils/isObject.ts","../src/utils/isResolver.ts","../src/restql.ts"],"sourcesContent":["function isPlainObject(value) {\n if (!value || typeof value !== 'object') {\n return false;\n }\n const proto = Object.getPrototypeOf(value);\n const hasObjectPrototype = proto === null ||\n proto === Object.prototype ||\n Object.getPrototypeOf(proto) === null;\n if (!hasObjectPrototype) {\n return false;\n }\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\nexport { isPlainObject };\n","function isUnsafeProperty(key) {\n return key === '__proto__';\n}\n\nexport { isUnsafeProperty };\n","import { isUnsafeProperty } from '../_internal/isUnsafeProperty.mjs';\nimport { isPlainObject } from '../predicate/isPlainObject.mjs';\n\nfunction merge(target, source) {\n const sourceKeys = Object.keys(source);\n for (let i = 0; i < sourceKeys.length; i++) {\n const key = sourceKeys[i];\n if (isUnsafeProperty(key)) {\n continue;\n }\n const sourceValue = source[key];\n const targetValue = target[key];\n if (isMergeableValue(sourceValue) && isMergeableValue(targetValue)) {\n target[key] = merge(targetValue, sourceValue);\n }\n else if (Array.isArray(sourceValue)) {\n target[key] = merge([], sourceValue);\n }\n else if (isPlainObject(sourceValue)) {\n target[key] = merge({}, sourceValue);\n }\n else if (targetValue === undefined || sourceValue !== undefined) {\n target[key] = sourceValue;\n }\n }\n return target;\n}\nfunction isMergeableValue(value) {\n return isPlainObject(value) || Array.isArray(value);\n}\n\nexport { merge };\n","const responses: Record<string, Promise<Response> | Response> = {}\n\nexport default async function fetchResource(\n resource: string,\n options: RequestInit,\n): Promise<Response> {\n const key = `${resource}-${JSON.stringify(options)}`\n\n if (!(key in responses)) {\n responses[key] = fetch(resource, options).then((response) => {\n responses[key] = response\n\n return response\n })\n }\n\n return responses[key]\n}\n","export default function isResource(resource: string): boolean {\n return Boolean(URL.parse(resource))\n}\n","const PROP_DELIMITER: string = '.'\n\nconst REGEX_PROP_IS_ARR_IS_OPT: RegExp = /^([^[\\]?]+)(\\[])?(\\?)?$/\n\nconst constants = Object.freeze({\n PROP_DELIMITER,\n REGEX_PROP_IS_ARR_IS_OPT,\n})\n\nexport default constants\n","import constants from '../constants'\n\nexport default function objectGet(\n obj: Record<string, unknown>,\n props: string,\n): unknown {\n const nextPropsArr = props.split(constants.PROP_DELIMITER)\n\n const [, prop, isArr, isOpt] =\n constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()!) || []\n\n const nextProps = nextPropsArr.join(constants.PROP_DELIMITER)\n\n if (!prop) {\n return obj\n }\n\n if (!(prop in obj)) {\n if (isOpt) {\n return isArr ? [] : null\n }\n\n throw new Error(`RuntimeError: could not get property \\`${prop}\\``)\n }\n\n const nextObjs = obj[prop]\n\n return isArr\n ? (nextObjs as unknown[]).map((nextObj) =>\n objectGet(nextObj as Record<string, unknown>, nextProps),\n )\n : objectGet(nextObjs as Record<string, unknown>, nextProps)\n}\n","import constants from '../constants'\n\nexport default function objectSet(\n data: unknown,\n props: string,\n): Record<string, unknown> {\n const nextPropsArr = props.split(constants.PROP_DELIMITER)\n\n const [, prop, isArr] =\n constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()!) || []\n\n const nextProps = nextPropsArr.join(constants.PROP_DELIMITER)\n\n if (!prop) {\n return data as Record<string, unknown>\n }\n\n return {\n [prop]: isArr\n ? (data as unknown[]).map((nextData) => objectSet(nextData, nextProps))\n : objectSet(data, nextProps),\n }\n}\n","import { merge } from 'es-toolkit'\n\nimport type { Resolver } from './types'\nimport fetchResource from './utils/fetchResource'\nimport isResource from './utils/isResource'\nimport objectGet from './utils/objectGet'\nimport objectSet from './utils/objectSet'\n\nexport default async function resolve(\n resource: string,\n resolver: Resolver | null,\n options: RequestInit,\n): Promise<Record<string, unknown> | null> {\n if (!resource) {\n return null\n }\n\n if (!isResource(resource)) {\n throw new Error(`InvalidArgumentError: invalid resource \\`${resource}\\``)\n }\n\n const response = (await fetchResource(resource, options)).clone()\n\n if (!response.ok) {\n throw new Error(`RuntimeError: could not fetch resource \\`${resource}\\``)\n }\n\n const obj = await response.json()\n\n if (resolver === null) {\n return obj\n }\n\n const resourcesObj = Object.keys(resolver).map((props) => ({\n [props]: objectGet(obj, props),\n }))\n\n const resourcesArr = Object.entries(\n resourcesObj.reduce((result, val) => ({ ...result, ...val }), {}),\n )\n\n const responses = await Promise.all(\n resourcesArr.map(async ([props, resources]) => {\n const nextResolver = resolver[props]\n\n const data = Array.isArray(resources)\n ? await Promise.all(\n resources.map(async (nextResource: string) =>\n resolve(nextResource, nextResolver, options),\n ),\n )\n : await resolve(resources as string, nextResolver, options)\n\n return [props, data]\n }),\n )\n\n return responses.reduce(\n (result, [props, data]) => merge(result, objectSet(data, props as string)),\n obj,\n )\n}\n","export default function isObject(obj: unknown): boolean {\n return obj !== null && typeof obj === 'object' && !Array.isArray(obj)\n}\n","import constants from '../constants'\nimport type { Resolver } from '../types'\n\nexport default function isResolver(resolver: Resolver | null): boolean {\n if (resolver === null) {\n return true\n }\n\n const keys = Object.keys(resolver)\n\n if (!keys.length) {\n return false\n }\n\n return keys\n .map(\n (key) =>\n !key.startsWith(constants.PROP_DELIMITER) &&\n !key.endsWith(constants.PROP_DELIMITER) &&\n isResolver(resolver[key]),\n )\n .reduce((result, val) => result && val, true)\n}\n","import resolve from './resolve'\nimport type { Resolver } from './types'\nimport isObject from './utils/isObject'\nimport isResolver from './utils/isResolver'\n\nexport default async function restql<\n T extends object = Record<string, unknown>,\n>(resource: string, resolver: Resolver, options: RequestInit = {}): Promise<T> {\n if (!isObject(resolver) || !isResolver(resolver)) {\n throw new Error(\n `InvalidArgumentError: invalid resolver \\`${JSON.stringify(resolver)}\\``,\n )\n }\n\n if (!isObject(options)) {\n throw new Error(\n `InvalidArgumentError: invalid options \\`${JSON.stringify(options)}\\``,\n )\n }\n\n return resolve(resource, resolver, options) as Promise<T>\n}\n"],"names":["isPlainObject","value","proto","isUnsafeProperty","key","merge","target","source","sourceKeys","i","sourceValue","targetValue","isMergeableValue","responses","fetchResource","resource","options","response","isResource","REGEX_PROP_IS_ARR_IS_OPT","constants","objectGet","obj","props","nextPropsArr","prop","isArr","isOpt","nextProps","nextObjs","nextObj","objectSet","data","nextData","resolve","resolver","resourcesObj","resourcesArr","result","val","resources","nextResolver","nextResource","isObject","isResolver","keys","restql"],"mappings":"wNAAA,SAASA,EAAcC,EAAO,CAC1B,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC3B,MAAO,GAEX,MAAMC,EAAQ,OAAO,eAAeD,CAAK,EAIzC,OAH2BC,IAAU,MACjCA,IAAU,OAAO,WACjB,OAAO,eAAeA,CAAK,IAAM,KAI9B,OAAO,UAAU,SAAS,KAAKD,CAAK,IAAM,kBAFtC,EAGf,CCZA,SAASE,EAAiBC,EAAK,CAC3B,OAAOA,IAAQ,WACnB,CCCA,SAASC,EAAMC,EAAQC,EAAQ,CAC3B,MAAMC,EAAa,OAAO,KAAKD,CAAM,EACrC,QAASE,EAAI,EAAGA,EAAID,EAAW,OAAQC,IAAK,CACxC,MAAML,EAAMI,EAAWC,CAAC,EACxB,GAAIN,EAAiBC,CAAG,EACpB,SAEJ,MAAMM,EAAcH,EAAOH,CAAG,EACxBO,EAAcL,EAAOF,CAAG,EAC1BQ,EAAiBF,CAAW,GAAKE,EAAiBD,CAAW,EAC7DL,EAAOF,CAAG,EAAIC,EAAMM,EAAaD,CAAW,EAEvC,MAAM,QAAQA,CAAW,EAC9BJ,EAAOF,CAAG,EAAIC,EAAM,CAAA,EAAIK,CAAW,EAE9BV,EAAcU,CAAW,EAC9BJ,EAAOF,CAAG,EAAIC,EAAM,CAAA,EAAIK,CAAW,GAE9BC,IAAgB,QAAaD,IAAgB,UAClDJ,EAAOF,CAAG,EAAIM,EAEtB,CACA,OAAOJ,CACX,CACA,SAASM,EAAiBX,EAAO,CAC7B,OAAOD,EAAcC,CAAK,GAAK,MAAM,QAAQA,CAAK,CACtD,CC7BA,MAAMY,EAA0D,CAAA,EAEhE,eAA8BC,EAC5BC,EACAC,EACmB,CACnB,MAAMZ,EAAM,GAAGW,CAAQ,IAAI,KAAK,UAAUC,CAAO,CAAC,GAElD,OAAMZ,KAAOS,IACXA,EAAUT,CAAG,EAAI,MAAMW,EAAUC,CAAO,EAAE,KAAMC,IAC9CJ,EAAUT,CAAG,EAAIa,EAEVA,EACR,GAGIJ,EAAUT,CAAG,CACtB,CCjBA,SAAwBc,EAAWH,EAA2B,CAC5D,MAAO,EAAQ,IAAI,MAAMA,CAAQ,CACnC,CCFA,MAEMI,EAAmC,0BAEnCC,EAAY,OAAO,OAAO,CAC9B,eAAA,IACA,yBAAAD,CACF,CAAC,ECLD,SAAwBE,EACtBC,EACAC,EACS,CACT,MAAMC,EAAeD,EAAM,MAAMH,EAAU,cAAc,EAEnD,CAAA,CAAGK,EAAMC,EAAOC,CAAK,EACzBP,EAAU,yBAAyB,KAAKI,EAAa,MAAA,CAAQ,GAAK,CAAA,EAE9DI,EAAYJ,EAAa,KAAKJ,EAAU,cAAc,EAE5D,GAAI,CAACK,EACH,OAAOH,EAGT,GAAI,EAAEG,KAAQH,GAAM,CAClB,GAAIK,EACF,OAAOD,EAAQ,CAAA,EAAK,KAGtB,MAAM,IAAI,MAAM,0CAA0CD,CAAI,IAAI,CACpE,CAEA,MAAMI,EAAWP,EAAIG,CAAI,EAEzB,OAAOC,EACFG,EAAuB,IAAKC,GAC3BT,EAAUS,EAAoCF,CAAS,CACzD,EACAP,EAAUQ,EAAqCD,CAAS,CAC9D,CC9BA,SAAwBG,EACtBC,EACAT,EACyB,CACzB,MAAMC,EAAeD,EAAM,MAAMH,EAAU,cAAc,EAEnD,CAAA,CAAGK,EAAMC,CAAK,EAClBN,EAAU,yBAAyB,KAAKI,EAAa,OAAQ,GAAK,GAE9DI,EAAYJ,EAAa,KAAKJ,EAAU,cAAc,EAE5D,OAAKK,EAIE,CACL,CAACA,CAAI,EAAGC,EACHM,EAAmB,IAAKC,GAAaF,EAAUE,EAAUL,CAAS,CAAC,EACpEG,EAAUC,EAAMJ,CAAS,CAC/B,EAPSI,CAQX,CCdA,eAA8BE,EAC5BnB,EACAoB,EACAnB,EACyC,CACzC,GAAI,CAACD,EACH,OAAO,KAGT,GAAI,CAACG,EAAWH,CAAQ,EACtB,MAAM,IAAI,MAAM,4CAA4CA,CAAQ,IAAI,EAG1E,MAAME,GAAY,MAAMH,EAAcC,EAAUC,CAAO,GAAG,MAAA,EAE1D,GAAI,CAACC,EAAS,GACZ,MAAM,IAAI,MAAM,4CAA4CF,CAAQ,IAAI,EAG1E,MAAMO,EAAM,MAAML,EAAS,KAAA,EAE3B,GAAIkB,IAAa,KACf,OAAOb,EAGT,MAAMc,EAAe,OAAO,KAAKD,CAAQ,EAAE,IAAKZ,IAAW,CACzD,CAACA,CAAK,EAAGF,EAAUC,EAAKC,CAAK,CAC/B,EAAE,EAEIc,EAAe,OAAO,QAC1BD,EAAa,OAAO,CAACE,EAAQC,KAAS,CAAE,GAAGD,EAAQ,GAAGC,CAAI,GAAI,CAAA,CAAE,CAClE,EAkBA,OAhBkB,MAAM,QAAQ,IAC9BF,EAAa,IAAI,MAAO,CAACd,EAAOiB,CAAS,IAAM,CAC7C,MAAMC,EAAeN,EAASZ,CAAK,EAE7BS,EAAO,MAAM,QAAQQ,CAAS,EAChC,MAAM,QAAQ,IACZA,EAAU,IAAI,MAAOE,GACnBR,EAAQQ,EAAcD,EAAczB,CAAO,CAC7C,CACF,EACA,MAAMkB,EAAQM,EAAqBC,EAAczB,CAAO,EAE5D,MAAO,CAACO,EAAOS,CAAI,CACrB,CAAC,CACH,GAEiB,OACf,CAACM,EAAQ,CAACf,EAAOS,CAAI,IAAM3B,EAAMiC,EAAQP,EAAUC,EAAMT,CAAe,CAAC,EACzED,CACF,CACF,CC7DA,SAAwBqB,EAASrB,EAAuB,CACtD,OAAOA,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,CACtE,CCCA,SAAwBsB,EAAWT,EAAoC,CACrE,GAAIA,IAAa,KACf,MAAO,GAGT,MAAMU,EAAO,OAAO,KAAKV,CAAQ,EAEjC,OAAKU,EAAK,OAIHA,EACJ,IACEzC,GACC,CAACA,EAAI,WAAWgB,EAAU,cAAc,GACxC,CAAChB,EAAI,SAASgB,EAAU,cAAc,GACtCwB,EAAWT,EAAS/B,CAAG,CAAC,CAC5B,EACC,OAAO,CAACkC,EAAQC,IAAQD,GAAUC,EAAK,EAAI,EAVrC,EAWX,CCjBA,eAA8BO,EAE5B/B,EAAkBoB,EAAoBnB,EAAuB,CAAA,EAAgB,CAC7E,GAAI,CAAC2B,EAASR,CAAQ,GAAK,CAACS,EAAWT,CAAQ,EAC7C,MAAM,IAAI,MACR,4CAA4C,KAAK,UAAUA,CAAQ,CAAC,IACtE,EAGF,GAAI,CAACQ,EAAS3B,CAAO,EACnB,MAAM,IAAI,MACR,2CAA2C,KAAK,UAAUA,CAAO,CAAC,IACpE,EAGF,OAAOkB,EAAQnB,EAAUoB,EAAUnB,CAAO,CAC5C","x_google_ignoreList":[0,1,2]}
1
+ {"version":3,"file":"index.min.js","sources":["../node_modules/.pnpm/es-toolkit@1.47.0/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs","../node_modules/.pnpm/es-toolkit@1.47.0/node_modules/es-toolkit/dist/_internal/isUnsafeProperty.mjs","../node_modules/.pnpm/es-toolkit@1.47.0/node_modules/es-toolkit/dist/object/merge.mjs","../src/utils/fetchResource.ts","../src/utils/isResource.ts","../src/constants.ts","../src/utils/objectGet.ts","../src/utils/objectSet.ts","../src/resolve.ts","../src/utils/isObject.ts","../src/utils/isResolver.ts","../src/restql.ts"],"sourcesContent":["//#region src/predicate/isPlainObject.ts\n/**\n* Checks if a given value is a plain object.\n*\n* @param {object} value - The value to check.\n* @returns {value is Record<PropertyKey, any>} - True if the value is a plain object, otherwise false.\n*\n* @example\n* ```typescript\n* // ✅👇 True\n*\n* isPlainObject({ }); // ✅\n* isPlainObject({ key: 'value' }); // ✅\n* isPlainObject({ key: new Date() }); // ✅\n* isPlainObject(new Object()); // ✅\n* isPlainObject(Object.create(null)); // ✅\n* isPlainObject({ nested: { key: true} }); // ✅\n* isPlainObject(new Proxy({}, {})); // ✅\n* isPlainObject({ [Symbol('tag')]: 'A' }); // ✅\n*\n* // ✅👇 (cross-realms, node context, workers, ...)\n* const runInNewContext = await import('node:vm').then(\n* (mod) => mod.runInNewContext\n* );\n* isPlainObject(runInNewContext('({})')); // ✅\n*\n* // ❌👇 False\n*\n* class Test { };\n* isPlainObject(new Test()) // ❌\n* isPlainObject(10); // ❌\n* isPlainObject(null); // ❌\n* isPlainObject('hello'); // ❌\n* isPlainObject([]); // ❌\n* isPlainObject(new Date()); // ❌\n* isPlainObject(new Uint8Array([1])); // ❌\n* isPlainObject(Buffer.from('ABC')); // ❌\n* isPlainObject(Promise.resolve({})); // ❌\n* isPlainObject(Object.create({})); // ❌\n* isPlainObject(new (class Cls {})); // ❌\n* isPlainObject(globalThis); // ❌,\n* ```\n*/\nfunction isPlainObject(value) {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst proto = Object.getPrototypeOf(value);\n\tif (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;\n\treturn Object.prototype.toString.call(value) === \"[object Object]\";\n}\n//#endregion\nexport { isPlainObject };\n","//#region src/_internal/isUnsafeProperty.ts\n/**\n* Checks if a property key is unsafe to modify directly.\n*\n* This function is used in functions like `merge` to prevent prototype pollution attacks\n* by identifying property keys that could modify the object's prototype chain or constructor.\n*\n* @param key - The property key to check\n* @returns `true` if the property is unsafe to modify directly, `false` otherwise\n* @internal\n*/\nfunction isUnsafeProperty(key) {\n\treturn key === \"__proto__\";\n}\n//#endregion\nexport { isUnsafeProperty };\n","import { isPlainObject } from \"../predicate/isPlainObject.mjs\";\nimport { isUnsafeProperty } from \"../_internal/isUnsafeProperty.mjs\";\n//#region src/object/merge.ts\n/**\n* Merges the properties of the source object into the target object.\n*\n* This function performs a deep merge, meaning nested objects and arrays are merged recursively.\n* If a property in the source object is an array or an object and the corresponding property in the target object is also an array or object, they will be merged.\n* If a property in the source object is undefined, it will not overwrite a defined property in the target object.\n*\n* Note that this function mutates the target object.\n*\n* @param {T} target - The target object into which the source object properties will be merged. This object is modified in place.\n* @param {S} source - The source object whose properties will be merged into the target object.\n* @returns {T & S} The updated target object with properties from the source object merged in.\n*\n* @template T - Type of the target object.\n* @template S - Type of the source object.\n*\n* @example\n* const target = { a: 1, b: { x: 1, y: 2 } };\n* const source = { b: { y: 3, z: 4 }, c: 5 };\n*\n* const result = merge(target, source);\n* console.log(result);\n* // Output: { a: 1, b: { x: 1, y: 3, z: 4 }, c: 5 }\n*\n* @example\n* const target = { a: [1, 2], b: { x: 1 } };\n* const source = { a: [3], b: { y: 2 } };\n*\n* const result = merge(target, source);\n* console.log(result);\n* // Output: { a: [3, 2], b: { x: 1, y: 2 } }\n*\n* @example\n* const target = { a: null };\n* const source = { a: [1, 2, 3] };\n*\n* const result = merge(target, source);\n* console.log(result);\n* // Output: { a: [1, 2, 3] }\n*/\nfunction merge(target, source) {\n\tconst sourceKeys = Object.keys(source);\n\tfor (let i = 0; i < sourceKeys.length; i++) {\n\t\tconst key = sourceKeys[i];\n\t\tif (isUnsafeProperty(key)) continue;\n\t\tconst sourceValue = source[key];\n\t\tconst targetValue = target[key];\n\t\tif (isMergeableValue(sourceValue) && isMergeableValue(targetValue)) target[key] = merge(targetValue, sourceValue);\n\t\telse if (Array.isArray(sourceValue)) target[key] = merge([], sourceValue);\n\t\telse if (isPlainObject(sourceValue)) target[key] = merge({}, sourceValue);\n\t\telse if (targetValue === void 0 || sourceValue !== void 0) target[key] = sourceValue;\n\t}\n\treturn target;\n}\nfunction isMergeableValue(value) {\n\treturn isPlainObject(value) || Array.isArray(value);\n}\n//#endregion\nexport { merge };\n","const responses = new Map<string, Promise<Response>>()\n\nexport default async function fetchResource(\n resource: string,\n options: RequestInit,\n): Promise<Response> {\n const key = `${resource}-${JSON.stringify(options)}`\n\n if (!responses.has(key)) {\n const response = fetch(resource, options)\n .then((nextResponse: Response) => {\n if (!nextResponse.ok) {\n responses.delete(key)\n }\n\n return nextResponse\n })\n .catch((error: Error) => {\n responses.delete(key)\n\n throw error\n })\n\n responses.set(key, response)\n }\n\n return responses.get(key) as Promise<Response>\n}\n","export default function isResource(resource: string): boolean {\n try {\n return Boolean(new URL(resource))\n } catch {\n return false\n }\n}\n","const PROP_DELIMITER: string = '.'\n\nconst REGEX_PROP_IS_ARR_IS_OPT: RegExp = /^([^[\\]?]+)(\\[])?(\\?)?$/\n\nconst constants = Object.freeze({\n PROP_DELIMITER,\n REGEX_PROP_IS_ARR_IS_OPT,\n})\n\nexport default constants\n","import constants from '../constants'\n\nexport default function objectGet(\n obj: Record<string, unknown>,\n props: string,\n): unknown {\n const nextPropsArr = props.split(constants.PROP_DELIMITER)\n\n const [, prop, isArr, isOpt] =\n constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()!) || []\n\n const nextProps = nextPropsArr.join(constants.PROP_DELIMITER)\n\n if (!prop) {\n return obj\n }\n\n if (!(prop in obj)) {\n if (isOpt) {\n return isArr ? [] : null\n }\n\n throw new Error(`RuntimeError: could not get property \\`${prop}\\``)\n }\n\n const nextObjs = obj[prop]\n\n return isArr\n ? (nextObjs as unknown[]).map((nextObj) =>\n objectGet(nextObj as Record<string, unknown>, nextProps),\n )\n : objectGet(nextObjs as Record<string, unknown>, nextProps)\n}\n","import constants from '../constants'\n\nexport default function objectSet(\n data: unknown,\n props: string,\n): Record<string, unknown> {\n const nextPropsArr = props.split(constants.PROP_DELIMITER)\n\n const [, prop, isArr] =\n constants.REGEX_PROP_IS_ARR_IS_OPT.exec(nextPropsArr.shift()!) || []\n\n const nextProps = nextPropsArr.join(constants.PROP_DELIMITER)\n\n if (!prop) {\n return data as Record<string, unknown>\n }\n\n return {\n [prop]: isArr\n ? (data as unknown[]).map((nextData) => objectSet(nextData, nextProps))\n : objectSet(data, nextProps),\n }\n}\n","import { merge } from 'es-toolkit'\n\nimport type { Resolver } from './types'\nimport fetchResource from './utils/fetchResource'\nimport isResource from './utils/isResource'\nimport objectGet from './utils/objectGet'\nimport objectSet from './utils/objectSet'\n\nexport default async function resolve(\n resource: string,\n resolver: Resolver | null,\n options: RequestInit,\n): Promise<Record<string, unknown> | null> {\n if (!isResource(resource)) {\n throw new Error(`InvalidArgumentError: invalid resource \\`${resource}\\``)\n }\n\n const response = (await fetchResource(resource, options)).clone()\n\n if (!response.ok) {\n throw new Error(`RuntimeError: could not fetch resource \\`${resource}\\``)\n }\n\n const obj = await response.json()\n\n if (resolver === null) {\n return obj\n }\n\n const resourcesObj = Object.keys(resolver).map((props) => ({\n [props]: objectGet(obj, props),\n }))\n\n const resourcesArr = Object.entries(\n resourcesObj.reduce((result, val) => ({ ...result, ...val }), {}),\n )\n\n const responses = await Promise.all(\n resourcesArr.map(async ([props, resources]) => {\n const nextResolver = resolver[props]\n\n const data = Array.isArray(resources)\n ? await Promise.all(\n resources.map(async (nextResource: string) =>\n resolve(nextResource, nextResolver, options),\n ),\n )\n : await resolve(resources as string, nextResolver, options)\n\n return [props, data]\n }),\n )\n\n return responses.reduce(\n (result, [props, data]) => merge(result, objectSet(data, props as string)),\n obj,\n )\n}\n","export default function isObject(obj: unknown): boolean {\n return obj !== null && typeof obj === 'object' && !Array.isArray(obj)\n}\n","import constants from '../constants'\nimport type { Resolver } from '../types'\n\nexport default function isResolver(resolver: Resolver | null): boolean {\n if (resolver === null) {\n return true\n }\n\n const keys = Object.keys(resolver)\n\n if (!keys.length) {\n return false\n }\n\n return keys\n .map(\n (key) =>\n !key.startsWith(constants.PROP_DELIMITER) &&\n !key.endsWith(constants.PROP_DELIMITER) &&\n isResolver(resolver[key]),\n )\n .reduce((result, val) => result && val, true)\n}\n","import resolve from './resolve'\nimport type { Resolver } from './types'\nimport isObject from './utils/isObject'\nimport isResolver from './utils/isResolver'\n\nexport default async function restql<\n T extends object = Record<string, unknown>,\n>(resource: string, resolver: Resolver, options: RequestInit = {}): Promise<T> {\n if (!isObject(resolver) || !isResolver(resolver)) {\n throw new Error(\n `InvalidArgumentError: invalid resolver \\`${JSON.stringify(resolver)}\\``,\n )\n }\n\n if (!isObject(options)) {\n throw new Error(\n `InvalidArgumentError: invalid options \\`${JSON.stringify(options)}\\``,\n )\n }\n\n return resolve(resource, resolver, options) as Promise<T>\n}\n"],"names":["isPlainObject","value","proto","isUnsafeProperty","key","merge","target","source","sourceKeys","i","sourceValue","targetValue","isMergeableValue","responses","fetchResource","resource","options","response","nextResponse","error","isResource","REGEX_PROP_IS_ARR_IS_OPT","constants","objectGet","obj","props","nextPropsArr","prop","isArr","isOpt","nextProps","nextObjs","nextObj","objectSet","data","nextData","resolve","resolver","resourcesObj","resourcesArr","result","val","resources","nextResolver","nextResource","isObject","isResolver","keys","restql"],"mappings":"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","x_google_ignoreList":[0,1,2]}
package/dist/index.mjs CHANGED
@@ -1,19 +1,29 @@
1
1
  import { merge } from 'es-toolkit';
2
2
 
3
- const responses = {};
3
+ const responses = /* @__PURE__ */ new Map();
4
4
  async function fetchResource(resource, options) {
5
5
  const key = `${resource}-${JSON.stringify(options)}`;
6
- if (!(key in responses)) {
7
- responses[key] = fetch(resource, options).then((response) => {
8
- responses[key] = response;
9
- return response;
6
+ if (!responses.has(key)) {
7
+ const response = fetch(resource, options).then((nextResponse) => {
8
+ if (!nextResponse.ok) {
9
+ responses.delete(key);
10
+ }
11
+ return nextResponse;
12
+ }).catch((error) => {
13
+ responses.delete(key);
14
+ throw error;
10
15
  });
16
+ responses.set(key, response);
11
17
  }
12
- return responses[key];
18
+ return responses.get(key);
13
19
  }
14
20
 
15
21
  function isResource(resource) {
16
- return Boolean(URL.parse(resource));
22
+ try {
23
+ return Boolean(new URL(resource));
24
+ } catch {
25
+ return false;
26
+ }
17
27
  }
18
28
 
19
29
  const PROP_DELIMITER = ".";
@@ -55,9 +65,6 @@ function objectSet(data, props) {
55
65
  }
56
66
 
57
67
  async function resolve(resource, resolver, options) {
58
- if (!resource) {
59
- return null;
60
- }
61
68
  if (!isResource(resource)) {
62
69
  throw new Error(`InvalidArgumentError: invalid resource \`${resource}\``);
63
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "restql",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "RESTful API Resolver for Nested-Linked Resources | 🕸 🕷",
5
5
  "type": "module",
6
6
  "unpkg": "./dist/index.js",
@@ -54,32 +54,29 @@
54
54
  },
55
55
  "homepage": "https://github.com/relztic/restql#readme",
56
56
  "dependencies": {
57
- "es-toolkit": "^1.44.0"
57
+ "es-toolkit": "^1.47.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@rollup/plugin-node-resolve": "^16.0.3",
61
61
  "@trivago/prettier-plugin-sort-imports": "^6.0.2",
62
62
  "@types/jest": "^30.0.0",
63
- "@types/node": "^25.5.2",
64
- "eslint": "^10.0.3",
63
+ "@types/node": "^25.9.1",
64
+ "eslint": "^10.4.0",
65
65
  "eslint-config-prettier": "^10.1.8",
66
66
  "eslint-flat-config-airbnb": "^2.0.5",
67
67
  "eslint-import-resolver-typescript": "^4.4.4",
68
- "eslint-plugin-jest": "^29.15.0",
68
+ "eslint-plugin-jest": "^29.15.2",
69
69
  "eslint-plugin-prettier": "^5.5.5",
70
- "globals": "^17.3.0",
71
- "jest": "^30.2.0",
72
- "prettier": "^3.8.1",
73
- "rollup": "^4.59.0",
74
- "rollup-plugin-dts": "^6.3.0",
70
+ "globals": "^17.6.0",
71
+ "jest": "^30.4.2",
72
+ "prettier": "^3.8.3",
73
+ "rollup": "^4.60.4",
74
+ "rollup-plugin-dts": "^6.4.1",
75
75
  "rollup-plugin-esbuild": "^6.2.1",
76
- "rollup-plugin-visualizer": "^7.0.0",
77
- "ts-jest": "^29.4.6",
78
- "tsx": "^4.21.0",
79
- "typescript": "^5.9.3",
80
- "typescript-eslint": "^8.56.1"
81
- },
82
- "overrides": {
83
- "serialize-javascript": "^7.0.3"
76
+ "rollup-plugin-visualizer": "^7.0.1",
77
+ "ts-jest": "^29.4.11",
78
+ "tsx": "^4.22.3",
79
+ "typescript": "^6.0.3",
80
+ "typescript-eslint": "^8.60.0"
84
81
  }
85
82
  }