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 +4 -4
- package/dist/index.cjs +17 -10
- package/dist/index.js +246 -161
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +17 -10
- package/package.json +15 -18
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
|
-
####
|
|
18
|
+
#### NPM
|
|
19
19
|
|
|
20
20
|
```sh
|
|
21
21
|
npm install restql
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
####
|
|
24
|
+
#### Yarn
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
27
|
yarn add restql
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
####
|
|
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
|
-
####
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
20
|
+
return responses.get(key);
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
function isResource(resource) {
|
|
18
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
149
|
+
function isResource(resource) {
|
|
150
|
+
try {
|
|
151
|
+
return Boolean(new URL(resource));
|
|
152
|
+
} catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
68
156
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
230
|
+
function isObject(obj) {
|
|
231
|
+
return obj !== null && typeof obj === "object" && !Array.isArray(obj);
|
|
232
|
+
}
|
|
148
233
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
|
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
|
package/dist/index.min.js.map
CHANGED
|
@@ -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":"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","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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
18
|
+
return responses.get(key);
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
function isResource(resource) {
|
|
16
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
64
|
-
"eslint": "^10.0
|
|
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.
|
|
68
|
+
"eslint-plugin-jest": "^29.15.2",
|
|
69
69
|
"eslint-plugin-prettier": "^5.5.5",
|
|
70
|
-
"globals": "^17.
|
|
71
|
-
"jest": "^30.2
|
|
72
|
-
"prettier": "^3.8.
|
|
73
|
-
"rollup": "^4.
|
|
74
|
-
"rollup-plugin-dts": "^6.
|
|
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.
|
|
77
|
-
"ts-jest": "^29.4.
|
|
78
|
-
"tsx": "^4.
|
|
79
|
-
"typescript": "^
|
|
80
|
-
"typescript-eslint": "^8.
|
|
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
|
}
|