@arc-js/pajo 0.0.1
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 +568 -0
- package/index.d.ts +90 -0
- package/index.js +150 -0
- package/index.min.d.ts +90 -0
- package/index.min.js +1 -0
- package/package.json +18 -0
- package/pajo.all.js +222 -0
- package/pajo.all.min.js +1 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# @arc-js/pajo
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
**@arc-js/pajo** est une bibliothèque TypeScript légère et robuste pour la manipulation de chemins de fichiers et d'URLs. Elle offre une API unifiée et type-safe pour travailler avec des chemins de fichiers sur différentes plateformes (Windows, Linux, macOS) et pour construire des URLs de manière cohérente.
|
|
11
|
+
|
|
12
|
+
## ✨ Fonctionnalités Principales
|
|
13
|
+
|
|
14
|
+
### 📁 Manipulation de Chemins
|
|
15
|
+
- **Style multi-plateforme** : Support natif des chemins Windows (\) et Unix (/)
|
|
16
|
+
- **Joindre des chemins** : Méthode intelligente pour joindre plusieurs segments de chemin
|
|
17
|
+
- **Chemins absolus/relatifs** : Détection automatique du type de chemin
|
|
18
|
+
- **Normalisation** : Élimination des séparateurs redondants et des points (., ..)
|
|
19
|
+
- **Extraction** : Récupération du nom de fichier, extension et répertoire parent
|
|
20
|
+
|
|
21
|
+
### 🌐 Manipulation d'URLs
|
|
22
|
+
- **Construction d'URLs** : Joindre des segments avec un hôte (avec ou sans protocole)
|
|
23
|
+
- **Normalisation automatique** : Ajout de protocole si absent, gestion des slashs
|
|
24
|
+
- **Support des protocoles** : Reconnaissance automatique des schémas (http://, https://, etc.)
|
|
25
|
+
|
|
26
|
+
### 🔄 Conversion
|
|
27
|
+
- **Conversion de style** : Convertir entre chemins Windows et Unix
|
|
28
|
+
- **Adaptation automatique** : Détection du style basée sur le contenu du chemin
|
|
29
|
+
|
|
30
|
+
### 🛡️ Robustesse
|
|
31
|
+
- **Gestion des cas limites** : Chemins vides, séparateurs multiples, points spéciaux
|
|
32
|
+
- **Type-safe** : Entièrement écrit en TypeScript avec des types stricts
|
|
33
|
+
- **Pas de dépendances** : Bibliothèque autonome, zéro dépendance
|
|
34
|
+
|
|
35
|
+
## 📦 Installation
|
|
36
|
+
|
|
37
|
+
### Via npm/yarn/pnpm
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @arc-js/pajo
|
|
41
|
+
# ou
|
|
42
|
+
yarn add @arc-js/pajo
|
|
43
|
+
# ou
|
|
44
|
+
pnpm add @arc-js/pajo
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Importation directe (CDN)
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<script src="@arc-js/pajo/pajo.all.js"></script>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 🚀 Démarrage Rapide
|
|
54
|
+
|
|
55
|
+
### TypeScript/ES Modules
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import Pajo from '@arc-js/pajo';
|
|
59
|
+
// ou
|
|
60
|
+
import { Pajo } from '@arc-js/pajo';
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### CommonJS
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const Pajo = require('@arc-js/pajo').default;
|
|
67
|
+
// ou
|
|
68
|
+
const { Pajo } = require('@arc-js/pajo');
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Navigateur (global)
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<script src="@arc-js/pajo/pajo.all.js"></script>
|
|
75
|
+
<script>
|
|
76
|
+
// Disponible globalement via window.Pajo
|
|
77
|
+
console.log(Pajo.join('path', 'to', 'file.txt'));
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Deno
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import Pajo from '@arc-js/pajo';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 📚 Documentation API
|
|
88
|
+
|
|
89
|
+
### Méthodes Statiques
|
|
90
|
+
|
|
91
|
+
#### `Pajo.join(...paths: string[]): string | undefined`
|
|
92
|
+
Joint plusieurs segments de chemin en normalisant les séparateurs.
|
|
93
|
+
|
|
94
|
+
**Paramètres:**
|
|
95
|
+
- `paths`: Segments de chemin à joindre (peut être vide)
|
|
96
|
+
|
|
97
|
+
**Retourne:** Le chemin normalisé ou `undefined` si aucun chemin valide
|
|
98
|
+
|
|
99
|
+
**Exemples:**
|
|
100
|
+
```typescript
|
|
101
|
+
// Chemins Unix
|
|
102
|
+
Pajo.join('/var', 'www', 'html'); // "/var/www/html"
|
|
103
|
+
Pajo.join('/usr/', '/local/', '/bin'); // "/usr/local/bin"
|
|
104
|
+
Pajo.join('./src', './utils', '../components'); // "src/components"
|
|
105
|
+
|
|
106
|
+
// Chemins Windows
|
|
107
|
+
Pajo.join('C:\\Users', 'Documents', 'file.txt'); // "C:\\Users\\Documents\\file.txt"
|
|
108
|
+
Pajo.join('D:\\Projects\\', '\\src\\', '\\app.js'); // "D:\\Projects\\src\\app.js"
|
|
109
|
+
|
|
110
|
+
// Chemins mixtes
|
|
111
|
+
Pajo.join('path', 'to', 'file.txt'); // "path/to/file.txt"
|
|
112
|
+
Pajo.join('path/', '//to/', 'file.txt'); // "path/to/file.txt"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `Pajo.joinWithHost(host: string, ...paths: string[]): string | undefined`
|
|
116
|
+
Joint un hôte avec des segments de chemin pour former une URL.
|
|
117
|
+
|
|
118
|
+
**Paramètres:**
|
|
119
|
+
- `host`: Hôte (peut inclure le protocole)
|
|
120
|
+
- `paths`: Segments de chemin à joindre
|
|
121
|
+
|
|
122
|
+
**Retourne:** L'URL complète normalisée ou `undefined` si invalide
|
|
123
|
+
|
|
124
|
+
**Exemples:**
|
|
125
|
+
```typescript
|
|
126
|
+
Pajo.joinWithHost('example.com', 'api', 'v1', 'users');
|
|
127
|
+
// "https://example.com/api/v1/users"
|
|
128
|
+
|
|
129
|
+
Pajo.joinWithHost('https://example.com', 'api', 'v1');
|
|
130
|
+
// "https://example.com/api/v1"
|
|
131
|
+
|
|
132
|
+
Pajo.joinWithHost('myserver.com', '/var', 'log', 'app.log');
|
|
133
|
+
// "https://myserver.com/var/log/app.log"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### `Pajo.resolve(...paths: string[]): string | undefined`
|
|
137
|
+
Résout les chemins avec . et .. pour obtenir un chemin normalisé.
|
|
138
|
+
|
|
139
|
+
**Paramètres:**
|
|
140
|
+
- `paths`: Segments de chemin à résoudre
|
|
141
|
+
|
|
142
|
+
**Retourne:** Chemin résolu ou `undefined` si invalide
|
|
143
|
+
|
|
144
|
+
**Exemples:**
|
|
145
|
+
```typescript
|
|
146
|
+
Pajo.resolve('/foo/bar', './baz'); // "/foo/bar/baz"
|
|
147
|
+
Pajo.resolve('/foo/bar', '../baz'); // "/foo/baz"
|
|
148
|
+
Pajo.resolve('C:\\foo\\bar', '..\\baz'); // "C:\\foo\\baz"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### `Pajo.isAbsolute(path: string): boolean`
|
|
152
|
+
Vérifie si un chemin est absolu.
|
|
153
|
+
|
|
154
|
+
**Paramètres:**
|
|
155
|
+
- `path`: Chemin à vérifier
|
|
156
|
+
|
|
157
|
+
**Retourne:** `true` si le chemin est absolu
|
|
158
|
+
|
|
159
|
+
**Exemples:**
|
|
160
|
+
```typescript
|
|
161
|
+
Pajo.isAbsolute('/path/to/file'); // true
|
|
162
|
+
Pajo.isAbsolute('C:\\Windows\\System32'); // true
|
|
163
|
+
Pajo.isAbsolute('https://example.com'); // true
|
|
164
|
+
Pajo.isAbsolute('relative/path'); // false
|
|
165
|
+
Pajo.isAbsolute('./file.txt'); // false
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### `Pajo.dirname(path: string): string | undefined`
|
|
169
|
+
Extrait le répertoire parent d'un chemin.
|
|
170
|
+
|
|
171
|
+
**Paramètres:**
|
|
172
|
+
- `path`: Chemin source
|
|
173
|
+
|
|
174
|
+
**Retourne:** Le répertoire parent ou `undefined`
|
|
175
|
+
|
|
176
|
+
**Exemples:**
|
|
177
|
+
```typescript
|
|
178
|
+
Pajo.dirname('/path/to/file.txt'); // "/path/to"
|
|
179
|
+
Pajo.dirname('C:\\Users\\file.txt'); // "C:\\Users"
|
|
180
|
+
Pajo.dirname('file.txt'); // "."
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### `Pajo.basename(path: string, ext?: string): string | undefined`
|
|
184
|
+
Extrait le nom de fichier d'un chemin.
|
|
185
|
+
|
|
186
|
+
**Paramètres:**
|
|
187
|
+
- `path`: Chemin source
|
|
188
|
+
- `ext` (optionnel): Extension à retirer
|
|
189
|
+
|
|
190
|
+
**Retourne:** Le nom de fichier ou `undefined`
|
|
191
|
+
|
|
192
|
+
**Exemples:**
|
|
193
|
+
```typescript
|
|
194
|
+
Pajo.basename('/path/to/file.txt'); // "file.txt"
|
|
195
|
+
Pajo.basename('/path/to/file.txt', '.txt'); // "file"
|
|
196
|
+
Pajo.basename('C:\\Users\\document.pdf'); // "document.pdf"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### `Pajo.extname(path: string): string | undefined`
|
|
200
|
+
Extrait l'extension d'un fichier.
|
|
201
|
+
|
|
202
|
+
**Paramètres:**
|
|
203
|
+
- `path`: Chemin source
|
|
204
|
+
|
|
205
|
+
**Retourne:** L'extension (incluant le point) ou `undefined`
|
|
206
|
+
|
|
207
|
+
**Exemples:**
|
|
208
|
+
```typescript
|
|
209
|
+
Pajo.extname('/path/to/file.txt'); // ".txt"
|
|
210
|
+
Pajo.extname('document.pdf'); // ".pdf"
|
|
211
|
+
Pajo.extname('file.with.many.dots.tar.gz'); // ".gz"
|
|
212
|
+
Pajo.extname('noextension'); // undefined
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `Pajo.toUnixPath(path: string): string`
|
|
216
|
+
Convertit un chemin Windows en chemin Unix.
|
|
217
|
+
|
|
218
|
+
**Paramètres:**
|
|
219
|
+
- `path`: Chemin Windows
|
|
220
|
+
|
|
221
|
+
**Retourne:** Chemin Unix
|
|
222
|
+
|
|
223
|
+
**Exemples:**
|
|
224
|
+
```typescript
|
|
225
|
+
Pajo.toUnixPath('C:\\Users\\file.txt'); // "C:/Users/file.txt"
|
|
226
|
+
Pajo.toUnixPath('D:\\Projects\\src'); // "D:/Projects/src"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### `Pajo.toWindowsPath(path: string): string`
|
|
230
|
+
Convertit un chemin Unix en chemin Windows.
|
|
231
|
+
|
|
232
|
+
**Paramètres:**
|
|
233
|
+
- `path`: Chemin Unix
|
|
234
|
+
|
|
235
|
+
**Retourne:** Chemin Windows
|
|
236
|
+
|
|
237
|
+
**Exemples:**
|
|
238
|
+
```typescript
|
|
239
|
+
Pajo.toWindowsPath('/home/user/file.txt'); // "\\home\\user\\file.txt"
|
|
240
|
+
Pajo.toWindowsPath('C:/Users/document'); // "C:\\Users\\document"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### `Pajo.exposeToGlobal(): void`
|
|
244
|
+
Expose la classe Pajo à l'objet global (window) pour une utilisation dans les navigateurs.
|
|
245
|
+
|
|
246
|
+
**Exemple:**
|
|
247
|
+
```javascript
|
|
248
|
+
// Dans un navigateur, après avoir chargé le script
|
|
249
|
+
Pajo.exposeToGlobal();
|
|
250
|
+
console.log(window.Pajo); // La classe Pajo est disponible
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## 🔧 Utilisation Détaillée
|
|
254
|
+
|
|
255
|
+
### Gestion Multi-Plateforme
|
|
256
|
+
|
|
257
|
+
Pajo détecte automatiquement le style de chemin basé sur le contenu :
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// Détection automatique du style
|
|
261
|
+
Pajo.join('C:\\Users', 'Documents'); // Style Windows
|
|
262
|
+
Pajo.join('/home', 'user'); // Style Unix
|
|
263
|
+
Pajo.join('relative', 'path'); // Style Unix par défaut
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Construction d'URLs
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// Construction d'URLs avec protocole automatique
|
|
270
|
+
Pajo.joinWithHost('api.example.com', 'v1', 'users');
|
|
271
|
+
// → "https://api.example.com/v1/users"
|
|
272
|
+
|
|
273
|
+
// Avec protocole explicite
|
|
274
|
+
Pajo.joinWithHost('http://localhost:3000', 'api', 'data');
|
|
275
|
+
// → "http://localhost:3000/api/data"
|
|
276
|
+
|
|
277
|
+
// Avec chemin absolu sur l'hôte
|
|
278
|
+
Pajo.joinWithHost('example.com', '/absolute/path');
|
|
279
|
+
// → "https://example.com/absolute/path"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Résolution de Chemins Relatifs
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Résolution des chemins avec .. et .
|
|
286
|
+
Pajo.resolve('/usr/local/bin', '..', 'share');
|
|
287
|
+
// → "/usr/local/share"
|
|
288
|
+
|
|
289
|
+
Pajo.resolve('C:\\Program Files\\App', '..', 'Common Files');
|
|
290
|
+
// → "C:\\Program Files\\Common Files"
|
|
291
|
+
|
|
292
|
+
Pajo.resolve('./src', '../lib', './utils');
|
|
293
|
+
// → "lib/utils"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Extraction d'Informations
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const path = '/var/www/html/index.html';
|
|
300
|
+
|
|
301
|
+
Pajo.dirname(path); // "/var/www/html"
|
|
302
|
+
Pajo.basename(path); // "index.html"
|
|
303
|
+
Pajo.extname(path); // ".html"
|
|
304
|
+
Pajo.isAbsolute(path); // true
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## 🎯 Exemples Complets
|
|
308
|
+
|
|
309
|
+
### Exemple 1 : Gestion de Chemins dans une Application
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import Pajo from '@arc-js/pajo';
|
|
313
|
+
|
|
314
|
+
class FileManager {
|
|
315
|
+
private baseDir: string;
|
|
316
|
+
|
|
317
|
+
constructor(baseDir: string) {
|
|
318
|
+
this.baseDir = baseDir;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
getFilePath(...segments: string[]): string {
|
|
322
|
+
const fullPath = Pajo.join(this.baseDir, ...segments);
|
|
323
|
+
return Pajo.resolve(fullPath) || fullPath;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
getFileInfo(path: string) {
|
|
327
|
+
return {
|
|
328
|
+
directory: Pajo.dirname(path),
|
|
329
|
+
filename: Pajo.basename(path),
|
|
330
|
+
extension: Pajo.extname(path),
|
|
331
|
+
isAbsolute: Pajo.isAbsolute(path),
|
|
332
|
+
unixPath: Pajo.toUnixPath(path)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Utilisation
|
|
338
|
+
const manager = new FileManager('/var/www');
|
|
339
|
+
const filePath = manager.getFilePath('uploads', '..', 'images', 'photo.jpg');
|
|
340
|
+
console.log(filePath); // "/var/images/photo.jpg"
|
|
341
|
+
|
|
342
|
+
const info = manager.getFileInfo(filePath);
|
|
343
|
+
console.log(info);
|
|
344
|
+
// {
|
|
345
|
+
// directory: "/var/images",
|
|
346
|
+
// filename: "photo.jpg",
|
|
347
|
+
// extension: ".jpg",
|
|
348
|
+
// isAbsolute: true,
|
|
349
|
+
// unixPath: "/var/images/photo.jpg"
|
|
350
|
+
// }
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Exemple 2 : Construction d'APIs REST
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import Pajo from '@arc-js/pajo';
|
|
357
|
+
|
|
358
|
+
class ApiClient {
|
|
359
|
+
private baseUrl: string;
|
|
360
|
+
|
|
361
|
+
constructor(baseUrl: string) {
|
|
362
|
+
this.baseUrl = baseUrl;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
buildUrl(endpoint: string, ...params: string[]): string {
|
|
366
|
+
return Pajo.joinWithHost(this.baseUrl, endpoint, ...params) || '';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async getResource(endpoint: string, id?: string) {
|
|
370
|
+
const url = id
|
|
371
|
+
? this.buildUrl(endpoint, id)
|
|
372
|
+
: this.buildUrl(endpoint);
|
|
373
|
+
|
|
374
|
+
const response = await fetch(url);
|
|
375
|
+
return response.json();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Utilisation
|
|
380
|
+
const api = new ApiClient('https://api.example.com');
|
|
381
|
+
|
|
382
|
+
// Construire des URLs
|
|
383
|
+
const usersUrl = api.buildUrl('users');
|
|
384
|
+
// → "https://api.example.com/users"
|
|
385
|
+
|
|
386
|
+
const userUrl = api.buildUrl('users', '123');
|
|
387
|
+
// → "https://api.example.com/users/123"
|
|
388
|
+
|
|
389
|
+
// Récupérer des données
|
|
390
|
+
const users = await api.getResource('users');
|
|
391
|
+
const user = await api.getResource('users', '123');
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Exemple 3 : Migration Multi-Plateforme
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import Pajo from '@arc-js/pajo';
|
|
398
|
+
|
|
399
|
+
function migratePath(oldPath: string, newBase: string): string {
|
|
400
|
+
// Normaliser le chemin d'entrée
|
|
401
|
+
const normalized = Pajo.resolve(oldPath);
|
|
402
|
+
if (!normalized) return newBase;
|
|
403
|
+
|
|
404
|
+
// Extraire le nom de fichier
|
|
405
|
+
const filename = Pajo.basename(normalized);
|
|
406
|
+
|
|
407
|
+
// Construire le nouveau chemin
|
|
408
|
+
return Pajo.join(newBase, filename);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Migration depuis Windows vers Unix
|
|
412
|
+
const windowsPath = 'C:\\Users\\John\\Documents\\file.txt';
|
|
413
|
+
const unixBase = '/home/john/files';
|
|
414
|
+
|
|
415
|
+
const migrated = migratePath(windowsPath, unixBase);
|
|
416
|
+
console.log(migrated); // "/home/john/files/file.txt"
|
|
417
|
+
|
|
418
|
+
// Conversion explicite si nécessaire
|
|
419
|
+
console.log(Pajo.toUnixPath(windowsPath)); // "C:/Users/John/Documents/file.txt"
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 🔧 Configuration Avancée
|
|
423
|
+
|
|
424
|
+
### Personnalisation du Style de Chemin
|
|
425
|
+
|
|
426
|
+
Bien que Pajo détecte automatiquement le style, vous pouvez forcer un style spécifique :
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
function forceWindowsPath(...segments: string[]): string {
|
|
430
|
+
// Ajouter un préfixe Windows pour forcer le style
|
|
431
|
+
return Pajo.join('C:\\forced', ...segments).replace('C:\\forced\\', '');
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function forceUnixPath(...segments: string[]): string {
|
|
435
|
+
// Ajouter un slash initial pour forcer le style Unix
|
|
436
|
+
return Pajo.join('/forced', ...segments).replace('/forced/', '');
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Extension pour les Chemins d'URL
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
class UrlPath extends Pajo {
|
|
444
|
+
static normalizeUrlPath(path: string): string {
|
|
445
|
+
// Pour les URLs, on utilise toujours des slashs
|
|
446
|
+
return path.replace(/\\/g, '/').replace(/\/+/g, '/');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
static buildQueryString(params: Record<string, any>): string {
|
|
450
|
+
const query = new URLSearchParams();
|
|
451
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
452
|
+
if (value !== undefined && value !== null) {
|
|
453
|
+
query.append(key, String(value));
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
const queryString = query.toString();
|
|
457
|
+
return queryString ? `?\${queryString}` : '';
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
static joinWithQuery(host: string, path: string, queryParams?: Record<string, any>): string {
|
|
461
|
+
const url = this.joinWithHost(host, path);
|
|
462
|
+
if (!url || !queryParams) return url || '';
|
|
463
|
+
|
|
464
|
+
const query = this.buildQueryString(queryParams);
|
|
465
|
+
return `\${url}\${query}`;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Utilisation
|
|
470
|
+
const url = UrlPath.joinWithQuery(
|
|
471
|
+
'example.com',
|
|
472
|
+
'api/search',
|
|
473
|
+
{ q: 'test', page: 1 }
|
|
474
|
+
);
|
|
475
|
+
console.log(url); // "https://example.com/api/search?q=test&page=1"
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## 📋 Table de Compatibilité
|
|
479
|
+
|
|
480
|
+
### Caractères Spéciaux Supportés
|
|
481
|
+
|
|
482
|
+
| Caractère | Description | Exemple |
|
|
483
|
+
|-----------|-------------|---------|
|
|
484
|
+
| . | Répertoire courant | `./file.txt` |
|
|
485
|
+
| .. | Répertoire parent | `../parent/file.txt` |
|
|
486
|
+
| ~ | Répertoire home (Unix) | `~/.config/app` |
|
|
487
|
+
| \\ | Séparateur Windows | `C:\\Users\\file.txt` |
|
|
488
|
+
| / | Séparateur Unix | `/home/user/file.txt` |
|
|
489
|
+
|
|
490
|
+
### Plates-formes Supportées
|
|
491
|
+
|
|
492
|
+
| Plate-forme | Support | Notes |
|
|
493
|
+
|-------------|---------|-------|
|
|
494
|
+
| Windows | ✅ Complet | Détection automatique des chemins Windows |
|
|
495
|
+
| Linux | ✅ Complet | Détection automatique des chemins Unix |
|
|
496
|
+
| macOS | ✅ Complet | Identique à Linux |
|
|
497
|
+
| Navigateurs | ✅ Complet | Via CDN ou module ES |
|
|
498
|
+
| Node.js | ✅ Complet | v18+ recommandé |
|
|
499
|
+
| Deno | ✅ Complet | Via esm.sh ou npm: |
|
|
500
|
+
| Bun | ✅ Complet | Support natif des modules ES |
|
|
501
|
+
|
|
502
|
+
## 🚨 Gestion des Cas Limites
|
|
503
|
+
|
|
504
|
+
### Chemins Vides ou Nuls
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
Pajo.join(); // undefined
|
|
508
|
+
Pajo.join(''); // undefined
|
|
509
|
+
Pajo.join('', 'path'); // "path"
|
|
510
|
+
Pajo.join('path', '', 'file'); // "path/file"
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Séparateurs Multiples
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
Pajo.join('path///', '//to/', 'file.txt'); // "path/to/file.txt"
|
|
517
|
+
Pajo.join('C:\\\\Windows', '\\\\System32'); // "C:\\\\Windows\\\\System32"
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Chemins avec Points
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
Pajo.join('..', 'parent', 'file.txt'); // "../parent/file.txt"
|
|
524
|
+
Pajo.join('.', 'current', 'file.txt'); // "current/file.txt"
|
|
525
|
+
Pajo.join('path..', 'file.txt'); // "path../file.txt"
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### URLs et Protocoles
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
Pajo.joinWithHost('https://example.com'); // "https://example.com"
|
|
532
|
+
Pajo.joinWithHost('ftp://server.com', 'files'); // "ftp://server.com/files"
|
|
533
|
+
Pajo.joinWithHost('file:///C:/Users', 'doc.txt'); // "file:///C:/Users/doc.txt"
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
## 🔧 Build et Développement
|
|
537
|
+
|
|
538
|
+
### Structure du Projet
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
@arc-js/pajo/
|
|
542
|
+
├── pajo.all.js
|
|
543
|
+
├── pajo.all.min.js
|
|
544
|
+
├── index.d.ts
|
|
545
|
+
├── index.js
|
|
546
|
+
├── index.min.d.ts
|
|
547
|
+
├── index.min.js
|
|
548
|
+
├── package.json
|
|
549
|
+
├── tsconfig.json
|
|
550
|
+
└── README.md
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
## 📄 Licence
|
|
554
|
+
|
|
555
|
+
MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
|
556
|
+
|
|
557
|
+
## 🐛 Signaler un Bug
|
|
558
|
+
|
|
559
|
+
Envoyez nous un mail à l'adresse `contact.inicode@gmail.com` pour :
|
|
560
|
+
- Signaler un bug
|
|
561
|
+
- Proposer une amélioration
|
|
562
|
+
- Poser une question
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
**@arc-js/pajo** - Manipulation de chemins multi-plateforme, simple et robuste.
|
|
567
|
+
|
|
568
|
+
*Développé par l'équipe INICODE*
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
Pajo: typeof Pajo;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
declare class Pajo {
|
|
7
|
+
private static readonly PROTOCOL_REGEX;
|
|
8
|
+
private static readonly DOUBLE_SLASH_REGEX;
|
|
9
|
+
private static readonly DOUBLE_BACKSLASH_REGEX;
|
|
10
|
+
private static readonly TRAILING_SLASH_REGEX;
|
|
11
|
+
private static readonly TRAILING_BACKSLASH_REGEX;
|
|
12
|
+
private static readonly LEADING_SLASH_REGEX;
|
|
13
|
+
private static readonly WINDOWS_DRIVE_REGEX;
|
|
14
|
+
private static readonly MIXED_SEPARATORS_REGEX;
|
|
15
|
+
/**
|
|
16
|
+
* Joint plusieurs segments de chemin en normalisant les séparateurs
|
|
17
|
+
* @param paths Segments de chemin à joindre
|
|
18
|
+
* @returns Le chemin normalisé ou undefined si aucun chemin valide
|
|
19
|
+
*/
|
|
20
|
+
static join(...paths: string[]): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Joint un hôte avec des segments de chemin
|
|
23
|
+
* @param host Hôte (peut inclure le protocole)
|
|
24
|
+
* @param paths Segments de chemin à joindre
|
|
25
|
+
* @returns L'URL complète normalisée ou undefined si invalide
|
|
26
|
+
*/
|
|
27
|
+
static joinWithHost(host: string, ...paths: string[]): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Normalise un segment de chemin individuel
|
|
30
|
+
* @param path Segment de chemin à normaliser
|
|
31
|
+
* @param isWindowsStyle Si on doit utiliser le style Windows
|
|
32
|
+
* @returns Le segment normalisé
|
|
33
|
+
*/
|
|
34
|
+
private static normalizePathSegment;
|
|
35
|
+
/**
|
|
36
|
+
* Vérifie si le chemin est un chemin Windows
|
|
37
|
+
* @param path Chemin à vérifier
|
|
38
|
+
* @returns True si c'est un chemin Windows
|
|
39
|
+
*/
|
|
40
|
+
private static isWindowsPath;
|
|
41
|
+
/**
|
|
42
|
+
* Résout les chemins avec . et .. (simplifié)
|
|
43
|
+
* @param paths Segments de chemin à résoudre
|
|
44
|
+
* @returns Chemin résolu
|
|
45
|
+
*/
|
|
46
|
+
static resolve(...paths: string[]): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Vérifie si un chemin est absolu
|
|
49
|
+
* @param path Chemin à vérifier
|
|
50
|
+
* @returns True si le chemin est absolu
|
|
51
|
+
*/
|
|
52
|
+
static isAbsolute(path: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Extrait le répertoire parent d'un chemin
|
|
55
|
+
* @param path Chemin source
|
|
56
|
+
* @returns Le répertoire parent ou undefined
|
|
57
|
+
*/
|
|
58
|
+
static dirname(path: string): string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Extrait le nom de fichier d'un chemin
|
|
61
|
+
* @param path Chemin source
|
|
62
|
+
* @param ext Extension optionnelle à retirer
|
|
63
|
+
* @returns Le nom de fichier ou undefined
|
|
64
|
+
*/
|
|
65
|
+
static basename(path: string, ext?: string): string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Extrait l'extension d'un fichier
|
|
68
|
+
* @param path Chemin source
|
|
69
|
+
* @returns L'extension ou undefined
|
|
70
|
+
*/
|
|
71
|
+
static extname(path: string): string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Convertit un chemin Windows en chemin Unix
|
|
74
|
+
* @param path Chemin Windows
|
|
75
|
+
* @returns Chemin Unix
|
|
76
|
+
*/
|
|
77
|
+
static toUnixPath(path: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Convertit un chemin Unix en chemin Windows
|
|
80
|
+
* @param path Chemin Unix
|
|
81
|
+
* @returns Chemin Windows
|
|
82
|
+
*/
|
|
83
|
+
static toWindowsPath(path: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* Exposition globale de la classe
|
|
86
|
+
*/
|
|
87
|
+
static exposeToGlobal(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { Pajo, Pajo as default };
|
package/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
class Pajo {
|
|
2
|
+
static PROTOCOL_REGEX = /^[a-zA-Z]+:\/\//;
|
|
3
|
+
static DOUBLE_SLASH_REGEX = /\/+/g;
|
|
4
|
+
static DOUBLE_BACKSLASH_REGEX = /\\+/g;
|
|
5
|
+
static TRAILING_SLASH_REGEX = /\/+$/;
|
|
6
|
+
static TRAILING_BACKSLASH_REGEX = /\\+$/;
|
|
7
|
+
static LEADING_SLASH_REGEX = /^\/+/;
|
|
8
|
+
static WINDOWS_DRIVE_REGEX = /^[a-zA-Z]:\\/;
|
|
9
|
+
static MIXED_SEPARATORS_REGEX = /[\\/]+/g;
|
|
10
|
+
static join(...paths) {
|
|
11
|
+
if (paths.length === 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
const isWindowsPath = paths.some(path => this.isWindowsPath(path));
|
|
14
|
+
const cleanPaths = paths
|
|
15
|
+
.filter(path => path != null && path.trim().length > 0)
|
|
16
|
+
.map(path => this.normalizePathSegment(path, isWindowsPath));
|
|
17
|
+
if (cleanPaths.length === 0)
|
|
18
|
+
return undefined;
|
|
19
|
+
const separator = isWindowsPath ? '\\' : '/';
|
|
20
|
+
let result = cleanPaths.join(separator);
|
|
21
|
+
if (isWindowsPath) {
|
|
22
|
+
result = result.replace(this.DOUBLE_BACKSLASH_REGEX, '\\');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
result = result.replace(this.DOUBLE_SLASH_REGEX, '/');
|
|
26
|
+
const hasLeadingSlash = paths[0]?.startsWith('/') || false;
|
|
27
|
+
if (hasLeadingSlash && !result.startsWith('/')) {
|
|
28
|
+
result = '/' + result;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result || undefined;
|
|
32
|
+
}
|
|
33
|
+
static joinWithHost(host, ...paths) {
|
|
34
|
+
if (!host || host.trim().length === 0) {
|
|
35
|
+
return this.join(...paths);
|
|
36
|
+
}
|
|
37
|
+
const cleanHost = host.trim().replace(this.TRAILING_SLASH_REGEX, '');
|
|
38
|
+
const hasProtocol = this.PROTOCOL_REGEX.test(cleanHost);
|
|
39
|
+
const normalizedHost = hasProtocol ? cleanHost : `https://${cleanHost}`;
|
|
40
|
+
const joinedPath = this.join(...paths);
|
|
41
|
+
if (!joinedPath) {
|
|
42
|
+
return normalizedHost;
|
|
43
|
+
}
|
|
44
|
+
const cleanPath = joinedPath.replace(/\\/g, '/').replace(this.LEADING_SLASH_REGEX, '');
|
|
45
|
+
return `${normalizedHost}/${cleanPath}`;
|
|
46
|
+
}
|
|
47
|
+
static normalizePathSegment(path, isWindowsStyle) {
|
|
48
|
+
if (!path || path.trim().length === 0)
|
|
49
|
+
return '';
|
|
50
|
+
const trimmed = path.trim();
|
|
51
|
+
if (isWindowsStyle) {
|
|
52
|
+
return trimmed
|
|
53
|
+
.replace(this.DOUBLE_BACKSLASH_REGEX, '\\')
|
|
54
|
+
.replace(this.TRAILING_BACKSLASH_REGEX, '');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return trimmed
|
|
58
|
+
.replace(this.DOUBLE_SLASH_REGEX, '/')
|
|
59
|
+
.replace(this.TRAILING_SLASH_REGEX, '');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
static isWindowsPath(path) {
|
|
63
|
+
return this.WINDOWS_DRIVE_REGEX.test(path) || path.includes('\\');
|
|
64
|
+
}
|
|
65
|
+
static resolve(...paths) {
|
|
66
|
+
const joined = this.join(...paths);
|
|
67
|
+
if (!joined)
|
|
68
|
+
return undefined;
|
|
69
|
+
const isWindows = this.isWindowsPath(joined);
|
|
70
|
+
const separator = isWindows ? '\\' : '/';
|
|
71
|
+
const parts = joined.split(separator);
|
|
72
|
+
const resolved = [];
|
|
73
|
+
for (const part of parts) {
|
|
74
|
+
if (part === '..') {
|
|
75
|
+
if (resolved.length > 0 && resolved[resolved.length - 1] !== '..') {
|
|
76
|
+
resolved.pop();
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
resolved.push(part);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (part !== '.' && part !== '') {
|
|
83
|
+
resolved.push(part);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let result = resolved.join(separator);
|
|
87
|
+
if (isWindows && this.WINDOWS_DRIVE_REGEX.test(parts[0])) {
|
|
88
|
+
result = parts[0] + separator + result;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
static isAbsolute(path) {
|
|
93
|
+
if (!path)
|
|
94
|
+
return false;
|
|
95
|
+
return path.startsWith('/') ||
|
|
96
|
+
this.WINDOWS_DRIVE_REGEX.test(path) ||
|
|
97
|
+
this.PROTOCOL_REGEX.test(path);
|
|
98
|
+
}
|
|
99
|
+
static dirname(path) {
|
|
100
|
+
if (!path)
|
|
101
|
+
return undefined;
|
|
102
|
+
const isWindows = this.isWindowsPath(path);
|
|
103
|
+
const separator = isWindows ? '\\' : '/';
|
|
104
|
+
const normalized = this.normalizePathSegment(path, isWindows);
|
|
105
|
+
const lastSeparatorIndex = normalized.lastIndexOf(separator);
|
|
106
|
+
if (lastSeparatorIndex === -1)
|
|
107
|
+
return isWindows ? '.' : '.';
|
|
108
|
+
if (lastSeparatorIndex === 0)
|
|
109
|
+
return isWindows ? normalized.substring(0, 2) : '/';
|
|
110
|
+
return normalized.substring(0, lastSeparatorIndex) || (isWindows ? '.' : '/');
|
|
111
|
+
}
|
|
112
|
+
static basename(path, ext) {
|
|
113
|
+
if (!path)
|
|
114
|
+
return undefined;
|
|
115
|
+
const isWindows = this.isWindowsPath(path);
|
|
116
|
+
const separator = isWindows ? '\\' : '/';
|
|
117
|
+
const normalized = this.normalizePathSegment(path, isWindows);
|
|
118
|
+
const lastSeparatorIndex = normalized.lastIndexOf(separator);
|
|
119
|
+
let basename = lastSeparatorIndex === -1 ? normalized : normalized.substring(lastSeparatorIndex + 1);
|
|
120
|
+
if (ext && basename.endsWith(ext)) {
|
|
121
|
+
basename = basename.substring(0, basename.length - ext.length);
|
|
122
|
+
}
|
|
123
|
+
return basename || undefined;
|
|
124
|
+
}
|
|
125
|
+
static extname(path) {
|
|
126
|
+
if (!path)
|
|
127
|
+
return undefined;
|
|
128
|
+
const basename = this.basename(path);
|
|
129
|
+
if (!basename)
|
|
130
|
+
return undefined;
|
|
131
|
+
const lastDotIndex = basename.lastIndexOf('.');
|
|
132
|
+
return lastDotIndex > 0 ? basename.substring(lastDotIndex) : undefined;
|
|
133
|
+
}
|
|
134
|
+
static toUnixPath(path) {
|
|
135
|
+
return path.replace(/\\/g, '/');
|
|
136
|
+
}
|
|
137
|
+
static toWindowsPath(path) {
|
|
138
|
+
return path.replace(/\//g, '\\');
|
|
139
|
+
}
|
|
140
|
+
static exposeToGlobal() {
|
|
141
|
+
if (typeof window !== "undefined") {
|
|
142
|
+
window.Pajo = Pajo;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (typeof window !== "undefined") {
|
|
147
|
+
Pajo.exposeToGlobal();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { Pajo, Pajo as default };
|
package/index.min.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
Pajo: typeof Pajo;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
declare class Pajo {
|
|
7
|
+
private static readonly PROTOCOL_REGEX;
|
|
8
|
+
private static readonly DOUBLE_SLASH_REGEX;
|
|
9
|
+
private static readonly DOUBLE_BACKSLASH_REGEX;
|
|
10
|
+
private static readonly TRAILING_SLASH_REGEX;
|
|
11
|
+
private static readonly TRAILING_BACKSLASH_REGEX;
|
|
12
|
+
private static readonly LEADING_SLASH_REGEX;
|
|
13
|
+
private static readonly WINDOWS_DRIVE_REGEX;
|
|
14
|
+
private static readonly MIXED_SEPARATORS_REGEX;
|
|
15
|
+
/**
|
|
16
|
+
* Joint plusieurs segments de chemin en normalisant les séparateurs
|
|
17
|
+
* @param paths Segments de chemin à joindre
|
|
18
|
+
* @returns Le chemin normalisé ou undefined si aucun chemin valide
|
|
19
|
+
*/
|
|
20
|
+
static join(...paths: string[]): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Joint un hôte avec des segments de chemin
|
|
23
|
+
* @param host Hôte (peut inclure le protocole)
|
|
24
|
+
* @param paths Segments de chemin à joindre
|
|
25
|
+
* @returns L'URL complète normalisée ou undefined si invalide
|
|
26
|
+
*/
|
|
27
|
+
static joinWithHost(host: string, ...paths: string[]): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Normalise un segment de chemin individuel
|
|
30
|
+
* @param path Segment de chemin à normaliser
|
|
31
|
+
* @param isWindowsStyle Si on doit utiliser le style Windows
|
|
32
|
+
* @returns Le segment normalisé
|
|
33
|
+
*/
|
|
34
|
+
private static normalizePathSegment;
|
|
35
|
+
/**
|
|
36
|
+
* Vérifie si le chemin est un chemin Windows
|
|
37
|
+
* @param path Chemin à vérifier
|
|
38
|
+
* @returns True si c'est un chemin Windows
|
|
39
|
+
*/
|
|
40
|
+
private static isWindowsPath;
|
|
41
|
+
/**
|
|
42
|
+
* Résout les chemins avec . et .. (simplifié)
|
|
43
|
+
* @param paths Segments de chemin à résoudre
|
|
44
|
+
* @returns Chemin résolu
|
|
45
|
+
*/
|
|
46
|
+
static resolve(...paths: string[]): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Vérifie si un chemin est absolu
|
|
49
|
+
* @param path Chemin à vérifier
|
|
50
|
+
* @returns True si le chemin est absolu
|
|
51
|
+
*/
|
|
52
|
+
static isAbsolute(path: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Extrait le répertoire parent d'un chemin
|
|
55
|
+
* @param path Chemin source
|
|
56
|
+
* @returns Le répertoire parent ou undefined
|
|
57
|
+
*/
|
|
58
|
+
static dirname(path: string): string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Extrait le nom de fichier d'un chemin
|
|
61
|
+
* @param path Chemin source
|
|
62
|
+
* @param ext Extension optionnelle à retirer
|
|
63
|
+
* @returns Le nom de fichier ou undefined
|
|
64
|
+
*/
|
|
65
|
+
static basename(path: string, ext?: string): string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Extrait l'extension d'un fichier
|
|
68
|
+
* @param path Chemin source
|
|
69
|
+
* @returns L'extension ou undefined
|
|
70
|
+
*/
|
|
71
|
+
static extname(path: string): string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Convertit un chemin Windows en chemin Unix
|
|
74
|
+
* @param path Chemin Windows
|
|
75
|
+
* @returns Chemin Unix
|
|
76
|
+
*/
|
|
77
|
+
static toUnixPath(path: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Convertit un chemin Unix en chemin Windows
|
|
80
|
+
* @param path Chemin Unix
|
|
81
|
+
* @returns Chemin Windows
|
|
82
|
+
*/
|
|
83
|
+
static toWindowsPath(path: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* Exposition globale de la classe
|
|
86
|
+
*/
|
|
87
|
+
static exposeToGlobal(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { Pajo, Pajo as default };
|
package/index.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class Pajo{static PROTOCOL_REGEX=/^[a-zA-Z]+:\/\//;static DOUBLE_SLASH_REGEX=/\/+/g;static DOUBLE_BACKSLASH_REGEX=/\\+/g;static TRAILING_SLASH_REGEX=/\/+$/;static TRAILING_BACKSLASH_REGEX=/\\+$/;static LEADING_SLASH_REGEX=/^\/+/;static WINDOWS_DRIVE_REGEX=/^[a-zA-Z]:\\/;static MIXED_SEPARATORS_REGEX=/[\\/]+/g;static join(...s){if(0!==s.length){let i=s.some(t=>this.isWindowsPath(t));var e=s.filter(t=>null!=t&&0<t.trim().length).map(t=>this.normalizePathSegment(t,i));if(0!==e.length){var a=i?"\\":"/";let t=e.join(a);return i?t=t.replace(this.DOUBLE_BACKSLASH_REGEX,"\\"):(t=t.replace(this.DOUBLE_SLASH_REGEX,"/"),s[0]?.startsWith("/")&&!t.startsWith("/")&&(t="/"+t)),t||void 0}}}static joinWithHost(t,...i){var s;return t&&0!==t.trim().length?(t=t.trim().replace(this.TRAILING_SLASH_REGEX,""),t=this.PROTOCOL_REGEX.test(t)?t:"https://"+t,(s=this.join(...i))?t+"/"+s.replace(/\\/g,"/").replace(this.LEADING_SLASH_REGEX,""):t):this.join(...i)}static normalizePathSegment(t,i){return t&&0!==t.trim().length?(t=t.trim(),i?t.replace(this.DOUBLE_BACKSLASH_REGEX,"\\").replace(this.TRAILING_BACKSLASH_REGEX,""):t.replace(this.DOUBLE_SLASH_REGEX,"/").replace(this.TRAILING_SLASH_REGEX,"")):""}static isWindowsPath(t){return this.WINDOWS_DRIVE_REGEX.test(t)||t.includes("\\")}static resolve(...i){i=this.join(...i);if(i){var s,e=this.isWindowsPath(i),a=e?"\\":"/",i=i.split(a),n=[];for(s of i)".."===s?0<n.length&&".."!==n[n.length-1]?n.pop():n.push(s):"."!==s&&""!==s&&n.push(s);let t=n.join(a);return t=e&&this.WINDOWS_DRIVE_REGEX.test(i[0])?i[0]+a+t:t}}static isAbsolute(t){return!!t&&(t.startsWith("/")||this.WINDOWS_DRIVE_REGEX.test(t)||this.PROTOCOL_REGEX.test(t))}static dirname(t){var i,s;if(t)return s=(i=this.isWindowsPath(t))?"\\":"/",-1===(s=(t=this.normalizePathSegment(t,i)).lastIndexOf(s))?".":0===s?i?t.substring(0,2):"/":t.substring(0,s)||(i?".":"/")}static basename(i,s){if(i){var e=this.isWindowsPath(i),a=e?"\\":"/",i=this.normalizePathSegment(i,e),e=i.lastIndexOf(a);let t=-1===e?i:i.substring(e+1);return(t=s&&t.endsWith(s)?t.substring(0,t.length-s.length):t)||void 0}}static extname(t){var i;return(t=t&&this.basename(t))&&0<(i=t.lastIndexOf("."))?t.substring(i):void 0}static toUnixPath(t){return t.replace(/\\/g,"/")}static toWindowsPath(t){return t.replace(/\//g,"\\")}static exposeToGlobal(){"undefined"!=typeof window&&(window.Pajo=Pajo)}}"undefined"!=typeof window&&Pajo.exposeToGlobal();export{Pajo,Pajo as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arc-js/pajo",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.0.1",
|
|
7
|
+
"description": "Pajo est une bibliothèque TypeScript légère et robuste pour la manipulation de chemins de fichiers et d'URLs. Elle offre une API unifiée et type-safe pour travailler avec des chemins de fichiers sur différentes plateformes (Windows, Linux, macOS) et pour construire des URLs de manière cohérente.",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"author": "INICODE <contact@inicode@gmail.com>",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"init": "npm init --scope=@arc-js/pajo",
|
|
14
|
+
"login": "npm login"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {},
|
|
17
|
+
"dependencies": {}
|
|
18
|
+
}
|
package/pajo.all.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
class Pajo {
|
|
2
|
+
static PROTOCOL_REGEX = /^[a-zA-Z]+:\/\//;
|
|
3
|
+
static DOUBLE_SLASH_REGEX = /\/+/g;
|
|
4
|
+
static DOUBLE_BACKSLASH_REGEX = /\\+/g;
|
|
5
|
+
static TRAILING_SLASH_REGEX = /\/+$/;
|
|
6
|
+
static TRAILING_BACKSLASH_REGEX = /\\+$/;
|
|
7
|
+
static LEADING_SLASH_REGEX = /^\/+/;
|
|
8
|
+
static WINDOWS_DRIVE_REGEX = /^[a-zA-Z]:\\/;
|
|
9
|
+
static MIXED_SEPARATORS_REGEX = /[\\/]+/g;
|
|
10
|
+
/**
|
|
11
|
+
* Joint plusieurs segments de chemin en normalisant les séparateurs
|
|
12
|
+
* @param paths Segments de chemin à joindre
|
|
13
|
+
* @returns Le chemin normalisé ou undefined si aucun chemin valide
|
|
14
|
+
*/
|
|
15
|
+
static join(...paths) {
|
|
16
|
+
if (paths.length === 0)
|
|
17
|
+
return undefined;
|
|
18
|
+
// Détection du style de chemin (Windows ou Unix)
|
|
19
|
+
const isWindowsPath = paths.some(path => this.isWindowsPath(path));
|
|
20
|
+
// Filtre les chemins vides et nettoie chaque segment
|
|
21
|
+
const cleanPaths = paths
|
|
22
|
+
.filter(path => path != null && path.trim().length > 0)
|
|
23
|
+
.map(path => this.normalizePathSegment(path, isWindowsPath));
|
|
24
|
+
if (cleanPaths.length === 0)
|
|
25
|
+
return undefined;
|
|
26
|
+
// Reconstruction du chemin final avec le séparateur approprié
|
|
27
|
+
const separator = isWindowsPath ? '\\' : '/';
|
|
28
|
+
let result = cleanPaths.join(separator);
|
|
29
|
+
// Normalisation des séparateurs multiples
|
|
30
|
+
if (isWindowsPath) {
|
|
31
|
+
result = result.replace(this.DOUBLE_BACKSLASH_REGEX, '\\');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
result = result.replace(this.DOUBLE_SLASH_REGEX, '/');
|
|
35
|
+
// Préservation du slash initial pour les chemins absolus Linux
|
|
36
|
+
const hasLeadingSlash = paths[0]?.startsWith('/') || false;
|
|
37
|
+
if (hasLeadingSlash && !result.startsWith('/')) {
|
|
38
|
+
result = '/' + result;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result || undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Joint un hôte avec des segments de chemin
|
|
45
|
+
* @param host Hôte (peut inclure le protocole)
|
|
46
|
+
* @param paths Segments de chemin à joindre
|
|
47
|
+
* @returns L'URL complète normalisée ou undefined si invalide
|
|
48
|
+
*/
|
|
49
|
+
static joinWithHost(host, ...paths) {
|
|
50
|
+
if (!host || host.trim().length === 0) {
|
|
51
|
+
return this.join(...paths);
|
|
52
|
+
}
|
|
53
|
+
const cleanHost = host.trim().replace(this.TRAILING_SLASH_REGEX, '');
|
|
54
|
+
// Vérification du protocole
|
|
55
|
+
const hasProtocol = this.PROTOCOL_REGEX.test(cleanHost);
|
|
56
|
+
const normalizedHost = hasProtocol ? cleanHost : `https://${cleanHost}`;
|
|
57
|
+
// Traitement des chemins
|
|
58
|
+
const joinedPath = this.join(...paths);
|
|
59
|
+
if (!joinedPath) {
|
|
60
|
+
return normalizedHost;
|
|
61
|
+
}
|
|
62
|
+
// Pour les URLs, on utilise toujours des slashs
|
|
63
|
+
const cleanPath = joinedPath.replace(/\\/g, '/').replace(this.LEADING_SLASH_REGEX, '');
|
|
64
|
+
return `${normalizedHost}/${cleanPath}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalise un segment de chemin individuel
|
|
68
|
+
* @param path Segment de chemin à normaliser
|
|
69
|
+
* @param isWindowsStyle Si on doit utiliser le style Windows
|
|
70
|
+
* @returns Le segment normalisé
|
|
71
|
+
*/
|
|
72
|
+
static normalizePathSegment(path, isWindowsStyle) {
|
|
73
|
+
if (!path || path.trim().length === 0)
|
|
74
|
+
return '';
|
|
75
|
+
const trimmed = path.trim();
|
|
76
|
+
if (isWindowsStyle) {
|
|
77
|
+
return trimmed
|
|
78
|
+
.replace(this.DOUBLE_BACKSLASH_REGEX, '\\')
|
|
79
|
+
.replace(this.TRAILING_BACKSLASH_REGEX, '');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return trimmed
|
|
83
|
+
.replace(this.DOUBLE_SLASH_REGEX, '/')
|
|
84
|
+
.replace(this.TRAILING_SLASH_REGEX, '');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Vérifie si le chemin est un chemin Windows
|
|
89
|
+
* @param path Chemin à vérifier
|
|
90
|
+
* @returns True si c'est un chemin Windows
|
|
91
|
+
*/
|
|
92
|
+
static isWindowsPath(path) {
|
|
93
|
+
return this.WINDOWS_DRIVE_REGEX.test(path) || path.includes('\\');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Résout les chemins avec . et .. (simplifié)
|
|
97
|
+
* @param paths Segments de chemin à résoudre
|
|
98
|
+
* @returns Chemin résolu
|
|
99
|
+
*/
|
|
100
|
+
static resolve(...paths) {
|
|
101
|
+
const joined = this.join(...paths);
|
|
102
|
+
if (!joined)
|
|
103
|
+
return undefined;
|
|
104
|
+
const isWindows = this.isWindowsPath(joined);
|
|
105
|
+
const separator = isWindows ? '\\' : '/';
|
|
106
|
+
const parts = joined.split(separator);
|
|
107
|
+
const resolved = [];
|
|
108
|
+
for (const part of parts) {
|
|
109
|
+
if (part === '..') {
|
|
110
|
+
if (resolved.length > 0 && resolved[resolved.length - 1] !== '..') {
|
|
111
|
+
resolved.pop();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
resolved.push(part);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (part !== '.' && part !== '') {
|
|
118
|
+
resolved.push(part);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let result = resolved.join(separator);
|
|
122
|
+
// Restauration du préfixe Windows si nécessaire
|
|
123
|
+
if (isWindows && this.WINDOWS_DRIVE_REGEX.test(parts[0])) {
|
|
124
|
+
result = parts[0] + separator + result;
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Vérifie si un chemin est absolu
|
|
130
|
+
* @param path Chemin à vérifier
|
|
131
|
+
* @returns True si le chemin est absolu
|
|
132
|
+
*/
|
|
133
|
+
static isAbsolute(path) {
|
|
134
|
+
if (!path)
|
|
135
|
+
return false;
|
|
136
|
+
return path.startsWith('/') ||
|
|
137
|
+
this.WINDOWS_DRIVE_REGEX.test(path) ||
|
|
138
|
+
this.PROTOCOL_REGEX.test(path);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Extrait le répertoire parent d'un chemin
|
|
142
|
+
* @param path Chemin source
|
|
143
|
+
* @returns Le répertoire parent ou undefined
|
|
144
|
+
*/
|
|
145
|
+
static dirname(path) {
|
|
146
|
+
if (!path)
|
|
147
|
+
return undefined;
|
|
148
|
+
const isWindows = this.isWindowsPath(path);
|
|
149
|
+
const separator = isWindows ? '\\' : '/';
|
|
150
|
+
const normalized = this.normalizePathSegment(path, isWindows);
|
|
151
|
+
const lastSeparatorIndex = normalized.lastIndexOf(separator);
|
|
152
|
+
if (lastSeparatorIndex === -1)
|
|
153
|
+
return isWindows ? '.' : '.';
|
|
154
|
+
if (lastSeparatorIndex === 0)
|
|
155
|
+
return isWindows ? normalized.substring(0, 2) : '/';
|
|
156
|
+
return normalized.substring(0, lastSeparatorIndex) || (isWindows ? '.' : '/');
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Extrait le nom de fichier d'un chemin
|
|
160
|
+
* @param path Chemin source
|
|
161
|
+
* @param ext Extension optionnelle à retirer
|
|
162
|
+
* @returns Le nom de fichier ou undefined
|
|
163
|
+
*/
|
|
164
|
+
static basename(path, ext) {
|
|
165
|
+
if (!path)
|
|
166
|
+
return undefined;
|
|
167
|
+
const isWindows = this.isWindowsPath(path);
|
|
168
|
+
const separator = isWindows ? '\\' : '/';
|
|
169
|
+
const normalized = this.normalizePathSegment(path, isWindows);
|
|
170
|
+
const lastSeparatorIndex = normalized.lastIndexOf(separator);
|
|
171
|
+
let basename = lastSeparatorIndex === -1 ? normalized : normalized.substring(lastSeparatorIndex + 1);
|
|
172
|
+
// Gestion de l'extension optionnelle
|
|
173
|
+
if (ext && basename.endsWith(ext)) {
|
|
174
|
+
basename = basename.substring(0, basename.length - ext.length);
|
|
175
|
+
}
|
|
176
|
+
return basename || undefined;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Extrait l'extension d'un fichier
|
|
180
|
+
* @param path Chemin source
|
|
181
|
+
* @returns L'extension ou undefined
|
|
182
|
+
*/
|
|
183
|
+
static extname(path) {
|
|
184
|
+
if (!path)
|
|
185
|
+
return undefined;
|
|
186
|
+
const basename = this.basename(path);
|
|
187
|
+
if (!basename)
|
|
188
|
+
return undefined;
|
|
189
|
+
const lastDotIndex = basename.lastIndexOf('.');
|
|
190
|
+
return lastDotIndex > 0 ? basename.substring(lastDotIndex) : undefined;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Convertit un chemin Windows en chemin Unix
|
|
194
|
+
* @param path Chemin Windows
|
|
195
|
+
* @returns Chemin Unix
|
|
196
|
+
*/
|
|
197
|
+
static toUnixPath(path) {
|
|
198
|
+
return path.replace(/\\/g, '/');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Convertit un chemin Unix en chemin Windows
|
|
202
|
+
* @param path Chemin Unix
|
|
203
|
+
* @returns Chemin Windows
|
|
204
|
+
*/
|
|
205
|
+
static toWindowsPath(path) {
|
|
206
|
+
return path.replace(/\//g, '\\');
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Exposition globale de la classe
|
|
210
|
+
*/
|
|
211
|
+
static exposeToGlobal() {
|
|
212
|
+
if (typeof window !== "undefined") {
|
|
213
|
+
window.Pajo = Pajo;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Exposition automatique en environnement browser
|
|
218
|
+
if (typeof window !== "undefined") {
|
|
219
|
+
Pajo.exposeToGlobal();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
package/pajo.all.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class Pajo{static PROTOCOL_REGEX=/^[a-zA-Z]+:\/\//;static DOUBLE_SLASH_REGEX=/\/+/g;static DOUBLE_BACKSLASH_REGEX=/\\+/g;static TRAILING_SLASH_REGEX=/\/+$/;static TRAILING_BACKSLASH_REGEX=/\\+$/;static LEADING_SLASH_REGEX=/^\/+/;static WINDOWS_DRIVE_REGEX=/^[a-zA-Z]:\\/;static MIXED_SEPARATORS_REGEX=/[\\/]+/g;static join(...s){if(0!==s.length){let i=s.some(t=>this.isWindowsPath(t));var e=s.filter(t=>null!=t&&0<t.trim().length).map(t=>this.normalizePathSegment(t,i));if(0!==e.length){var a=i?"\\":"/";let t=e.join(a);return i?t=t.replace(this.DOUBLE_BACKSLASH_REGEX,"\\"):(t=t.replace(this.DOUBLE_SLASH_REGEX,"/"),s[0]?.startsWith("/")&&!t.startsWith("/")&&(t="/"+t)),t||void 0}}}static joinWithHost(t,...i){var s;return t&&0!==t.trim().length?(t=t.trim().replace(this.TRAILING_SLASH_REGEX,""),t=this.PROTOCOL_REGEX.test(t)?t:"https://"+t,(s=this.join(...i))?t+"/"+s.replace(/\\/g,"/").replace(this.LEADING_SLASH_REGEX,""):t):this.join(...i)}static normalizePathSegment(t,i){return t&&0!==t.trim().length?(t=t.trim(),i?t.replace(this.DOUBLE_BACKSLASH_REGEX,"\\").replace(this.TRAILING_BACKSLASH_REGEX,""):t.replace(this.DOUBLE_SLASH_REGEX,"/").replace(this.TRAILING_SLASH_REGEX,"")):""}static isWindowsPath(t){return this.WINDOWS_DRIVE_REGEX.test(t)||t.includes("\\")}static resolve(...i){i=this.join(...i);if(i){var s,e=this.isWindowsPath(i),a=e?"\\":"/",i=i.split(a),n=[];for(s of i)".."===s?0<n.length&&".."!==n[n.length-1]?n.pop():n.push(s):"."!==s&&""!==s&&n.push(s);let t=n.join(a);return t=e&&this.WINDOWS_DRIVE_REGEX.test(i[0])?i[0]+a+t:t}}static isAbsolute(t){return!!t&&(t.startsWith("/")||this.WINDOWS_DRIVE_REGEX.test(t)||this.PROTOCOL_REGEX.test(t))}static dirname(t){var i,s;if(t)return s=(i=this.isWindowsPath(t))?"\\":"/",-1===(s=(t=this.normalizePathSegment(t,i)).lastIndexOf(s))?".":0===s?i?t.substring(0,2):"/":t.substring(0,s)||(i?".":"/")}static basename(i,s){if(i){var e=this.isWindowsPath(i),a=e?"\\":"/",i=this.normalizePathSegment(i,e),e=i.lastIndexOf(a);let t=-1===e?i:i.substring(e+1);return(t=s&&t.endsWith(s)?t.substring(0,t.length-s.length):t)||void 0}}static extname(t){var i;return(t=t&&this.basename(t))&&0<(i=t.lastIndexOf("."))?t.substring(i):void 0}static toUnixPath(t){return t.replace(/\\/g,"/")}static toWindowsPath(t){return t.replace(/\//g,"\\")}static exposeToGlobal(){"undefined"!=typeof window&&(window.Pajo=Pajo)}}"undefined"!=typeof window&&Pajo.exposeToGlobal();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext"],
|
|
6
|
+
"strict": false,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"declaration": false,
|
|
10
|
+
"sourceMap": false,
|
|
11
|
+
"allowSyntheticDefaultImports": true,
|
|
12
|
+
"noEmit": false
|
|
13
|
+
},
|
|
14
|
+
"include": [],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"node_modules",
|
|
17
|
+
"**/*.d.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|