@scarif/scarif-js 1.0.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 +451 -0
- package/dist/client.d.ts +33 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +145 -0
- package/dist/constants.d.ts +25 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +26 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/types/api.d.ts +37 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +20 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +27 -0
- package/dist/types/queries.d.ts +53 -0
- package/dist/types/queries.d.ts.map +1 -0
- package/dist/types/queries.js +5 -0
- package/dist/types/tables.d.ts +13 -0
- package/dist/types/tables.d.ts.map +1 -0
- package/dist/types/tables.js +6 -0
- package/dist/types/types.d.ts +22 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +12 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/utils/query-builder.d.ts +84 -0
- package/dist/utils/query-builder.d.ts.map +1 -0
- package/dist/utils/query-builder.js +336 -0
- package/dist/utils/select-parser.d.ts +28 -0
- package/dist/utils/select-parser.d.ts.map +1 -0
- package/dist/utils/select-parser.js +84 -0
- package/package.json +44 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueryBuilderImpl = void 0;
|
|
4
|
+
exports.buildQueryString = buildQueryString;
|
|
5
|
+
const select_parser_1 = require("./select-parser");
|
|
6
|
+
/**
|
|
7
|
+
* Chainable query builder implementation
|
|
8
|
+
*/
|
|
9
|
+
class QueryBuilderImpl {
|
|
10
|
+
constructor(table, executeFn) {
|
|
11
|
+
this.table = table;
|
|
12
|
+
this.executeFn = executeFn;
|
|
13
|
+
this.state = {
|
|
14
|
+
filters: {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// ===========================================
|
|
18
|
+
// VALIDATION HELPERS
|
|
19
|
+
// ===========================================
|
|
20
|
+
/**
|
|
21
|
+
* Validates that a number is non-negative
|
|
22
|
+
*/
|
|
23
|
+
validateNonNegative(value, paramName) {
|
|
24
|
+
if (value < 0) {
|
|
25
|
+
throw new Error(`${paramName} must be non-negative, got ${value}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates that a value is not null or undefined
|
|
30
|
+
*/
|
|
31
|
+
validateNotNull(value, paramName) {
|
|
32
|
+
if (value === null || value === undefined) {
|
|
33
|
+
throw new Error(`${paramName} cannot be null or undefined`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validates that an array is not empty
|
|
38
|
+
*/
|
|
39
|
+
validateNonEmptyArray(arr, paramName) {
|
|
40
|
+
if (!Array.isArray(arr)) {
|
|
41
|
+
throw new Error(`${paramName} must be an array`);
|
|
42
|
+
}
|
|
43
|
+
if (arr.length === 0) {
|
|
44
|
+
throw new Error(`${paramName} cannot be an empty array`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validates column name is a non-empty string
|
|
49
|
+
*/
|
|
50
|
+
validateColumnName(column, paramName = 'column') {
|
|
51
|
+
if (typeof column !== 'string' || column.trim().length === 0) {
|
|
52
|
+
throw new Error(`${paramName} must be a non-empty string`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ===========================================
|
|
56
|
+
// SELECTION
|
|
57
|
+
// ===========================================
|
|
58
|
+
select(query) {
|
|
59
|
+
const parsed = (0, select_parser_1.parseSupabaseSelect)(query);
|
|
60
|
+
// Map parsed result to QueryState format
|
|
61
|
+
// Convert tableName to table for ParsedRelation
|
|
62
|
+
this.state.select = {
|
|
63
|
+
primaryColumns: parsed.primaryColumns,
|
|
64
|
+
associatedTables: parsed.associatedTables.map(t => ({
|
|
65
|
+
table: t.tableName,
|
|
66
|
+
columns: t.columns
|
|
67
|
+
}))
|
|
68
|
+
};
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
// ===========================================
|
|
72
|
+
// FILTERS
|
|
73
|
+
// ===========================================
|
|
74
|
+
/**
|
|
75
|
+
* Helper method to add object-based filters (eq, neq, gt, etc.)
|
|
76
|
+
*/
|
|
77
|
+
addObjectFilter(key, column, value) {
|
|
78
|
+
this.validateColumnName(column);
|
|
79
|
+
this.validateNotNull(value, `Filter value for ${column}`);
|
|
80
|
+
if (!this.state.filters[key]) {
|
|
81
|
+
this.state.filters[key] = {};
|
|
82
|
+
}
|
|
83
|
+
this.state.filters[key][column] = value;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Helper method to add array-based filters (in, notIn)
|
|
88
|
+
*/
|
|
89
|
+
addArrayFilter(key, column, values) {
|
|
90
|
+
this.validateColumnName(column);
|
|
91
|
+
this.validateNonEmptyArray(values, `Filter values for ${column}`);
|
|
92
|
+
if (!this.state.filters[key]) {
|
|
93
|
+
this.state.filters[key] = {};
|
|
94
|
+
}
|
|
95
|
+
this.state.filters[key][column] = values.map(String);
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Helper method to add column list filters (isNull, isNotNull)
|
|
100
|
+
*/
|
|
101
|
+
addColumnListFilter(key, column) {
|
|
102
|
+
this.validateColumnName(column);
|
|
103
|
+
if (!this.state.filters[key]) {
|
|
104
|
+
this.state.filters[key] = [];
|
|
105
|
+
}
|
|
106
|
+
this.state.filters[key].push(column);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
eq(column, value) {
|
|
110
|
+
return this.addObjectFilter('eq', column, value);
|
|
111
|
+
}
|
|
112
|
+
neq(column, value) {
|
|
113
|
+
return this.addObjectFilter('neq', column, value);
|
|
114
|
+
}
|
|
115
|
+
gt(column, value) {
|
|
116
|
+
return this.addObjectFilter('gt', column, value);
|
|
117
|
+
}
|
|
118
|
+
gte(column, value) {
|
|
119
|
+
return this.addObjectFilter('gte', column, value);
|
|
120
|
+
}
|
|
121
|
+
lt(column, value) {
|
|
122
|
+
return this.addObjectFilter('lt', column, value);
|
|
123
|
+
}
|
|
124
|
+
lte(column, value) {
|
|
125
|
+
return this.addObjectFilter('lte', column, value);
|
|
126
|
+
}
|
|
127
|
+
like(column, value) {
|
|
128
|
+
return this.addObjectFilter('like', column, value);
|
|
129
|
+
}
|
|
130
|
+
ilike(column, value) {
|
|
131
|
+
return this.addObjectFilter('ilike', column, value);
|
|
132
|
+
}
|
|
133
|
+
in(column, values) {
|
|
134
|
+
return this.addArrayFilter('in', column, values);
|
|
135
|
+
}
|
|
136
|
+
notIn(column, values) {
|
|
137
|
+
return this.addArrayFilter('notIn', column, values);
|
|
138
|
+
}
|
|
139
|
+
isNull(column) {
|
|
140
|
+
return this.addColumnListFilter('isNull', column);
|
|
141
|
+
}
|
|
142
|
+
isNotNull(column) {
|
|
143
|
+
return this.addColumnListFilter('isNotNull', column);
|
|
144
|
+
}
|
|
145
|
+
// ===========================================
|
|
146
|
+
// ORDERING
|
|
147
|
+
// ===========================================
|
|
148
|
+
order(column, direction = 'asc') {
|
|
149
|
+
this.validateColumnName(column, 'order column');
|
|
150
|
+
if (!this.state.order)
|
|
151
|
+
this.state.order = [];
|
|
152
|
+
this.state.order.push({ column, direction });
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
// ===========================================
|
|
156
|
+
// PAGINATION
|
|
157
|
+
// ===========================================
|
|
158
|
+
limit(count) {
|
|
159
|
+
this.validateNonNegative(count, 'limit');
|
|
160
|
+
this.state.limit = count;
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
offset(count) {
|
|
164
|
+
this.validateNonNegative(count, 'offset');
|
|
165
|
+
this.state.offset = count;
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
range(from, to) {
|
|
169
|
+
this.validateNonNegative(from, 'range start');
|
|
170
|
+
this.validateNonNegative(to, 'range end');
|
|
171
|
+
if (to < from) {
|
|
172
|
+
throw new Error(`range end (${to}) must be >= range start (${from})`);
|
|
173
|
+
}
|
|
174
|
+
this.state.offset = from;
|
|
175
|
+
// Calculate limit: to is exclusive (like array.slice), so limit = to - from
|
|
176
|
+
this.state.limit = to - from;
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
// ===========================================
|
|
180
|
+
// RESPONSE MODIFIERS
|
|
181
|
+
// ===========================================
|
|
182
|
+
single() {
|
|
183
|
+
this.state.single = true;
|
|
184
|
+
// Only set limit if not already set to avoid overwriting user's limit()
|
|
185
|
+
if (this.state.limit === undefined) {
|
|
186
|
+
this.state.limit = 1;
|
|
187
|
+
}
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
// ===========================================
|
|
191
|
+
// THENABLE INTERFACE
|
|
192
|
+
// ===========================================
|
|
193
|
+
then(onfulfilled, onrejected) {
|
|
194
|
+
// Enforce required select()
|
|
195
|
+
if (!this.state.select) {
|
|
196
|
+
const error = new Error("select() is required. Use .select('*') to select all columns.");
|
|
197
|
+
return Promise.reject(error);
|
|
198
|
+
}
|
|
199
|
+
// Create the base promise from executeFn
|
|
200
|
+
const basePromise = this.executeFn(this.table, this.state);
|
|
201
|
+
// Transform the response based on single flag
|
|
202
|
+
const transformedPromise = basePromise.then(response => {
|
|
203
|
+
if (this.state.single) {
|
|
204
|
+
// Handle single result
|
|
205
|
+
if (response.error) {
|
|
206
|
+
return response;
|
|
207
|
+
}
|
|
208
|
+
const data = Array.isArray(response.data) && response.data.length > 0
|
|
209
|
+
? response.data[0]
|
|
210
|
+
: null;
|
|
211
|
+
return {
|
|
212
|
+
...response,
|
|
213
|
+
data
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return response;
|
|
217
|
+
});
|
|
218
|
+
// Always chain the handlers (Promise.then works with undefined handlers)
|
|
219
|
+
return transformedPromise.then(onfulfilled, onrejected);
|
|
220
|
+
}
|
|
221
|
+
catch(onrejected) {
|
|
222
|
+
return this.then().catch(onrejected);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.QueryBuilderImpl = QueryBuilderImpl;
|
|
226
|
+
// ===========================================
|
|
227
|
+
// QUERY STRING BUILDER
|
|
228
|
+
// ===========================================
|
|
229
|
+
/**
|
|
230
|
+
* Helper function to add object-based filter parameters to URLSearchParams
|
|
231
|
+
*/
|
|
232
|
+
function addObjectFilterParams(params, filter, filterType) {
|
|
233
|
+
if (filter) {
|
|
234
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
235
|
+
params.append(`${key}[${filterType}]`, String(value));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Helper function to add array-based filter parameters to URLSearchParams
|
|
241
|
+
*/
|
|
242
|
+
function addArrayFilterParams(params, filter, filterType) {
|
|
243
|
+
if (filter) {
|
|
244
|
+
for (const [key, values] of Object.entries(filter)) {
|
|
245
|
+
params.append(`${key}[${filterType}]`, values.join(','));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Helper function to add column list filter parameters to URLSearchParams
|
|
251
|
+
*/
|
|
252
|
+
function addColumnListFilterParams(params, columns, filterType) {
|
|
253
|
+
if (columns) {
|
|
254
|
+
for (const column of columns) {
|
|
255
|
+
params.append(`${column}[${filterType}]`, 'true');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Builds URL query string from QueryState
|
|
261
|
+
*
|
|
262
|
+
* Transforms the internal QueryState structure into URL query parameters
|
|
263
|
+
* following the API's expected format:
|
|
264
|
+
* - Select columns: `select=col1,col2`
|
|
265
|
+
* - Relations: `with=table(col1,col2)`
|
|
266
|
+
* - Filters: `column[filterType]=value`
|
|
267
|
+
* - Ordering: `order=column.direction`
|
|
268
|
+
* - Pagination: `limit=N&offset=N`
|
|
269
|
+
*
|
|
270
|
+
* @param state - The query state containing all filters, selections, and modifiers
|
|
271
|
+
* @returns Query string with leading '?' if params exist, empty string otherwise
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* const state: QueryState = {
|
|
276
|
+
* select: { primaryColumns: ['id', 'name'], associatedTables: [] },
|
|
277
|
+
* filters: { eq: { status: 'active' } },
|
|
278
|
+
* limit: 10
|
|
279
|
+
* };
|
|
280
|
+
* buildQueryString(state); // "?select=id,name&status[eq]=active&limit=10"
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
function buildQueryString(state) {
|
|
284
|
+
const params = new URLSearchParams();
|
|
285
|
+
// Select columns and relations (transformed from parsed select)
|
|
286
|
+
if (state.select) {
|
|
287
|
+
// Primary columns
|
|
288
|
+
if (state.select.primaryColumns.length > 0) {
|
|
289
|
+
params.append('select', state.select.primaryColumns.join(','));
|
|
290
|
+
}
|
|
291
|
+
// Associated tables as 'with' parameters
|
|
292
|
+
if (state.select.associatedTables.length > 0) {
|
|
293
|
+
for (const relation of state.select.associatedTables) {
|
|
294
|
+
if (relation.columns && relation.columns.length > 0) {
|
|
295
|
+
params.append('with', `${relation.table}(${relation.columns.join(',')})`);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
params.append('with', relation.table);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Filters - object-based filters
|
|
304
|
+
const { filters } = state;
|
|
305
|
+
addObjectFilterParams(params, filters.eq, 'eq');
|
|
306
|
+
addObjectFilterParams(params, filters.neq, 'neq');
|
|
307
|
+
addObjectFilterParams(params, filters.gt, 'gt');
|
|
308
|
+
addObjectFilterParams(params, filters.gte, 'gte');
|
|
309
|
+
addObjectFilterParams(params, filters.lt, 'lt');
|
|
310
|
+
addObjectFilterParams(params, filters.lte, 'lte');
|
|
311
|
+
addObjectFilterParams(params, filters.like, 'like');
|
|
312
|
+
addObjectFilterParams(params, filters.ilike, 'ilike');
|
|
313
|
+
// Filters - array-based filters
|
|
314
|
+
addArrayFilterParams(params, filters.in, 'in');
|
|
315
|
+
addArrayFilterParams(params, filters.notIn, 'notIn');
|
|
316
|
+
// Filters - column list filters
|
|
317
|
+
addColumnListFilterParams(params, filters.isNull, 'isNull');
|
|
318
|
+
addColumnListFilterParams(params, filters.isNotNull, 'isNotNull');
|
|
319
|
+
// Order
|
|
320
|
+
if (state.order && state.order.length > 0) {
|
|
321
|
+
const orderStr = state.order
|
|
322
|
+
.map(o => `${o.column}.${o.direction}`)
|
|
323
|
+
.join(',');
|
|
324
|
+
params.append('order', orderStr);
|
|
325
|
+
}
|
|
326
|
+
// Limit
|
|
327
|
+
if (state.limit !== undefined) {
|
|
328
|
+
params.append('limit', String(state.limit));
|
|
329
|
+
}
|
|
330
|
+
// Offset
|
|
331
|
+
if (state.offset !== undefined) {
|
|
332
|
+
params.append('offset', String(state.offset));
|
|
333
|
+
}
|
|
334
|
+
const queryString = params.toString();
|
|
335
|
+
return queryString ? `?${queryString}` : '';
|
|
336
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of parsing a Supabase-style select query string
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedQuery {
|
|
5
|
+
primaryColumns: string[];
|
|
6
|
+
associatedTables: {
|
|
7
|
+
tableName: string;
|
|
8
|
+
columns: string[];
|
|
9
|
+
}[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parses a Supabase/PostgREST-style select query string into structured data
|
|
13
|
+
*
|
|
14
|
+
* @param selectQuery - Select query string (e.g., "id, name, posts(title, content)")
|
|
15
|
+
* @returns Parsed query with primary columns and associated tables
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* parseSupabaseSelect('id, name, posts(title, content)')
|
|
20
|
+
* // Returns:
|
|
21
|
+
* // {
|
|
22
|
+
* // primaryColumns: ['id', 'name'],
|
|
23
|
+
* // associatedTables: [{ tableName: 'posts', columns: ['title', 'content'] }]
|
|
24
|
+
* // }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseSupabaseSelect(selectQuery: string): ParsedQuery;
|
|
28
|
+
//# sourceMappingURL=select-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-parser.d.ts","sourceRoot":"","sources":["../../src/utils/select-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,EAAE,CAAC;CACL;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAqEpE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSupabaseSelect = parseSupabaseSelect;
|
|
4
|
+
/**
|
|
5
|
+
* Parses a Supabase/PostgREST-style select query string into structured data
|
|
6
|
+
*
|
|
7
|
+
* @param selectQuery - Select query string (e.g., "id, name, posts(title, content)")
|
|
8
|
+
* @returns Parsed query with primary columns and associated tables
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* parseSupabaseSelect('id, name, posts(title, content)')
|
|
13
|
+
* // Returns:
|
|
14
|
+
* // {
|
|
15
|
+
* // primaryColumns: ['id', 'name'],
|
|
16
|
+
* // associatedTables: [{ tableName: 'posts', columns: ['title', 'content'] }]
|
|
17
|
+
* // }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function parseSupabaseSelect(selectQuery) {
|
|
21
|
+
// Remove extra whitespace and newlines
|
|
22
|
+
const normalized = selectQuery.replace(/\s+/g, ' ').trim();
|
|
23
|
+
const result = {
|
|
24
|
+
primaryColumns: [],
|
|
25
|
+
associatedTables: []
|
|
26
|
+
};
|
|
27
|
+
let i = 0;
|
|
28
|
+
let currentToken = '';
|
|
29
|
+
let parenDepth = 0;
|
|
30
|
+
while (i < normalized.length) {
|
|
31
|
+
const char = normalized[i];
|
|
32
|
+
if (char === '(') {
|
|
33
|
+
parenDepth++;
|
|
34
|
+
if (parenDepth === 1 && currentToken.trim()) {
|
|
35
|
+
// Start of associated table
|
|
36
|
+
const tableName = currentToken.trim();
|
|
37
|
+
i++; // Skip opening paren
|
|
38
|
+
// Extract content within parentheses
|
|
39
|
+
let tableContent = '';
|
|
40
|
+
let depth = 1;
|
|
41
|
+
while (i < normalized.length && depth > 0) {
|
|
42
|
+
if (normalized[i] === '(')
|
|
43
|
+
depth++;
|
|
44
|
+
if (normalized[i] === ')')
|
|
45
|
+
depth--;
|
|
46
|
+
if (depth > 0)
|
|
47
|
+
tableContent += normalized[i];
|
|
48
|
+
i++;
|
|
49
|
+
}
|
|
50
|
+
// Parse columns for this table
|
|
51
|
+
const columns = tableContent
|
|
52
|
+
.split(',')
|
|
53
|
+
.map(col => col.trim())
|
|
54
|
+
.filter(col => col.length > 0);
|
|
55
|
+
result.associatedTables.push({
|
|
56
|
+
tableName,
|
|
57
|
+
columns
|
|
58
|
+
});
|
|
59
|
+
currentToken = '';
|
|
60
|
+
parenDepth = 0;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else if (char === ',') {
|
|
65
|
+
if (parenDepth === 0 && currentToken.trim()) {
|
|
66
|
+
// Primary column
|
|
67
|
+
result.primaryColumns.push(currentToken.trim());
|
|
68
|
+
currentToken = '';
|
|
69
|
+
}
|
|
70
|
+
else if (parenDepth > 0) {
|
|
71
|
+
currentToken += char;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
currentToken += char;
|
|
76
|
+
}
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
// Add last token if it exists and we're not in parentheses
|
|
80
|
+
if (currentToken.trim() && parenDepth === 0) {
|
|
81
|
+
result.primaryColumns.push(currentToken.trim());
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scarif/scarif-js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A TypeScript SDK for Scarif API services",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"\"api",
|
|
7
|
+
"sdk",
|
|
8
|
+
"data\""
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/GeneralTyres/stoorplek-sdk#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/GeneralTyres/stoorplek-sdk/issues"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/GeneralTyres/stoorplek-sdk.git"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "GeneralTyres",
|
|
20
|
+
"type": "commonjs",
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"directories": {
|
|
24
|
+
"doc": "docs"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"prepare": "npm run build",
|
|
33
|
+
"test": "echo \"No tests yet\"",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"type-check": "tsc --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"undici-types": "^7.16.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^25.0.7",
|
|
42
|
+
"typescript": "^5.9.3"
|
|
43
|
+
}
|
|
44
|
+
}
|