unslash 1.0.2 → 2.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 +39 -19
- package/dist/index.d.ts +38 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +3 -3
- package/package.json +4 -3
- package/dist/pattern.d.ts +0 -20
- package/dist/pattern.js +0 -1
- package/dist/pattern.js.map +0 -7
- package/dist/slash.d.ts +0 -27
- package/dist/slash.js +0 -2
- package/dist/slash.js.map +0 -7
- package/dist/slashFn.d.ts +0 -9
- package/dist/slashFn.js +0 -2
- package/dist/slashFn.js.map +0 -7
package/README.md
CHANGED
|
@@ -13,68 +13,88 @@ npm install unslash
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import { slash } from 'unslash';
|
|
16
|
+
import { s, slash } from 'unslash';
|
|
17
|
+
|
|
18
|
+
// Just join some paths. No magic.
|
|
19
|
+
s('path', 'to', 'file');
|
|
20
|
+
// → 'path/to/file'
|
|
17
21
|
|
|
18
22
|
// Need a trailing slash? Done.
|
|
19
|
-
|
|
23
|
+
s(/t/, 'path', 'to', 'file');
|
|
20
24
|
// → 'path/to/file/'
|
|
21
25
|
|
|
22
26
|
// Don’t want it? Gone.
|
|
23
|
-
|
|
27
|
+
s(/!t/, 'path/to/file/');
|
|
24
28
|
// → 'path/to/file'
|
|
25
29
|
|
|
26
30
|
// Want a leading slash? Here you go.
|
|
27
|
-
|
|
31
|
+
s(/l/, 'path', 'to', 'file');
|
|
28
32
|
// → '/path/to/file'
|
|
29
33
|
|
|
30
34
|
// Need to collapse that mess? Fixed.
|
|
31
|
-
|
|
35
|
+
s(/c/, 'path///to', 'this//file');
|
|
32
36
|
// → 'path/to/this/file'
|
|
33
37
|
|
|
34
38
|
// Want to force forward slashes? Me too.
|
|
35
|
-
|
|
39
|
+
s(/f/, 'path\\to', 'this/file');
|
|
36
40
|
// → 'path/to/this/file'
|
|
37
41
|
|
|
38
42
|
// Need Windows paths? What is wrong with you?!
|
|
39
|
-
|
|
43
|
+
s(/!f/, 'path', 'to', 'file');
|
|
40
44
|
// → 'path\to\file'
|
|
41
45
|
|
|
42
46
|
// Combine them. Because you can.
|
|
43
|
-
|
|
47
|
+
s(/tlfc/, 'path\\\\to\\file');
|
|
44
48
|
// → '/path/to/file/'
|
|
45
|
-
|
|
49
|
+
s(/!t!l!fc/, '/path///to/file/');
|
|
46
50
|
// → 'path\to\file'
|
|
47
51
|
|
|
48
52
|
// Your precious protocols are safe — don’t worry.
|
|
49
|
-
|
|
53
|
+
s(/tlfc/, 'http://example.com', 'path', 'to', 'file');
|
|
50
54
|
// → 'http://example.com/path/to/file/'
|
|
51
55
|
```
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
There are three ways to use the library:
|
|
54
58
|
|
|
55
59
|
```ts
|
|
56
|
-
import
|
|
60
|
+
import unslash, { s, slash } from 'unslash';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For all DRY lovers like me, you can create reusable formatters:
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
```ts
|
|
66
|
+
// Create a formatter
|
|
67
|
+
const normalize = s(/fc/); // Force forward, collapse
|
|
68
|
+
|
|
69
|
+
// Use it
|
|
70
|
+
normalize('path\\to\\file');
|
|
71
|
+
// → 'path/to/file'
|
|
72
|
+
|
|
73
|
+
// Extend it on the fly if you're feeling spicy
|
|
74
|
+
normalize(/t/, 'path\\to\\file');
|
|
59
75
|
// → 'path/to/file/'
|
|
60
76
|
```
|
|
61
77
|
|
|
62
|
-
|
|
78
|
+
For the lazy ones, `snormalize` (or `sn`) is already pre-configured with `/fc/` (Force forward + Collapse):
|
|
63
79
|
|
|
64
80
|
```ts
|
|
65
|
-
import {
|
|
66
|
-
const normalizePath = sfn('tlfc');
|
|
81
|
+
import { sn } from 'unslash';
|
|
67
82
|
|
|
68
|
-
|
|
69
|
-
// → '
|
|
83
|
+
sn('path\\to//file');
|
|
84
|
+
// → 'path/to/file'
|
|
85
|
+
|
|
86
|
+
sn(/t/, 'path\\to//file');
|
|
87
|
+
// → 'path/to/file/'
|
|
70
88
|
```
|
|
71
89
|
|
|
72
90
|
## Pattern Flags
|
|
73
91
|
|
|
92
|
+
Use these in your regex literal (e.g., `/tfc/`):
|
|
93
|
+
|
|
74
94
|
- `t` / `!t` — Add/remove **T**railing slash
|
|
75
95
|
- `l` / `!l` — Add/remove **L**eading slash
|
|
76
96
|
- `f` / `!f` — Force **F**orward slashes / backward slashes
|
|
77
|
-
- `c` — **C**ollapse multiple slashes
|
|
97
|
+
- `c` / `!c` — **C**ollapse multiple slashes / Don't collapse
|
|
78
98
|
|
|
79
99
|
## But Gwynerva, there are libraries for this
|
|
80
100
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
declare function _slash(pattern: RegExp): SlashFormatter;
|
|
2
|
+
declare function _slash(pattern: RegExp, ...parts: string[]): string;
|
|
3
|
+
declare function _slash(...parts: string[]): string;
|
|
4
|
+
type SlashFormatter = {
|
|
5
|
+
(pattern: RegExp): SlashFormatter;
|
|
6
|
+
(...parts: string[]): string;
|
|
7
|
+
(pattern: RegExp, ...parts: string[]): string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Creates a slash formatter or formats strings directly.
|
|
11
|
+
*
|
|
12
|
+
* The formatter is configured using a RegExp pattern whose source consists of
|
|
13
|
+
* single-letter flags and their negations (`!x`). Flags are evaluated
|
|
14
|
+
* left-to-right; later flags override earlier ones (e.g. `c!c` disables
|
|
15
|
+
* collapsing even if `c` appeared before).
|
|
16
|
+
*
|
|
17
|
+
* Supported flags:
|
|
18
|
+
* - `t` | `!t` — ensure trailing slash is added | removed
|
|
19
|
+
* - `l` | `!l` — ensure leading slash is added | removed
|
|
20
|
+
* - `f` | `!f` — force forward | backward slashes
|
|
21
|
+
* - `c` | `!c` — collapse multiple slashes | do not collapse
|
|
22
|
+
*
|
|
23
|
+
* Calling with a RegExp returns a reusable formatter.
|
|
24
|
+
* Calling a formatter with another RegExp appends flags to the existing pattern.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const normalize = slasher(/fc/); // Force forward slashes, collapse multiple slashes
|
|
28
|
+
* normalize(/t/, 'my\\long\\\\path'); // `fc` flags + force trailing slash and apply formatting
|
|
29
|
+
* // → 'my/long/path/'
|
|
30
|
+
*/
|
|
31
|
+
export declare const slash: typeof _slash;
|
|
32
|
+
/** Short version of `slash`. */
|
|
33
|
+
export declare const s: typeof _slash;
|
|
34
|
+
/** Convert to forward slashes + collapse multiple adjacent slashes. */
|
|
35
|
+
export declare const snormalize: SlashFormatter;
|
|
36
|
+
/** Short version of `snormalize`. */
|
|
37
|
+
export declare const sn: SlashFormatter;
|
|
38
|
+
export default slash;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function h(...s){const[n,...e]=s;if(typeof n=="string")return s.join("/");if(n instanceof RegExp&&e.length===0){const t=o(n);return g(t)}return n instanceof RegExp?l(o(n),e):""}function g(s){return((...e)=>{const[t,...i]=e;if(t instanceof RegExp){const r=o(t),a=p(s,r);return i.length>0?l(a,i):g(a)}return l(s,e)})}function o(s){const n=s.source,e={};for(let t=0;t<n.length;t++){const i=n[t],r=i==="!",a=r?n[t+1]:i;switch(r&&t++,a){case"f":case"c":case"t":case"l":e[a]=!r;break}}return e}function p(s,n){return{...s,...n}}function l(s,n){const e=s.f===!1?"\\":"/";let t=n.join(e);const i=/^([a-zA-Z][a-zA-Z\d+\-.]*:)(\/\/)?/;let r="";const a=t.match(i);if(a&&(r=a[0],t=t.slice(r.length)),s.f===!1?t=t.replace(/\//g,"\\"):s.f===!0&&(t=t.replace(/\\/g,"/")),s.c){const c=s.f===!1?/\\+/g:/\/+/g;t=t.replace(c,e)}if(s.t)t.endsWith(e)||(t+=e);else if(s.t===!1)for(;t.endsWith("/")||t.endsWith("\\");)t=t.slice(0,-1);if(s.l)t.startsWith(e)||(t=e+t);else if(s.l===!1)for(;t.startsWith("/")||t.startsWith("\\");)t=t.slice(1);return r+t}const f=h,x=f,u=f(/fc/),m=u;var S=f;export{S as default,x as s,f as slash,m as sn,u as snormalize};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["slash", "s", "
|
|
4
|
+
"sourcesContent": ["// #region Slash\n//\n\nfunction _slash(pattern: RegExp): SlashFormatter;\nfunction _slash(pattern: RegExp, ...parts: string[]): string;\nfunction _slash(...parts: string[]): string;\nfunction _slash(\n ...args: [RegExp | string, ...string[]] | string[]\n): string | SlashFormatter {\n const [first, ...rest] = args;\n\n //\n // slash(\"a\", \"b\")\n //\n\n if (typeof first === 'string') {\n return (args as string[]).join('/');\n }\n\n //\n // slash(/pattern/)\n //\n\n if (first instanceof RegExp && rest.length === 0) {\n const config = parsePattern(first);\n return createFormatter(config);\n }\n\n //\n // slash(/pattern/, \"a\", \"b\")\n //\n\n if (first instanceof RegExp) {\n return applyConfig(parsePattern(first), rest as string[]);\n }\n\n return '';\n}\n\n//\n// #endregion\n\n// #region Helpers\n//\n\ntype SlashFormatter = {\n (pattern: RegExp): SlashFormatter;\n (...parts: string[]): string;\n (pattern: RegExp, ...parts: string[]): string;\n};\n\ntype SlashConfig = {\n f?: boolean;\n c?: boolean;\n t?: boolean;\n l?: boolean;\n};\n\nfunction createFormatter(config: SlashConfig): SlashFormatter {\n const formatter = ((\n ...inner: [RegExp | string, ...string[]] | string[]\n ): string | SlashFormatter => {\n const [head, ...tail] = inner;\n\n // Append pattern\n if (head instanceof RegExp) {\n const nextConfig = parsePattern(head);\n const combined = mergeConfigs(config, nextConfig);\n\n // pattern + strings \u2192 evaluate immediately\n if (tail.length > 0) {\n return applyConfig(combined, tail as string[]);\n }\n\n // pattern only \u2192 return new formatter\n return createFormatter(combined);\n }\n\n // formatter(\"a\", \"b\")\n return applyConfig(config, inner as string[]);\n }) as SlashFormatter;\n\n return formatter;\n}\n\nfunction parsePattern(pattern: RegExp): SlashConfig {\n const source = pattern.source;\n const config: SlashConfig = {};\n\n for (let i = 0; i < source.length; i++) {\n const char = source[i];\n const negated = char === '!';\n const flag = negated ? source[i + 1] : char;\n\n if (negated) i++;\n\n switch (flag) {\n case 'f':\n case 'c':\n case 't':\n case 'l':\n config[flag] = !negated;\n break;\n }\n }\n\n return config;\n}\n\nfunction mergeConfigs(a: SlashConfig, b: SlashConfig): SlashConfig {\n return { ...a, ...b };\n}\n\nfunction applyConfig(config: SlashConfig, parts: string[]): string {\n const slashChar = config.f === false ? '\\\\' : '/';\n //\n // Protocol-safe join\n //\n\n let joined = parts.join(slashChar);\n\n const PROTOCOL_RE = /^([a-zA-Z][a-zA-Z\\d+\\-.]*:)(\\/\\/)?/;\n\n let protocol = '';\n const match = joined.match(PROTOCOL_RE);\n\n if (match) {\n protocol = match[0];\n joined = joined.slice(protocol.length);\n }\n\n //\n // Force slash type\n //\n\n if (config.f === false) {\n joined = joined.replace(/\\//g, '\\\\');\n } else if (config.f === true) {\n joined = joined.replace(/\\\\/g, '/');\n }\n\n //\n // Collapse multiple slashes\n //\n\n if (config.c) {\n const slashRegex = config.f === false ? /\\\\+/g : /\\/+/g;\n joined = joined.replace(slashRegex, slashChar);\n }\n\n //\n // Trailing slash\n //\n\n if (config.t) {\n if (!joined.endsWith(slashChar)) {\n joined += slashChar;\n }\n } else if (config.t === false) {\n // Explicitly removed (!t)\n while (joined.endsWith('/') || joined.endsWith('\\\\')) {\n joined = joined.slice(0, -1);\n }\n }\n\n //\n // Leading slash\n //\n\n if (config.l) {\n if (!joined.startsWith(slashChar)) {\n joined = slashChar + joined;\n }\n } else if (config.l === false) {\n // Explicitly removed (!l)\n while (joined.startsWith('/') || joined.startsWith('\\\\')) {\n joined = joined.slice(1);\n }\n }\n\n return protocol + joined;\n}\n\n//\n// #endregion\n\n// #region Exports\n//\n\n/**\n * Creates a slash formatter or formats strings directly.\n *\n * The formatter is configured using a RegExp pattern whose source consists of\n * single-letter flags and their negations (`!x`). Flags are evaluated\n * left-to-right; later flags override earlier ones (e.g. `c!c` disables\n * collapsing even if `c` appeared before).\n *\n * Supported flags:\n * - `t` | `!t` \u2014 ensure trailing slash is added | removed\n * - `l` | `!l` \u2014 ensure leading slash is added | removed\n * - `f` | `!f` \u2014 force forward | backward slashes\n * - `c` | `!c` \u2014 collapse multiple slashes | do not collapse\n *\n * Calling with a RegExp returns a reusable formatter.\n * Calling a formatter with another RegExp appends flags to the existing pattern.\n *\n * @example\n * const normalize = slasher(/fc/); // Force forward slashes, collapse multiple slashes\n * normalize(/t/, 'my\\\\long\\\\\\\\path'); // `fc` flags + force trailing slash and apply formatting\n * // \u2192 'my/long/path/'\n */\nexport const slash = _slash;\n\n/** Short version of `slash`. */\nexport const s = slash;\n\n/** Convert to forward slashes + collapse multiple adjacent slashes. */\nexport const snormalize = slash(/fc/);\n\n/** Short version of `snormalize`. */\nexport const sn = snormalize;\n\nexport default slash;\n\n//\n// #endregion\n"],
|
|
5
|
+
"mappings": "AAMA,SAASA,KACJC,EACsB,CACzB,KAAM,CAACC,EAAO,GAAGC,CAAI,EAAIF,EAMzB,GAAI,OAAOC,GAAU,SACnB,OAAQD,EAAkB,KAAK,GAAG,EAOpC,GAAIC,aAAiB,QAAUC,EAAK,SAAW,EAAG,CAChD,MAAMC,EAASC,EAAaH,CAAK,EACjC,OAAOI,EAAgBF,CAAM,CAC/B,CAMA,OAAIF,aAAiB,OACZK,EAAYF,EAAaH,CAAK,EAAGC,CAAgB,EAGnD,EACT,CAqBA,SAASG,EAAgBF,EAAqC,CAwB5D,OAvBmB,IACdI,IACyB,CAC5B,KAAM,CAACC,EAAM,GAAGC,CAAI,EAAIF,EAGxB,GAAIC,aAAgB,OAAQ,CAC1B,MAAME,EAAaN,EAAaI,CAAI,EAC9BG,EAAWC,EAAaT,EAAQO,CAAU,EAGhD,OAAID,EAAK,OAAS,EACTH,EAAYK,EAAUF,CAAgB,EAIxCJ,EAAgBM,CAAQ,CACjC,CAGA,OAAOL,EAAYH,EAAQI,CAAiB,CAC9C,EAGF,CAEA,SAASH,EAAaS,EAA8B,CAClD,MAAMC,EAASD,EAAQ,OACjBV,EAAsB,CAAC,EAE7B,QAASY,EAAI,EAAGA,EAAID,EAAO,OAAQC,IAAK,CACtC,MAAMC,EAAOF,EAAOC,CAAC,EACfE,EAAUD,IAAS,IACnBE,EAAOD,EAAUH,EAAOC,EAAI,CAAC,EAAIC,EAIvC,OAFIC,GAASF,IAELG,EAAM,CACZ,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACHf,EAAOe,CAAI,EAAI,CAACD,EAChB,KACJ,CACF,CAEA,OAAOd,CACT,CAEA,SAASS,EAAaO,EAAgBC,EAA6B,CACjE,MAAO,CAAE,GAAGD,EAAG,GAAGC,CAAE,CACtB,CAEA,SAASd,EAAYH,EAAqBkB,EAAyB,CACjE,MAAMC,EAAYnB,EAAO,IAAM,GAAQ,KAAO,IAK9C,IAAIoB,EAASF,EAAM,KAAKC,CAAS,EAEjC,MAAME,EAAc,qCAEpB,IAAIC,EAAW,GACf,MAAMC,EAAQH,EAAO,MAAMC,CAAW,EAqBtC,GAnBIE,IACFD,EAAWC,EAAM,CAAC,EAClBH,EAASA,EAAO,MAAME,EAAS,MAAM,GAOnCtB,EAAO,IAAM,GACfoB,EAASA,EAAO,QAAQ,MAAO,IAAI,EAC1BpB,EAAO,IAAM,KACtBoB,EAASA,EAAO,QAAQ,MAAO,GAAG,GAOhCpB,EAAO,EAAG,CACZ,MAAMwB,EAAaxB,EAAO,IAAM,GAAQ,OAAS,OACjDoB,EAASA,EAAO,QAAQI,EAAYL,CAAS,CAC/C,CAMA,GAAInB,EAAO,EACJoB,EAAO,SAASD,CAAS,IAC5BC,GAAUD,WAEHnB,EAAO,IAAM,GAEtB,KAAOoB,EAAO,SAAS,GAAG,GAAKA,EAAO,SAAS,IAAI,GACjDA,EAASA,EAAO,MAAM,EAAG,EAAE,EAQ/B,GAAIpB,EAAO,EACJoB,EAAO,WAAWD,CAAS,IAC9BC,EAASD,EAAYC,WAEdpB,EAAO,IAAM,GAEtB,KAAOoB,EAAO,WAAW,GAAG,GAAKA,EAAO,WAAW,IAAI,GACrDA,EAASA,EAAO,MAAM,CAAC,EAI3B,OAAOE,EAAWF,CACpB,CA8BO,MAAMK,EAAQ7B,EAGR8B,EAAID,EAGJE,EAAaF,EAAM,IAAI,EAGvBG,EAAKD,EAElB,IAAOE,EAAQJ",
|
|
6
|
+
"names": ["_slash", "args", "first", "rest", "config", "parsePattern", "createFormatter", "applyConfig", "inner", "head", "tail", "nextConfig", "combined", "mergeConfigs", "pattern", "source", "i", "char", "negated", "flag", "a", "b", "parts", "slashChar", "joined", "PROTOCOL_RE", "protocol", "match", "slashRegex", "slash", "s", "snormalize", "sn", "index_default"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unslash",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "🤬 No more pain with slashes!",
|
|
6
6
|
"keywords": [
|
|
@@ -38,9 +38,10 @@
|
|
|
38
38
|
"test": "bun vitest run"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
+
"@types/node": "^25.1.0",
|
|
42
|
+
"esbuild": "^0.27.2",
|
|
41
43
|
"prettier": "^3.8.1",
|
|
42
44
|
"typescript": "^5.9.3",
|
|
43
|
-
"vitest": "^4.0.18"
|
|
44
|
-
"esbuild": "^0.27.2"
|
|
45
|
+
"vitest": "^4.0.18"
|
|
45
46
|
}
|
|
46
47
|
}
|
package/dist/pattern.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type SlashBooleanFlag = 't' | 'l' | 'f';
|
|
2
|
-
export type SlashPlainFlag = 'c';
|
|
3
|
-
export type SlashFlag = SlashBooleanFlag | SlashPlainFlag;
|
|
4
|
-
export declare const unslash: unique symbol;
|
|
5
|
-
type link = 'https://github.com/Gwynerva/unslash';
|
|
6
|
-
export type UnknownFlagError<C extends string> = {
|
|
7
|
-
readonly [unslash]: link;
|
|
8
|
-
SlashPatternError: `Character "${C}" is not a valid SlashFlag (allowed: t l f c, optionally prefixed with "!")`;
|
|
9
|
-
};
|
|
10
|
-
export type DuplicateFlagError<F extends string> = {
|
|
11
|
-
readonly [unslash]: link;
|
|
12
|
-
SlashPatternError: `Flag "${F}" is used more than once or both negated and non-negated`;
|
|
13
|
-
};
|
|
14
|
-
export type InvalidNegationError<F extends string> = {
|
|
15
|
-
readonly [unslash]: link;
|
|
16
|
-
SlashPatternError: `Flag "${F}" cannot be negated`;
|
|
17
|
-
};
|
|
18
|
-
export type ValidateSlashPattern<S extends string, Pos extends string = never, Neg extends string = never> = S extends `!${infer L}${infer R}` ? L extends SlashFlag ? L extends SlashBooleanFlag ? L extends Pos | Neg ? DuplicateFlagError<L> : ValidateSlashPattern<R, Pos, Neg | L> : InvalidNegationError<L> : UnknownFlagError<`!${L}`> : S extends `${infer L}${infer R}` ? L extends SlashFlag ? L extends Pos | Neg ? DuplicateFlagError<L> : ValidateSlashPattern<R, Pos | L, Neg> : UnknownFlagError<L> : S;
|
|
19
|
-
export type SlashPattern<S extends string> = ValidateSlashPattern<S> extends string ? S : ValidateSlashPattern<S>;
|
|
20
|
-
export {};
|
package/dist/pattern.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=pattern.js.map
|
package/dist/pattern.js.map
DELETED
package/dist/slash.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { SlashPattern } from './pattern.js';
|
|
2
|
-
/**
|
|
3
|
-
* Formats a string based on the given slash pattern.
|
|
4
|
-
* @param pattern
|
|
5
|
-
* A string of letters or their negations (prefixed with "!").
|
|
6
|
-
* Each letter represents a specific formatting rule:
|
|
7
|
-
* - `t` | `!t`: Ensure trailing slash is added | removed.
|
|
8
|
-
* - `l` | `!l`: Ensure leading slash is added | removed.
|
|
9
|
-
* - `f` | `!f`: Force forward | backward slashes.
|
|
10
|
-
* - `c` Collapse multiple adjacent slashes into a single slash.
|
|
11
|
-
*
|
|
12
|
-
* Example patterns:
|
|
13
|
-
* - `"tlfc"`: Ensure leading and trailing slashes, force forward slashes, collapse multiple slashes.
|
|
14
|
-
* - `"lf"`: Force forward slashes and ensure leading slash (trailing might be present or absent).
|
|
15
|
-
* - `tl!f`: Ensure leading and trailing slashes, force backward slashes.
|
|
16
|
-
* @param parts
|
|
17
|
-
* The string parts to be formatted according to the specified pattern.
|
|
18
|
-
* They will be joined together using forward slashes by default (or backward slashes if `!f` is specified in the pattern).
|
|
19
|
-
* @returns
|
|
20
|
-
* The formatted string with slash-concatenated parts according to the specified slash pattern.
|
|
21
|
-
* Protocols (like `http://`) are preserved and not altered by the formatting.
|
|
22
|
-
*/
|
|
23
|
-
export declare function slash<S extends string>(pattern: SlashPattern<S>, ...parts: string[]): string;
|
|
24
|
-
/**
|
|
25
|
-
* Shortened version of `slash`.
|
|
26
|
-
*/
|
|
27
|
-
export declare const s: typeof slash;
|
package/dist/slash.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
function g(l,...f){const e={};l=l;for(let t=0;t<l.length;t++){const n=l[t],c=n==="!",h=c?l[t+1]:n;e[h]=!c,c&&t++}const i=e.f===!1?"\\":"/";let s=f.join(i);const r=/^([a-zA-Z][a-zA-Z\d+\-.]*:)(\/\/)?/;let a="";const o=s.match(r);if(o&&(a=o[0],s=s.slice(a.length)),e.f===!1?s=s.replace(/\//g,"\\"):e.f===!0&&(s=s.replace(/\\/g,"/")),e.c){const t=e.f===!1?/\\+/g:/\/+/g,n=e.f===!1?"\\":"/";s=s.replace(t,n)}if(e.l)s.startsWith(i)||(s=i+s);else for(;s.startsWith("\\")||s.startsWith("/");)s=s.slice(1);if(e.t)s.endsWith(i)||(s=s+i);else for(;s.endsWith("\\")||s.endsWith("/");)s=s.slice(0,-1);return a+s}const d=g;export{d as s,g as slash};
|
|
2
|
-
//# sourceMappingURL=slash.js.map
|
package/dist/slash.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/slash.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SlashPattern } from './pattern.js';\n\n/**\n * Formats a string based on the given slash pattern.\n * @param pattern\n * A string of letters or their negations (prefixed with \"!\").\n * Each letter represents a specific formatting rule:\n * - `t` | `!t`: Ensure trailing slash is added | removed.\n * - `l` | `!l`: Ensure leading slash is added | removed.\n * - `f` | `!f`: Force forward | backward slashes.\n * - `c` Collapse multiple adjacent slashes into a single slash.\n *\n * Example patterns:\n * - `\"tlfc\"`: Ensure leading and trailing slashes, force forward slashes, collapse multiple slashes.\n * - `\"lf\"`: Force forward slashes and ensure leading slash (trailing might be present or absent).\n * - `tl!f`: Ensure leading and trailing slashes, force backward slashes.\n * @param parts\n * The string parts to be formatted according to the specified pattern.\n * They will be joined together using forward slashes by default (or backward slashes if `!f` is specified in the pattern).\n * @returns\n * The formatted string with slash-concatenated parts according to the specified slash pattern.\n * Protocols (like `http://`) are preserved and not altered by the formatting.\n */\nexport function slash<S extends string>(\n pattern: SlashPattern<S>,\n ...parts: string[]\n): string {\n const flags: Record<string, boolean> = {};\n\n // @ts-expect-error Pattern is validated at compile-time\n pattern = pattern as string;\n\n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i];\n const negated = char === '!';\n const flag = negated ? pattern[i + 1] : char;\n\n flags[flag] = !negated;\n\n if (negated) {\n i++;\n }\n }\n\n const slashChar = flags['f'] === false ? '\\\\' : '/';\n\n // ------------------------------------------------------------\n // Protocol-safe join\n // ------------------------------------------------------------\n\n let joined = parts.join(slashChar);\n\n // Matches: scheme: or scheme://\n // Examples: http://, file://, mailto:\n const PROTOCOL_RE = /^([a-zA-Z][a-zA-Z\\d+\\-.]*:)(\\/\\/)?/;\n\n let protocol = '';\n const match = joined.match(PROTOCOL_RE);\n\n if (match) {\n protocol = match[0];\n joined = joined.slice(protocol.length);\n }\n\n // ------------------------------------------------------------\n // Force slash type (convert all slashes)\n // ------------------------------------------------------------\n\n if (flags['f'] === false) {\n // Force backward slashes: convert all / to \\\n joined = joined.replace(/\\//g, '\\\\');\n } else if (flags['f'] === true) {\n // Force forward slashes: convert all \\ to /\n joined = joined.replace(/\\\\/g, '/');\n }\n\n // ------------------------------------------------------------\n // Collapse multiple slashes\n // ------------------------------------------------------------\n\n if (flags['c']) {\n const slashRegex = flags['f'] === false ? /\\\\+/g : /\\/+/g;\n const replacement = flags['f'] === false ? '\\\\' : '/';\n joined = joined.replace(slashRegex, replacement);\n }\n\n // ------------------------------------------------------------\n // Leading slash handling\n // ------------------------------------------------------------\n\n if (flags['l']) {\n if (!joined.startsWith(slashChar)) {\n joined = slashChar + joined;\n }\n } else {\n while (joined.startsWith('\\\\') || joined.startsWith('/')) {\n joined = joined.slice(1);\n }\n }\n\n // ------------------------------------------------------------\n // Trailing slash handling\n // ------------------------------------------------------------\n\n if (flags['t']) {\n if (!joined.endsWith(slashChar)) {\n joined = joined + slashChar;\n }\n } else {\n while (joined.endsWith('\\\\') || joined.endsWith('/')) {\n joined = joined.slice(0, -1);\n }\n }\n\n return protocol + joined;\n}\n\n/**\n * Shortened version of `slash`.\n */\nexport const s = slash;\n"],
|
|
5
|
-
"mappings": "AAuBO,SAASA,EACdC,KACGC,EACK,CACR,MAAMC,EAAiC,CAAC,EAGxCF,EAAUA,EAEV,QAASG,EAAI,EAAGA,EAAIH,EAAQ,OAAQG,IAAK,CACvC,MAAMC,EAAOJ,EAAQG,CAAC,EAChBE,EAAUD,IAAS,IACnBE,EAAOD,EAAUL,EAAQG,EAAI,CAAC,EAAIC,EAExCF,EAAMI,CAAI,EAAI,CAACD,EAEXA,GACFF,GAEJ,CAEA,MAAMI,EAAYL,EAAM,IAAS,GAAQ,KAAO,IAMhD,IAAIM,EAASP,EAAM,KAAKM,CAAS,EAIjC,MAAME,EAAc,qCAEpB,IAAIC,EAAW,GACf,MAAMC,EAAQH,EAAO,MAAMC,CAAW,EAuBtC,GArBIE,IACFD,EAAWC,EAAM,CAAC,EAClBH,EAASA,EAAO,MAAME,EAAS,MAAM,GAOnCR,EAAM,IAAS,GAEjBM,EAASA,EAAO,QAAQ,MAAO,IAAI,EAC1BN,EAAM,IAAS,KAExBM,EAASA,EAAO,QAAQ,MAAO,GAAG,GAOhCN,EAAM,EAAM,CACd,MAAMU,EAAaV,EAAM,IAAS,GAAQ,OAAS,OAC7CW,EAAcX,EAAM,IAAS,GAAQ,KAAO,IAClDM,EAASA,EAAO,QAAQI,EAAYC,CAAW,CACjD,CAMA,GAAIX,EAAM,EACHM,EAAO,WAAWD,CAAS,IAC9BC,EAASD,EAAYC,OAGvB,MAAOA,EAAO,WAAW,IAAI,GAAKA,EAAO,WAAW,GAAG,GACrDA,EAASA,EAAO,MAAM,CAAC,EAQ3B,GAAIN,EAAM,EACHM,EAAO,SAASD,CAAS,IAC5BC,EAASA,EAASD,OAGpB,MAAOC,EAAO,SAAS,IAAI,GAAKA,EAAO,SAAS,GAAG,GACjDA,EAASA,EAAO,MAAM,EAAG,EAAE,EAI/B,OAAOE,EAAWF,CACpB,CAKO,MAAMM,EAAIf",
|
|
6
|
-
"names": ["slash", "pattern", "parts", "flags", "i", "char", "negated", "flag", "slashChar", "joined", "PROTOCOL_RE", "protocol", "match", "slashRegex", "replacement", "s"]
|
|
7
|
-
}
|
package/dist/slashFn.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { SlashPattern } from './pattern.js';
|
|
2
|
-
/**
|
|
3
|
-
* Creates a slash formatter with a fixed pattern for multiple uses.
|
|
4
|
-
* @param pattern
|
|
5
|
-
* See `slash` function for pattern documentation.
|
|
6
|
-
*/
|
|
7
|
-
export declare function slashFn<S extends string>(pattern: SlashPattern<S>): (...parts: string[]) => string;
|
|
8
|
-
/** Shortened version of `slashFn`. */
|
|
9
|
-
export declare const sfn: typeof slashFn;
|
package/dist/slashFn.js
DELETED
package/dist/slashFn.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/slashFn.ts"],
|
|
4
|
-
"sourcesContent": ["import type { SlashPattern } from './pattern.js';\r\nimport { slash } from './slash.js';\r\n\r\n/**\r\n * Creates a slash formatter with a fixed pattern for multiple uses.\r\n * @param pattern\r\n * See `slash` function for pattern documentation.\r\n */\r\nexport function slashFn<S extends string>(pattern: SlashPattern<S>) {\r\n return (...parts: string[]) => slash(pattern, ...parts);\r\n}\r\n\r\n/** Shortened version of `slashFn`. */\r\nexport const sfn = slashFn;\r\n"],
|
|
5
|
-
"mappings": "AACA,OAAS,SAAAA,MAAa,aAOf,SAASC,EAA0BC,EAA0B,CAClE,MAAO,IAAIC,IAAoBH,EAAME,EAAS,GAAGC,CAAK,CACxD,CAGO,MAAMC,EAAMH",
|
|
6
|
-
"names": ["slash", "slashFn", "pattern", "parts", "sfn"]
|
|
7
|
-
}
|