@remit/web-client 0.0.201 → 0.0.202
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/web-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.202",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
|
|
6
6
|
"exports": {
|
|
@@ -285,3 +285,20 @@ describe("initialStage", () => {
|
|
|
285
285
|
assert.equal(initialStage(3), "choose-fate");
|
|
286
286
|
});
|
|
287
287
|
});
|
|
288
|
+
|
|
289
|
+
describe("hasChildFolders in a flat namespace", () => {
|
|
290
|
+
it("does not read a shared prefix as a child", () => {
|
|
291
|
+
const target = folder({
|
|
292
|
+
mailboxId: "work",
|
|
293
|
+
fullPath: "Work",
|
|
294
|
+
hierarchyDelimiter: "",
|
|
295
|
+
});
|
|
296
|
+
assert.equal(
|
|
297
|
+
hasChildFolders(target, [
|
|
298
|
+
target,
|
|
299
|
+
{ mailboxId: "shop", fullPath: "Workshop" },
|
|
300
|
+
]),
|
|
301
|
+
false,
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
});
|
package/src/lib/delete-folder.ts
CHANGED
|
@@ -34,12 +34,14 @@ const isInboxPath = (fullPath: string): boolean =>
|
|
|
34
34
|
/**
|
|
35
35
|
* A folder has children when another mailbox's path is nested under it — the
|
|
36
36
|
* folder's own path followed by the hierarchy delimiter. The delimiter matters:
|
|
37
|
-
* `Work` is not a parent of `Workshop`, only of `Work/Shop`.
|
|
37
|
+
* `Work` is not a parent of `Workshop`, only of `Work/Shop`. A server that
|
|
38
|
+
* reports no delimiter has a flat namespace, where nothing nests at all.
|
|
38
39
|
*/
|
|
39
40
|
export const hasChildFolders = (
|
|
40
41
|
folder: Pick<FolderNode, "mailboxId" | "fullPath" | "hierarchyDelimiter">,
|
|
41
42
|
all: readonly Pick<FolderNode, "mailboxId" | "fullPath">[],
|
|
42
43
|
): boolean => {
|
|
44
|
+
if (folder.hierarchyDelimiter.length === 0) return false;
|
|
43
45
|
const prefix = `${folder.fullPath}${folder.hierarchyDelimiter}`;
|
|
44
46
|
return all.some(
|
|
45
47
|
(other) =>
|
|
@@ -107,3 +107,21 @@ describe("validateNewFolderName", () => {
|
|
|
107
107
|
);
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
|
+
|
|
111
|
+
describe("validateNewFolderName in a flat namespace", () => {
|
|
112
|
+
const flat = { delimiter: "", existingPaths: ["INBOX", "Archive"] };
|
|
113
|
+
|
|
114
|
+
it("accepts a name when the server reports no delimiter", () => {
|
|
115
|
+
assert.equal(
|
|
116
|
+
validateNewFolderName({ ...flat, name: "Receipts" }),
|
|
117
|
+
undefined,
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("still catches a collision", () => {
|
|
122
|
+
assert.match(
|
|
123
|
+
validateNewFolderName({ ...flat, name: "inbox" }) ?? "",
|
|
124
|
+
/already exists/,
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
});
|
package/src/lib/new-folder.ts
CHANGED
|
@@ -19,7 +19,7 @@ export function composeFolderPath(name: string, parent?: FolderTarget): string {
|
|
|
19
19
|
* match `inbox/x` against `INBOX/x` without folding case anywhere else.
|
|
20
20
|
*/
|
|
21
21
|
const canonicalizePath = (path: string, delimiter: string): string => {
|
|
22
|
-
const parts = path.split(delimiter);
|
|
22
|
+
const parts = delimiter.length === 0 ? [path] : path.split(delimiter);
|
|
23
23
|
if (parts[0]?.toLowerCase() === "inbox") parts[0] = "INBOX";
|
|
24
24
|
return parts.join(delimiter);
|
|
25
25
|
};
|
|
@@ -29,7 +29,8 @@ const canonicalizePath = (path: string, delimiter: string): string => {
|
|
|
29
29
|
* name must be non-empty, must not contain the hierarchy delimiter (nesting is
|
|
30
30
|
* expressed by the parent select, not by typing a path), and must not collide
|
|
31
31
|
* with an existing folder — INBOX compared case-insensitively, everything else
|
|
32
|
-
* exactly.
|
|
32
|
+
* exactly. A server that reports no delimiter has a flat namespace, so there is
|
|
33
|
+
* no separator to forbid and every name would otherwise contain it.
|
|
33
34
|
*/
|
|
34
35
|
export function validateNewFolderName({
|
|
35
36
|
name,
|
|
@@ -44,7 +45,7 @@ export function validateNewFolderName({
|
|
|
44
45
|
}): string | undefined {
|
|
45
46
|
const trimmed = name.trim();
|
|
46
47
|
if (trimmed === "") return "Enter a folder name.";
|
|
47
|
-
if (trimmed.includes(delimiter))
|
|
48
|
+
if (delimiter.length > 0 && trimmed.includes(delimiter))
|
|
48
49
|
return `A folder name can't contain "${delimiter}".`;
|
|
49
50
|
const candidate = canonicalizePath(
|
|
50
51
|
composeFolderPath(trimmed, parent),
|