@coffre/client 0.1.11 → 0.1.13

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.
@@ -1,85 +0,0 @@
1
- /**
2
- * A sync provider's form, as the web page and `coffre sync add` fill it in.
3
- *
4
- * Each provider describes its fields (`GET /syncs/providers`); the server's
5
- * parser validates every one of them (formats, lengths, combinations) and
6
- * says what is wrong in a sentence. This only turns what someone typed into
7
- * the JSON that parser expects.
8
- */
9
- import type { SyncField, SyncProviderInfo } from './api.ts';
10
-
11
- export type FormValues = Record<string, string | string[]>;
12
-
13
- export function initialValues(provider: SyncProviderInfo): FormValues {
14
- return Object.fromEntries(
15
- provider.fields.map((field) => [field.name, field.type === 'text' ? '' : field.initial]),
16
- );
17
- }
18
-
19
- /** Whether the rest of the form makes the field meaningful. */
20
- export function isAsked(field: SyncField, values: FormValues): boolean {
21
- if (field.type === 'options' || field.when === undefined) return true;
22
- const picked = values[field.when.field];
23
- const list = Array.isArray(picked) ? picked : [];
24
- return list.length === field.when.is.length && field.when.is.every((value) => list.includes(value));
25
- }
26
-
27
- /** The label of the first required field left empty, or null when the form can be sent. */
28
- export function firstMissing(provider: SyncProviderInfo, values: FormValues): string | null {
29
- for (const field of provider.fields) {
30
- if (!isAsked(field, values)) continue;
31
- const value = values[field.name];
32
- const empty = typeof value === 'string' ? value.trim() === '' : (value ?? []).length === 0;
33
- if (empty && (field.type === 'options' || field.optional !== true)) return field.label;
34
- }
35
- return null;
36
- }
37
-
38
- /**
39
- * The provider's config. Text is trimmed, and an optional field left empty
40
- * is left out rather than sent as "", which the server rightly refuses.
41
- */
42
- export function configFromForm(provider: SyncProviderInfo, values: FormValues): Record<string, unknown> {
43
- const config: Record<string, unknown> = {};
44
- for (const field of provider.fields) {
45
- if (!isAsked(field, values)) continue;
46
- const value = values[field.name];
47
- if (field.type === 'options') {
48
- const picked = Array.isArray(value) ? value : [];
49
- config[field.name] = field.multiple ? picked : picked[0];
50
- } else {
51
- const text = typeof value === 'string' ? value.trim() : '';
52
- if (text !== '') config[field.name] = text;
53
- }
54
- }
55
- return config;
56
- }
57
-
58
- /**
59
- * The config from `name=value` arguments, as the CLI takes them. A field with
60
- * several options takes them comma-separated, and one left out gets what the
61
- * form preselects. Text goes as typed, for the server to check.
62
- */
63
- export function configFromArguments(provider: SyncProviderInfo, assignments: readonly string[]): Record<string, unknown> {
64
- const config: Record<string, unknown> = {};
65
- for (const assignment of assignments) {
66
- const equals = assignment.indexOf('=');
67
- const name = equals === -1 ? assignment : assignment.slice(0, equals);
68
- const field = provider.fields.find((candidate) => candidate.name === name);
69
- if (equals === -1 || field === undefined) {
70
- const names = provider.fields.map((candidate) => candidate.name).join(', ');
71
- throw new Error(`${provider.label} takes ${names} as name=value; got ${JSON.stringify(assignment)}`);
72
- }
73
- if (Object.hasOwn(config, name)) throw new Error(`${name} is given twice`);
74
- const value = assignment.slice(equals + 1);
75
- if (field.type === 'text') config[name] = value;
76
- else if (field.multiple) config[name] = value.split(',').map((item) => item.trim()).filter((item) => item !== '');
77
- else config[name] = value;
78
- }
79
- for (const field of provider.fields) {
80
- if (field.type === 'options' && !Object.hasOwn(config, field.name)) {
81
- config[field.name] = field.multiple ? field.initial : field.initial[0];
82
- }
83
- }
84
- return config;
85
- }