@zukhruf/fs 0.3.24 → 0.3.26

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
@@ -66,9 +66,8 @@ await createExclusive(join('/var/lib/app/locks', `${name}.lock`), 'pid 4242');
66
66
  ```
67
67
 
68
68
  - A key that fits gets its URI encoding, with each `.` as `%2E`. Thus a name is never `.` or `..`. The name of `job.lock` is `job%2Elock`, so it is never the name of `job` plus the suffix `.lock`.
69
+ - The encoding also encodes each uppercase letter. The names of `Sync`, `sync` and `SYNC` are `%53ync`, `sync` and `%53%59%4E%43`. APFS and NTFS compare file names without case. On these file systems too, each key gets its own file, as on Linux.
69
70
  - A key that does not fit, or that is not well-formed Unicode, gets a hashed name: the first 32 characters of its encoding, `%%`, and the SHA-256 of its UTF-16 code units in hex. A hashed name has at most 98 characters. An encoding never holds `%%`, so a hashed name is never the name of a key that fits.
70
- - The rule does not change between versions. Processes of two versions find the same file for a key.
71
- - On a case-insensitive file system, keys that differ only by case get one file.
72
71
 
73
72
  ## Try again while Windows refuses a file for a moment
74
73
 
@@ -1,17 +1,18 @@
1
1
  /**
2
2
  * Maps any key to a single path segment that still fits a file name after the
3
- * caller adds up to `longestSuffix` characters. Encoding every dot means a key
4
- * can never be `.` or `..`, and suffixes such as `.lock` can never collide with
5
- * a key. On a case-insensitive file system, keys that differ only by case share
6
- * a name and so one file. A lock file then guards more keys than it must, but
7
- * never fewer.
3
+ * caller adds up to `longestSuffix` characters. The name is the URI encoding of
4
+ * the key, with each dot and each uppercase letter encoded too. A name thus has
5
+ * no dot: a key can never be `.` or `..`, and a suffix such as `.lock` can never
6
+ * make the name of another key. A name is ASCII, and it has no uppercase letter
7
+ * outside an escape, whose hex digits are always uppercase. Thus two keys never
8
+ * get names that are equal without case. APFS and NTFS compare file names
9
+ * without case, and there too each key gets its own file, as on Linux.
8
10
  *
9
11
  * A key whose encoding does not fit, or that is not well-formed Unicode and so
10
12
  * has no encoding, gets the start of its encoding, `%%`, and the SHA-256 of its
11
- * UTF-16 code units. A key that fits keeps the name earlier versions gave it, so
12
- * processes of two versions share its file. No encoding contains `%%`, so the
13
- * two kinds of name never meet; the digest is hex, whose one case cannot fold
14
- * two digests into one name; and the code units keep lone surrogates apart.
13
+ * UTF-16 code units. No encoding contains `%%`, so the two kinds of name never
14
+ * meet; the digest is lowercase hex, so case cannot fold two digests into one
15
+ * name; and the code units keep lone surrogates apart.
15
16
  */
16
17
  export declare function safeFileName(key: string, longestSuffix: number): string;
17
18
  //# sourceMappingURL=safe-file-name.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-file-name.d.ts","sourceRoot":"","sources":["../src/safe-file-name.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAYvE"}
1
+ {"version":3,"file":"safe-file-name.d.ts","sourceRoot":"","sources":["../src/safe-file-name.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAYvE"}
@@ -5,18 +5,19 @@ const longestFileName = 255;
5
5
  const visibleStart = 32;
6
6
  /**
7
7
  * Maps any key to a single path segment that still fits a file name after the
8
- * caller adds up to `longestSuffix` characters. Encoding every dot means a key
9
- * can never be `.` or `..`, and suffixes such as `.lock` can never collide with
10
- * a key. On a case-insensitive file system, keys that differ only by case share
11
- * a name and so one file. A lock file then guards more keys than it must, but
12
- * never fewer.
8
+ * caller adds up to `longestSuffix` characters. The name is the URI encoding of
9
+ * the key, with each dot and each uppercase letter encoded too. A name thus has
10
+ * no dot: a key can never be `.` or `..`, and a suffix such as `.lock` can never
11
+ * make the name of another key. A name is ASCII, and it has no uppercase letter
12
+ * outside an escape, whose hex digits are always uppercase. Thus two keys never
13
+ * get names that are equal without case. APFS and NTFS compare file names
14
+ * without case, and there too each key gets its own file, as on Linux.
13
15
  *
14
16
  * A key whose encoding does not fit, or that is not well-formed Unicode and so
15
17
  * has no encoding, gets the start of its encoding, `%%`, and the SHA-256 of its
16
- * UTF-16 code units. A key that fits keeps the name earlier versions gave it, so
17
- * processes of two versions share its file. No encoding contains `%%`, so the
18
- * two kinds of name never meet; the digest is hex, whose one case cannot fold
19
- * two digests into one name; and the code units keep lone surrogates apart.
18
+ * UTF-16 code units. No encoding contains `%%`, so the two kinds of name never
19
+ * meet; the digest is lowercase hex, so case cannot fold two digests into one
20
+ * name; and the code units keep lone surrogates apart.
20
21
  */
21
22
  export function safeFileName(key, longestSuffix) {
22
23
  if (key.isWellFormed()) {
@@ -33,6 +34,8 @@ export function safeFileName(key, longestSuffix) {
33
34
  return `${start}%%${digest}`;
34
35
  }
35
36
  function encode(key) {
36
- return encodeURIComponent(key).replaceAll('.', '%2E');
37
+ return encodeURIComponent(key).replaceAll(/%[0-9A-F]{2}|[.A-Z]/g, (match) => match.length === 1
38
+ ? `%${match.charCodeAt(0).toString(16).toUpperCase()}`
39
+ : match);
37
40
  }
38
41
  //# sourceMappingURL=safe-file-name.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-file-name.js","sourceRoot":"","sources":["../src/safe-file-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,oEAAoE;AACpE,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,2EAA2E;AAC3E,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,aAAqB;IAC7D,IAAI,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,GAAG,aAAa,IAAI,eAAe;YAAE,OAAO,OAAO,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;SACrC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;SACtB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;SAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SACnC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjB,OAAO,GAAG,KAAK,KAAK,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC"}
1
+ {"version":3,"file":"safe-file-name.js","sourceRoot":"","sources":["../src/safe-file-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,oEAAoE;AACpE,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,2EAA2E;AAC3E,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,aAAqB;IAC7D,IAAI,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,GAAG,aAAa,IAAI,eAAe;YAAE,OAAO,OAAO,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;SACrC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;SACtB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;SAChC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SACnC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjB,OAAO,GAAG,KAAK,KAAK,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,KAAK,EAAE,EAAE,CAC1E,KAAK,CAAC,MAAM,KAAK,CAAC;QAChB,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE;QACtD,CAAC,CAAC,KAAK,CACV,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/fs",
3
- "version": "0.3.24",
3
+ "version": "0.3.26",
4
4
  "description": "File writes that a reader never sees half done: replace a file in one step, with or without a sync to the disk, or create it only when it is absent. A lock on a file that the kernel frees when its holder dies. Also retries the short refusals of Windows, and names a file after any key.",
5
5
  "license": "MIT",
6
6
  "repository": {