@nyaomaru/divider 1.9.18 → 1.9.20

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
@@ -209,9 +209,22 @@ Some common use cases are wrapped as presets for convenience.
209
209
  | `emailDivider` | Divide email into [local-part, domain] (by '@') |
210
210
  | `csvDivider` | Divide comma-separated strings, with quoted field support |
211
211
  | `pathDivider` | Divide file paths by / or \| |
212
+ | `queryDivider` | Divide query strings into [key, value] pairs (URL-safe) |
212
213
 
213
214
  [Presets detail](src/presets/README.md)
214
215
 
216
+ Example:
217
+
218
+ ```ts
219
+ import { queryDivider } from '@nyaomaru/divider';
220
+
221
+ queryDivider('?q=hello+world');
222
+ // [['q', 'hello world']] // default: '+' treated as space and % decoded
223
+
224
+ queryDivider('q=hello+world', { mode: 'raw' });
225
+ // [['q', 'hello+world']] // raw mode keeps '+' and % as-is
226
+ ```
227
+
215
228
  ## 🎯 General Options
216
229
 
217
230
  | Option | Type | Default | Description |
package/dist/index.cjs CHANGED
@@ -27,7 +27,8 @@ __export(index_exports, {
27
27
  dividerLoop: () => dividerLoop,
28
28
  dividerNumberString: () => dividerNumberString,
29
29
  emailDivider: () => emailDivider,
30
- pathDivider: () => pathDivider
30
+ pathDivider: () => pathDivider,
31
+ queryDivider: () => queryDivider
31
32
  });
32
33
  module.exports = __toCommonJS(index_exports);
33
34
 
@@ -60,6 +61,15 @@ var PATH_SEPARATORS = {
60
61
  SLASH: "/",
61
62
  ALT: "|"
62
63
  };
64
+ var QUERY_SEPARATORS = {
65
+ QUESTION_MARK: "?",
66
+ AMPERSAND: "&",
67
+ EQUALS: "="
68
+ };
69
+ var QUERY_DECODE_MODES = {
70
+ AUTO: "auto",
71
+ RAW: "raw"
72
+ };
63
73
 
64
74
  // src/utils/is.ts
65
75
  function isString(value) {
@@ -509,6 +519,45 @@ function pathDivider(input, options = {}) {
509
519
  const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
510
520
  return collapse ? maybeTrimmed.filter((segment) => !isEmptyString(segment)) : maybeTrimmed;
511
521
  }
522
+
523
+ // src/presets/query-divider.ts
524
+ function tryExtractQuery(input) {
525
+ try {
526
+ const url = new URL(input);
527
+ return url.search.startsWith(QUERY_SEPARATORS.QUESTION_MARK) ? url.search.slice(1) : url.search;
528
+ } catch {
529
+ return input;
530
+ }
531
+ }
532
+ function stripLeadingQuestionMark(query) {
533
+ return query.startsWith(QUERY_SEPARATORS.QUESTION_MARK) ? query.slice(1) : query;
534
+ }
535
+ function splitOnFirstEquals(part) {
536
+ const kv = dividePreserve(part, QUERY_SEPARATORS.EQUALS);
537
+ if (kv.length === 1) return [kv[0] ?? "", ""];
538
+ return [kv[0] ?? "", kv.slice(1).join(QUERY_SEPARATORS.EQUALS)];
539
+ }
540
+ function decodeField(text, mode, trim) {
541
+ let t = text;
542
+ if (mode === QUERY_DECODE_MODES.AUTO) {
543
+ t = t.replace(/\+/g, " ");
544
+ try {
545
+ t = decodeURIComponent(t);
546
+ } catch {
547
+ }
548
+ }
549
+ if (trim) t = t.trim();
550
+ return t;
551
+ }
552
+ function queryDivider(input, { mode = QUERY_DECODE_MODES.AUTO, trim = false } = {}) {
553
+ if (input.length === 0) return [];
554
+ const query = stripLeadingQuestionMark(tryExtractQuery(input));
555
+ if (query.length === 0) return [];
556
+ return dividePreserve(query, QUERY_SEPARATORS.AMPERSAND).map((part) => {
557
+ const [key, value] = splitOnFirstEquals(part);
558
+ return [decodeField(key, mode, trim), decodeField(value, mode, trim)];
559
+ });
560
+ }
512
561
  // Annotate the CommonJS export names for ESM import in node:
513
562
  0 && (module.exports = {
514
563
  csvDivider,
@@ -518,5 +567,6 @@ function pathDivider(input, options = {}) {
518
567
  dividerLoop,
519
568
  dividerNumberString,
520
569
  emailDivider,
521
- pathDivider
570
+ pathDivider,
571
+ queryDivider
522
572
  });
package/dist/index.d.cts CHANGED
@@ -13,6 +13,13 @@ declare const DIVIDER_EXCLUDE_MODES: {
13
13
  readonly EMPTY: "empty";
14
14
  readonly WHITESPACE: "whitespace";
15
15
  };
16
+ /**
17
+ * Query string decode modes.
18
+ */
19
+ declare const QUERY_DECODE_MODES: {
20
+ readonly AUTO: "auto";
21
+ readonly RAW: "raw";
22
+ };
16
23
 
17
24
  type DividerExcludeMode = (typeof DIVIDER_EXCLUDE_MODES)[keyof typeof DIVIDER_EXCLUDE_MODES];
18
25
  type StringInput = string;
@@ -158,6 +165,11 @@ type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
158
165
  /** Collapse empty segments produced by leading/trailing or repeated separators. */
159
166
  collapse?: boolean;
160
167
  };
168
+ type QueryDecodeMode = (typeof QUERY_DECODE_MODES)[keyof typeof QUERY_DECODE_MODES];
169
+ type QueryDividerOptions = Pick<DividerOptions, 'trim'> & {
170
+ /** Decoding mode: 'auto' applies standard URL decoding; 'raw' leaves values untouched. */
171
+ mode?: QueryDecodeMode;
172
+ };
161
173
 
162
174
  /**
163
175
  * Divides a CSV line into an array of fields, handling quoted values appropriately.
@@ -190,4 +202,15 @@ declare function emailDivider(input: string, options?: EmailDividerOptions): Div
190
202
  */
191
203
  declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
192
204
 
193
- export { type DividerArg, type DividerArgs, type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
205
+ /**
206
+ * Divide a query string into key/value pairs.
207
+ * - Supports raw query (with or without leading '?').
208
+ * - Accepts full URLs (query extracted automatically).
209
+ * - Preserves empty keys/values and trailing separators.
210
+ * @param input Query string or full URL.
211
+ * @param options Parsing options: { mode?: 'auto' | 'raw'; trim?: boolean }.
212
+ * @returns Array of [key, value] string tuples in input order.
213
+ */
214
+ declare function queryDivider(input: string, { mode, trim }?: QueryDividerOptions): DividerArrayResult;
215
+
216
+ export { type DividerArg, type DividerArgs, type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider, queryDivider };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,13 @@ declare const DIVIDER_EXCLUDE_MODES: {
13
13
  readonly EMPTY: "empty";
14
14
  readonly WHITESPACE: "whitespace";
15
15
  };
16
+ /**
17
+ * Query string decode modes.
18
+ */
19
+ declare const QUERY_DECODE_MODES: {
20
+ readonly AUTO: "auto";
21
+ readonly RAW: "raw";
22
+ };
16
23
 
17
24
  type DividerExcludeMode = (typeof DIVIDER_EXCLUDE_MODES)[keyof typeof DIVIDER_EXCLUDE_MODES];
18
25
  type StringInput = string;
@@ -158,6 +165,11 @@ type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
158
165
  /** Collapse empty segments produced by leading/trailing or repeated separators. */
159
166
  collapse?: boolean;
160
167
  };
168
+ type QueryDecodeMode = (typeof QUERY_DECODE_MODES)[keyof typeof QUERY_DECODE_MODES];
169
+ type QueryDividerOptions = Pick<DividerOptions, 'trim'> & {
170
+ /** Decoding mode: 'auto' applies standard URL decoding; 'raw' leaves values untouched. */
171
+ mode?: QueryDecodeMode;
172
+ };
161
173
 
162
174
  /**
163
175
  * Divides a CSV line into an array of fields, handling quoted values appropriately.
@@ -190,4 +202,15 @@ declare function emailDivider(input: string, options?: EmailDividerOptions): Div
190
202
  */
191
203
  declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
192
204
 
193
- export { type DividerArg, type DividerArgs, type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
205
+ /**
206
+ * Divide a query string into key/value pairs.
207
+ * - Supports raw query (with or without leading '?').
208
+ * - Accepts full URLs (query extracted automatically).
209
+ * - Preserves empty keys/values and trailing separators.
210
+ * @param input Query string or full URL.
211
+ * @param options Parsing options: { mode?: 'auto' | 'raw'; trim?: boolean }.
212
+ * @returns Array of [key, value] string tuples in input order.
213
+ */
214
+ declare function queryDivider(input: string, { mode, trim }?: QueryDividerOptions): DividerArrayResult;
215
+
216
+ export { type DividerArg, type DividerArgs, type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider, queryDivider };
package/dist/index.js CHANGED
@@ -27,6 +27,15 @@ var PATH_SEPARATORS = {
27
27
  SLASH: "/",
28
28
  ALT: "|"
29
29
  };
30
+ var QUERY_SEPARATORS = {
31
+ QUESTION_MARK: "?",
32
+ AMPERSAND: "&",
33
+ EQUALS: "="
34
+ };
35
+ var QUERY_DECODE_MODES = {
36
+ AUTO: "auto",
37
+ RAW: "raw"
38
+ };
30
39
 
31
40
  // src/utils/is.ts
32
41
  function isString(value) {
@@ -476,6 +485,45 @@ function pathDivider(input, options = {}) {
476
485
  const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
477
486
  return collapse ? maybeTrimmed.filter((segment) => !isEmptyString(segment)) : maybeTrimmed;
478
487
  }
488
+
489
+ // src/presets/query-divider.ts
490
+ function tryExtractQuery(input) {
491
+ try {
492
+ const url = new URL(input);
493
+ return url.search.startsWith(QUERY_SEPARATORS.QUESTION_MARK) ? url.search.slice(1) : url.search;
494
+ } catch {
495
+ return input;
496
+ }
497
+ }
498
+ function stripLeadingQuestionMark(query) {
499
+ return query.startsWith(QUERY_SEPARATORS.QUESTION_MARK) ? query.slice(1) : query;
500
+ }
501
+ function splitOnFirstEquals(part) {
502
+ const kv = dividePreserve(part, QUERY_SEPARATORS.EQUALS);
503
+ if (kv.length === 1) return [kv[0] ?? "", ""];
504
+ return [kv[0] ?? "", kv.slice(1).join(QUERY_SEPARATORS.EQUALS)];
505
+ }
506
+ function decodeField(text, mode, trim) {
507
+ let t = text;
508
+ if (mode === QUERY_DECODE_MODES.AUTO) {
509
+ t = t.replace(/\+/g, " ");
510
+ try {
511
+ t = decodeURIComponent(t);
512
+ } catch {
513
+ }
514
+ }
515
+ if (trim) t = t.trim();
516
+ return t;
517
+ }
518
+ function queryDivider(input, { mode = QUERY_DECODE_MODES.AUTO, trim = false } = {}) {
519
+ if (input.length === 0) return [];
520
+ const query = stripLeadingQuestionMark(tryExtractQuery(input));
521
+ if (query.length === 0) return [];
522
+ return dividePreserve(query, QUERY_SEPARATORS.AMPERSAND).map((part) => {
523
+ const [key, value] = splitOnFirstEquals(part);
524
+ return [decodeField(key, mode, trim), decodeField(value, mode, trim)];
525
+ });
526
+ }
479
527
  export {
480
528
  csvDivider,
481
529
  divider,
@@ -484,5 +532,6 @@ export {
484
532
  dividerLoop,
485
533
  dividerNumberString,
486
534
  emailDivider,
487
- pathDivider
535
+ pathDivider,
536
+ queryDivider
488
537
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nyaomaru/divider",
3
3
  "type": "module",
4
- "version": "1.9.18",
4
+ "version": "1.9.20",
5
5
  "description": "To divide string or string[] with a given separator",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",