@adminiumjs/add-on-contracts 0.3.39 → 0.3.41
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/dist/add-on-block.d.ts +47 -2
- package/dist/add-on-block.d.ts.map +1 -1
- package/dist/add-on-block.js +18 -2
- package/dist/add-on-block.js.map +1 -1
- package/dist/forms/check.d.ts +82 -0
- package/dist/forms/check.d.ts.map +1 -0
- package/dist/forms/check.js +298 -0
- package/dist/forms/check.js.map +1 -0
- package/dist/forms/definition.d.ts +1462 -0
- package/dist/forms/definition.d.ts.map +1 -0
- package/dist/forms/definition.js +451 -0
- package/dist/forms/definition.js.map +1 -0
- package/dist/forms/index.d.ts +18 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +19 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/parse.d.ts +30 -0
- package/dist/forms/parse.d.ts.map +1 -0
- package/dist/forms/parse.js +93 -0
- package/dist/forms/parse.js.map +1 -0
- package/dist/forms/scales.d.ts +34 -0
- package/dist/forms/scales.d.ts.map +1 -0
- package/dist/forms/scales.js +17 -0
- package/dist/forms/scales.js.map +1 -0
- package/dist/forms/settings.d.ts +77 -0
- package/dist/forms/settings.d.ts.map +1 -0
- package/dist/forms/settings.js +68 -0
- package/dist/forms/settings.js.map +1 -0
- package/dist/forms/slug.d.ts +23 -0
- package/dist/forms/slug.d.ts.map +1 -0
- package/dist/forms/slug.js +26 -0
- package/dist/forms/slug.js.map +1 -0
- package/dist/forms/summary.d.ts +60 -0
- package/dist/forms/summary.d.ts.map +1 -0
- package/dist/forms/summary.js +91 -0
- package/dist/forms/summary.js.map +1 -0
- package/dist/forms/websites.d.ts +54 -0
- package/dist/forms/websites.d.ts.map +1 -0
- package/dist/forms/websites.js +97 -0
- package/dist/forms/websites.js.map +1 -0
- package/dist/forms/words.d.ts +49 -0
- package/dist/forms/words.d.ts.map +1 -0
- package/dist/forms/words.js +31 -0
- package/dist/forms/words.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/data-types.d.ts +55 -0
- package/dist/runtime/data-types.d.ts.map +1 -1
- package/dist/runtime/data.d.ts +2 -0
- package/dist/runtime/data.d.ts.map +1 -1
- package/dist/runtime/data.js +2 -0
- package/dist/runtime/data.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/steps.d.ts +150 -5
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +59 -8
- package/dist/steps.js.map +1 -1
- package/package.json +13 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { formDefinitionSchema, SCALE_OF } from './definition.js';
|
|
2
|
+
import { formSettingsSchema, keepsNames } from './settings.js';
|
|
3
|
+
/** Codes the settings are refused with, beside the definition's and Zod's own. */
|
|
4
|
+
export const FORM_SETTINGS_CODES = [
|
|
5
|
+
/** A survey says how it is answered (`survey`). */
|
|
6
|
+
'survey-settings-missing',
|
|
7
|
+
/** A form has no survey settings. */
|
|
8
|
+
'survey-settings-on-form',
|
|
9
|
+
/** An anonymous survey keeps no names, so it cannot link answers to them. */
|
|
10
|
+
'survey-anonymous-names',
|
|
11
|
+
/** The map names a question the form does not have. */
|
|
12
|
+
'becomes-question-unknown',
|
|
13
|
+
/** A file or a tick fills no column: files are kept with the answer, a tick is a consent. */
|
|
14
|
+
'becomes-question-kind',
|
|
15
|
+
/** Two questions, or a question and the source, fill one column. */
|
|
16
|
+
'becomes-column-twice',
|
|
17
|
+
/** A survey that keeps no names becomes no row: the row would say who answered. */
|
|
18
|
+
'becomes-anonymous',
|
|
19
|
+
'tell-duplicate',
|
|
20
|
+
/** The low-score tell names no score or star question of the form. */
|
|
21
|
+
'tell-when-question',
|
|
22
|
+
/** The low-score tell's number is beyond its question's scale. */
|
|
23
|
+
'tell-when-range',
|
|
24
|
+
];
|
|
25
|
+
function issuesOf(error, under) {
|
|
26
|
+
return error.issues.map((issue) => {
|
|
27
|
+
const own = issue.params?.code;
|
|
28
|
+
return {
|
|
29
|
+
path: [under, ...issue.path.map((part) => (typeof part === 'symbol' ? String(part) : part))],
|
|
30
|
+
code: issue.code === 'custom' && typeof own === 'string' ? own : issue.code,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** The rules that need the definition and the settings together. */
|
|
35
|
+
function settingsIssues(definition, settings) {
|
|
36
|
+
const out = [];
|
|
37
|
+
const report = (code, ...path) => out.push({ path: ['settings', ...path], code });
|
|
38
|
+
const questions = new Map(definition.questions.map((question) => [question.id, question]));
|
|
39
|
+
if (definition.kind === 'survey' && settings.survey === undefined)
|
|
40
|
+
report('survey-settings-missing', 'survey');
|
|
41
|
+
if (definition.kind === 'form' && settings.survey !== undefined)
|
|
42
|
+
report('survey-settings-on-form', 'survey');
|
|
43
|
+
if (settings.survey?.mode === 'anonymous' && settings.survey.linkNames)
|
|
44
|
+
report('survey-anonymous-names', 'survey', 'linkNames');
|
|
45
|
+
const becomes = settings.becomes;
|
|
46
|
+
if (becomes !== null) {
|
|
47
|
+
if (definition.kind === 'survey' && !keepsNames(settings))
|
|
48
|
+
report('becomes-anonymous', 'becomes');
|
|
49
|
+
const filled = new Set();
|
|
50
|
+
for (const [id, column] of Object.entries(becomes.map)) {
|
|
51
|
+
const question = questions.get(id);
|
|
52
|
+
if (question === undefined)
|
|
53
|
+
report('becomes-question-unknown', 'becomes', 'map', id);
|
|
54
|
+
else if (question.kind === 'file' || question.kind === 'tick')
|
|
55
|
+
report('becomes-question-kind', 'becomes', 'map', id);
|
|
56
|
+
if (filled.has(column))
|
|
57
|
+
report('becomes-column-twice', 'becomes', 'map', id);
|
|
58
|
+
filled.add(column);
|
|
59
|
+
}
|
|
60
|
+
if (becomes.source !== undefined && filled.has(becomes.source.column))
|
|
61
|
+
report('becomes-column-twice', 'becomes', 'source', 'column');
|
|
62
|
+
}
|
|
63
|
+
const told = new Set();
|
|
64
|
+
settings.tell.forEach((tell, t) => {
|
|
65
|
+
const key = `${tell.kind}\u0000${tell.id}`;
|
|
66
|
+
if (told.has(key))
|
|
67
|
+
report('tell-duplicate', 'tell', t);
|
|
68
|
+
told.add(key);
|
|
69
|
+
});
|
|
70
|
+
if (settings.tellWhen !== undefined) {
|
|
71
|
+
const question = questions.get(settings.tellWhen.question);
|
|
72
|
+
if (question === undefined || (question.kind !== 'score' && question.kind !== 'stars'))
|
|
73
|
+
report('tell-when-question', 'tellWhen', 'question');
|
|
74
|
+
else if (settings.tellWhen.atMost < SCALE_OF[question.kind].min || settings.tellWhen.atMost > SCALE_OF[question.kind].max)
|
|
75
|
+
report('tell-when-range', 'tellWhen', 'atMost');
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* A form from its stored definition and settings, or every reason it is not
|
|
81
|
+
* one. The definition's issues come first; the rules across the two are
|
|
82
|
+
* checked only when both parse.
|
|
83
|
+
*/
|
|
84
|
+
export function parseForm(definition, settings) {
|
|
85
|
+
const d = formDefinitionSchema.safeParse(definition);
|
|
86
|
+
const s = formSettingsSchema.safeParse(settings);
|
|
87
|
+
const issues = [...(d.success ? [] : issuesOf(d.error, 'definition')), ...(s.success ? [] : issuesOf(s.error, 'settings'))];
|
|
88
|
+
if (!d.success || !s.success)
|
|
89
|
+
return { ok: false, issues };
|
|
90
|
+
const across = settingsIssues(d.data, s.data);
|
|
91
|
+
return across.length === 0 ? { ok: true, form: { definition: d.data, settings: s.data } } : { ok: false, issues: across };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/forms/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The few values and rules the answer's check shares with the schemas,
|
|
3
|
+
* kept apart from them: no schema here, so a page that checks answers in
|
|
4
|
+
* the browser (`@adminium/add-on-contracts/forms/check`) carries the check
|
|
5
|
+
* and none of the schemas.
|
|
6
|
+
*
|
|
7
|
+
* Pure: no I/O, no import but types.
|
|
8
|
+
*/
|
|
9
|
+
/** The most files one file question takes when it takes several. */
|
|
10
|
+
export declare const FORM_FILES_MAX = 5;
|
|
11
|
+
/** The values a question of a scale holds: 0–10 for a score, 1–5 for stars. */
|
|
12
|
+
export declare const SCALE_OF: {
|
|
13
|
+
readonly score: {
|
|
14
|
+
readonly min: 0;
|
|
15
|
+
readonly max: 10;
|
|
16
|
+
};
|
|
17
|
+
readonly stars: {
|
|
18
|
+
readonly min: 1;
|
|
19
|
+
readonly max: 5;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/** Whether a survey keeps who answered: a named one that links answers to names. Every form does. */
|
|
23
|
+
/**
|
|
24
|
+
* The part of a form's settings this reads, spelled out here rather than imported: the settings' schema builds on the
|
|
25
|
+
* definition, which takes these limits, so an import back would close a loop.
|
|
26
|
+
*/
|
|
27
|
+
export interface SurveyNaming {
|
|
28
|
+
survey?: {
|
|
29
|
+
mode: 'named' | 'anonymous';
|
|
30
|
+
linkNames: boolean;
|
|
31
|
+
} | undefined;
|
|
32
|
+
}
|
|
33
|
+
export declare function keepsNames(settings: SurveyNaming): boolean;
|
|
34
|
+
//# sourceMappingURL=scales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scales.d.ts","sourceRoot":"","sources":["../../src/forms/scales.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,oEAAoE;AACpE,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,+EAA+E;AAC/E,eAAO,MAAM,QAAQ;;;;;;;;;CAAqE,CAAC;AAE3F,qGAAqG;AACrG;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAC1E;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAE1D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* The few values and rules the answer's check shares with the schemas,
|
|
4
|
+
* kept apart from them: no schema here, so a page that checks answers in
|
|
5
|
+
* the browser (`@adminium/add-on-contracts/forms/check`) carries the check
|
|
6
|
+
* and none of the schemas.
|
|
7
|
+
*
|
|
8
|
+
* Pure: no I/O, no import but types.
|
|
9
|
+
*/
|
|
10
|
+
/** The most files one file question takes when it takes several. */
|
|
11
|
+
export const FORM_FILES_MAX = 5;
|
|
12
|
+
/** The values a question of a scale holds: 0–10 for a score, 1–5 for stars. */
|
|
13
|
+
export const SCALE_OF = { score: { min: 0, max: 10 }, stars: { min: 1, max: 5 } };
|
|
14
|
+
export function keepsNames(settings) {
|
|
15
|
+
return settings.survey === undefined || (settings.survey.mode === 'named' && settings.survey.linkNames);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=scales.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scales.js","sourceRoot":"","sources":["../../src/forms/scales.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;GAOG;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAW,CAAC;AAW3F,MAAM,UAAU,UAAU,CAAC,QAAsB;IAC/C,OAAO,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC1G,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A FORM'S SETTINGS: what the owner sets beside the questions (comp M-4,
|
|
3
|
+
* "Form settings"). What an answer becomes, who is told, the limits, and a
|
|
4
|
+
* survey's three settings.
|
|
5
|
+
*
|
|
6
|
+
* "Becomes" names a table and fills its columns from answers. Which tables a
|
|
7
|
+
* form may write, and which of their columns, is the app's to say through its
|
|
8
|
+
* `publicAccess` entry under the key `forms`: the engine holds the map to that
|
|
9
|
+
* entry when the form is published and on every answer. This file checks only
|
|
10
|
+
* what the form itself can see: that the map names its own questions, of
|
|
11
|
+
* kinds an answer can be written from, each into a column of its own.
|
|
12
|
+
*
|
|
13
|
+
* Pure: no I/O.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
/** A column of an app's table, by the manifest's ref. */
|
|
17
|
+
export declare const formColumnRefSchema: z.ZodString;
|
|
18
|
+
/** The most people and roles one form tells. */
|
|
19
|
+
export declare const FORM_TELL_MAX = 10;
|
|
20
|
+
/** The hourly cap a form starts with, and the most it may be raised to. */
|
|
21
|
+
export declare const FORM_PER_HOUR_DEFAULT = 200;
|
|
22
|
+
export declare const FORM_PER_HOUR_MAX = 1000;
|
|
23
|
+
/** How many days after each invitation a survey takes answers, by default. */
|
|
24
|
+
export declare const SURVEY_STOP_AFTER_DAYS_DEFAULT = 30;
|
|
25
|
+
export declare const formBecomesSchema: z.ZodObject<{
|
|
26
|
+
table: z.ZodString;
|
|
27
|
+
map: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
28
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
29
|
+
column: z.ZodString;
|
|
30
|
+
value: z.ZodString;
|
|
31
|
+
}, z.core.$strict>>;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type FormBecomes = z.infer<typeof formBecomesSchema>;
|
|
34
|
+
export declare const formTellSchema: z.ZodObject<{
|
|
35
|
+
kind: z.ZodEnum<{
|
|
36
|
+
role: "role";
|
|
37
|
+
person: "person";
|
|
38
|
+
}>;
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
export declare const formSettingsSchema: z.ZodObject<{
|
|
42
|
+
becomes: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
43
|
+
table: z.ZodString;
|
|
44
|
+
map: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
45
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
46
|
+
column: z.ZodString;
|
|
47
|
+
value: z.ZodString;
|
|
48
|
+
}, z.core.$strict>>;
|
|
49
|
+
}, z.core.$strict>>>;
|
|
50
|
+
tell: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
51
|
+
kind: z.ZodEnum<{
|
|
52
|
+
role: "role";
|
|
53
|
+
person: "person";
|
|
54
|
+
}>;
|
|
55
|
+
id: z.ZodString;
|
|
56
|
+
}, z.core.$strict>>>;
|
|
57
|
+
tellWhen: z.ZodOptional<z.ZodObject<{
|
|
58
|
+
question: z.ZodString;
|
|
59
|
+
atMost: z.ZodNumber;
|
|
60
|
+
}, z.core.$strict>>;
|
|
61
|
+
limits: z.ZodDefault<z.ZodObject<{
|
|
62
|
+
perHour: z.ZodDefault<z.ZodNumber>;
|
|
63
|
+
harder: z.ZodDefault<z.ZodBoolean>;
|
|
64
|
+
}, z.core.$strict>>;
|
|
65
|
+
survey: z.ZodOptional<z.ZodObject<{
|
|
66
|
+
mode: z.ZodEnum<{
|
|
67
|
+
named: "named";
|
|
68
|
+
anonymous: "anonymous";
|
|
69
|
+
}>;
|
|
70
|
+
linkNames: z.ZodBoolean;
|
|
71
|
+
stopAfterDays: z.ZodDefault<z.ZodNumber>;
|
|
72
|
+
}, z.core.$strict>>;
|
|
73
|
+
}, z.core.$strict>;
|
|
74
|
+
export type FormSettings = z.infer<typeof formSettingsSchema>;
|
|
75
|
+
export type FormSettingsInput = z.input<typeof formSettingsSchema>;
|
|
76
|
+
export { keepsNames } from './scales.js';
|
|
77
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/forms/settings.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,aAA6D,CAAC;AAE9F,gDAAgD;AAChD,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,eAAO,MAAM,iBAAiB;;;;;;;kBASnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,cAAc;;;;;;kBAAyF,CAAC;AAErH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4BpB,CAAC;AACZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEnE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* A FORM'S SETTINGS: what the owner sets beside the questions (comp M-4,
|
|
4
|
+
* "Form settings"). What an answer becomes, who is told, the limits, and a
|
|
5
|
+
* survey's three settings.
|
|
6
|
+
*
|
|
7
|
+
* "Becomes" names a table and fills its columns from answers. Which tables a
|
|
8
|
+
* form may write, and which of their columns, is the app's to say through its
|
|
9
|
+
* `publicAccess` entry under the key `forms`: the engine holds the map to that
|
|
10
|
+
* entry when the form is published and on every answer. This file checks only
|
|
11
|
+
* what the form itself can see: that the map names its own questions, of
|
|
12
|
+
* kinds an answer can be written from, each into a column of its own.
|
|
13
|
+
*
|
|
14
|
+
* Pure: no I/O.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import { questionIdSchema } from './definition.js';
|
|
18
|
+
/** A column of an app's table, by the manifest's ref. */
|
|
19
|
+
export const formColumnRefSchema = z.string().regex(/^[a-z][a-z0-9_]{0,62}$/, 'a column ref');
|
|
20
|
+
/** The most people and roles one form tells. */
|
|
21
|
+
export const FORM_TELL_MAX = 10;
|
|
22
|
+
/** The hourly cap a form starts with, and the most it may be raised to. */
|
|
23
|
+
export const FORM_PER_HOUR_DEFAULT = 200;
|
|
24
|
+
export const FORM_PER_HOUR_MAX = 1000;
|
|
25
|
+
/** How many days after each invitation a survey takes answers, by default. */
|
|
26
|
+
export const SURVEY_STOP_AFTER_DAYS_DEFAULT = 30;
|
|
27
|
+
export const formBecomesSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
/** The app table, by the id the kit names it with. */
|
|
30
|
+
table: z.string().min(1).max(200),
|
|
31
|
+
/** Which question fills which column. */
|
|
32
|
+
map: z.record(questionIdSchema, formColumnRefSchema),
|
|
33
|
+
/** A fixed value the row gets whoever answers ("Source → Showroom form"). */
|
|
34
|
+
source: z.object({ column: formColumnRefSchema, value: z.string().min(1).max(200) }).strict().optional(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
export const formTellSchema = z.object({ kind: z.enum(['role', 'person']), id: z.string().min(1).max(64) }).strict();
|
|
38
|
+
export const formSettingsSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
/** A new row in an app's table, or nothing but the answer (`null`). */
|
|
41
|
+
becomes: formBecomesSchema.nullable().default(null),
|
|
42
|
+
/** Who gets a bell and an e-mail for each answer. */
|
|
43
|
+
tell: z.array(formTellSchema).max(FORM_TELL_MAX).default([]),
|
|
44
|
+
/** Only when this score or star answer is at most this (a survey's low-score tell). */
|
|
45
|
+
tellWhen: z.object({ question: questionIdSchema, atMost: z.number().int().min(0).max(10) }).strict().optional(),
|
|
46
|
+
limits: z
|
|
47
|
+
.object({
|
|
48
|
+
perHour: z.number().int().min(1).max(FORM_PER_HOUR_MAX).default(FORM_PER_HOUR_DEFAULT),
|
|
49
|
+
/** A harder human check: the challenge's difficulty goes up. */
|
|
50
|
+
harder: z.boolean().default(false),
|
|
51
|
+
})
|
|
52
|
+
.strict()
|
|
53
|
+
.default({ perHour: FORM_PER_HOUR_DEFAULT, harder: false }),
|
|
54
|
+
/** A survey's own settings; required on a survey and refused on a form. */
|
|
55
|
+
survey: z
|
|
56
|
+
.object({
|
|
57
|
+
/** Named: invitations only. Anonymous: an open link, and no names kept. */
|
|
58
|
+
mode: z.enum(['named', 'anonymous']),
|
|
59
|
+
/** Link answers to names (off: the answers are anonymous). */
|
|
60
|
+
linkNames: z.boolean(),
|
|
61
|
+
stopAfterDays: z.number().int().min(1).max(365).default(SURVEY_STOP_AFTER_DAYS_DEFAULT),
|
|
62
|
+
})
|
|
63
|
+
.strict()
|
|
64
|
+
.optional(),
|
|
65
|
+
})
|
|
66
|
+
.strict();
|
|
67
|
+
export { keepsNames } from './scales.js';
|
|
68
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/forms/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A FORM'S SLUG: the last part of its address (`/x/forms/<slug>`).
|
|
3
|
+
*
|
|
4
|
+
* One rule, held by the engine's door (a slug that breaks it is never
|
|
5
|
+
* served) and by the forms add-on's builder (which refuses it as it is
|
|
6
|
+
* typed), so a form the builder lets through is a form the door serves.
|
|
7
|
+
*
|
|
8
|
+
* - lower-case letters, digits and dashes, 1 to 80 characters, with no dash
|
|
9
|
+
* at either end;
|
|
10
|
+
* - never one of the words the addresses themselves use: `api` (the
|
|
11
|
+
* form's own reads, `/x/forms/api/<slug>`), and `surveys` (the staff
|
|
12
|
+
* page's own path to a survey, `/add-ons/<key>/<key>/surveys/<slug>`,
|
|
13
|
+
* beside a form's `/add-ons/<key>/<key>/<slug>`).
|
|
14
|
+
*/
|
|
15
|
+
/** A slug as a form's address may carry one: lower-case letters, digits and dashes. */
|
|
16
|
+
export declare const FORM_SLUG: RegExp;
|
|
17
|
+
/** The longest a slug is. */
|
|
18
|
+
export declare const FORM_SLUG_MAX = 80;
|
|
19
|
+
/** The slugs no form may have: words the addresses themselves use. */
|
|
20
|
+
export declare const FORM_SLUGS_RESERVED: readonly string[];
|
|
21
|
+
/** Whether a form may have this slug: it keeps the rule, and is no reserved word. */
|
|
22
|
+
export declare function isFormSlug(slug: unknown): slug is string;
|
|
23
|
+
//# sourceMappingURL=slug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../src/forms/slug.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;GAaG;AAEH,uFAAuF;AACvF,eAAO,MAAM,SAAS,QAA2C,CAAC;AAElE,6BAA6B;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,sEAAsE;AACtE,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAuB,CAAC;AAEzE,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAExD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* A FORM'S SLUG: the last part of its address (`/x/forms/<slug>`).
|
|
4
|
+
*
|
|
5
|
+
* One rule, held by the engine's door (a slug that breaks it is never
|
|
6
|
+
* served) and by the forms add-on's builder (which refuses it as it is
|
|
7
|
+
* typed), so a form the builder lets through is a form the door serves.
|
|
8
|
+
*
|
|
9
|
+
* - lower-case letters, digits and dashes, 1 to 80 characters, with no dash
|
|
10
|
+
* at either end;
|
|
11
|
+
* - never one of the words the addresses themselves use: `api` (the
|
|
12
|
+
* form's own reads, `/x/forms/api/<slug>`), and `surveys` (the staff
|
|
13
|
+
* page's own path to a survey, `/add-ons/<key>/<key>/surveys/<slug>`,
|
|
14
|
+
* beside a form's `/add-ons/<key>/<key>/<slug>`).
|
|
15
|
+
*/
|
|
16
|
+
/** A slug as a form's address may carry one: lower-case letters, digits and dashes. */
|
|
17
|
+
export const FORM_SLUG = /^[a-z0-9](?:[a-z0-9-]{0,78}[a-z0-9])?$/;
|
|
18
|
+
/** The longest a slug is. */
|
|
19
|
+
export const FORM_SLUG_MAX = 80;
|
|
20
|
+
/** The slugs no form may have: words the addresses themselves use. */
|
|
21
|
+
export const FORM_SLUGS_RESERVED = ['api', 'surveys'];
|
|
22
|
+
/** Whether a form may have this slug: it keeps the rule, and is no reserved word. */
|
|
23
|
+
export function isFormSlug(slug) {
|
|
24
|
+
return typeof slug === 'string' && FORM_SLUG.test(slug) && !FORM_SLUGS_RESERVED.includes(slug);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=slug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/forms/slug.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC;;;;;;;;;;;;;GAaG;AAEH,uFAAuF;AACvF,MAAM,CAAC,MAAM,SAAS,GAAG,wCAAwC,CAAC;AAElE,6BAA6B;AAC7B,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC,sEAAsE;AACtE,MAAM,CAAC,MAAM,mBAAmB,GAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAEzE,qFAAqF;AACrF,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A form's results, counted: per choice, per score, per star, the recommend
|
|
3
|
+
* score and the stars' average, how many answered each question, and how
|
|
4
|
+
* many answers came in each language. Every language's answers are counted
|
|
5
|
+
* together (one form, a version per language). Numbers only: the dashboard
|
|
6
|
+
* words them.
|
|
7
|
+
*
|
|
8
|
+
* The answers are what the engine stored, read back: a value that does not
|
|
9
|
+
* fit its question (a form changed since) is left out of that question's
|
|
10
|
+
* counts rather than counted wrong.
|
|
11
|
+
*
|
|
12
|
+
* Pure: no I/O.
|
|
13
|
+
*/
|
|
14
|
+
import { type FormQuestionKind } from './definition.js';
|
|
15
|
+
import type { Form } from './parse.js';
|
|
16
|
+
import { type FormLanguage } from './words.js';
|
|
17
|
+
/** What is counted of one question. */
|
|
18
|
+
export type QuestionSummary = {
|
|
19
|
+
kind: 'one' | 'several';
|
|
20
|
+
answered: number;
|
|
21
|
+
choices: Record<string, number>;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'score';
|
|
24
|
+
answered: number;
|
|
25
|
+
/** How many gave each score, index = score (0–10). */
|
|
26
|
+
counts: number[];
|
|
27
|
+
/** 9–10, 7–8 and 0–6. */
|
|
28
|
+
promoters: number;
|
|
29
|
+
passives: number;
|
|
30
|
+
detractors: number;
|
|
31
|
+
/** Promoters' share minus detractors', a whole-number percentage with its sign; null with no answer. */
|
|
32
|
+
recommendScore: number | null;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'stars';
|
|
35
|
+
answered: number;
|
|
36
|
+
/** How many gave each number of stars, index 0 = one star. */
|
|
37
|
+
counts: number[];
|
|
38
|
+
/** To one decimal; null with no answer. */
|
|
39
|
+
average: number | null;
|
|
40
|
+
} | {
|
|
41
|
+
kind: Exclude<FormQuestionKind, 'one' | 'several' | 'score' | 'stars'>;
|
|
42
|
+
answered: number;
|
|
43
|
+
};
|
|
44
|
+
export interface FormSummary {
|
|
45
|
+
/** Every answer counted. */
|
|
46
|
+
total: number;
|
|
47
|
+
/** Answers per language: every language the form lists, and any other an answer came in. */
|
|
48
|
+
byLanguage: Partial<Record<FormLanguage, number>>;
|
|
49
|
+
/** The survey's recommend question's score; null when it has none or nobody gave one. */
|
|
50
|
+
recommendScore: number | null;
|
|
51
|
+
questions: Record<string, QuestionSummary>;
|
|
52
|
+
}
|
|
53
|
+
/** The recommend score of counts per score 0–10: promoters' share minus detractors', as a whole-number percentage. */
|
|
54
|
+
export declare function recommendScoreOf(counts: readonly number[]): number | null;
|
|
55
|
+
/** A form's answers, counted. */
|
|
56
|
+
export declare function summarise(form: Pick<Form, 'definition'>, answers: readonly {
|
|
57
|
+
values: Readonly<Record<string, unknown>>;
|
|
58
|
+
language: string;
|
|
59
|
+
}[]): FormSummary;
|
|
60
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/forms/summary.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAY,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/D,uCAAuC;AACvC,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC9E;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GACD;IAAE,IAAI,EAAE,OAAO,CAAC,gBAAgB,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,yFAAyF;IACzF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC5C;AAED,sHAAsH;AACtH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAQzE;AAID,iCAAiC;AACjC,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,SAAS;IAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,WAAW,CAsD1J"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
/**
|
|
3
|
+
* A form's results, counted: per choice, per score, per star, the recommend
|
|
4
|
+
* score and the stars' average, how many answered each question, and how
|
|
5
|
+
* many answers came in each language. Every language's answers are counted
|
|
6
|
+
* together (one form, a version per language). Numbers only: the dashboard
|
|
7
|
+
* words them.
|
|
8
|
+
*
|
|
9
|
+
* The answers are what the engine stored, read back: a value that does not
|
|
10
|
+
* fit its question (a form changed since) is left out of that question's
|
|
11
|
+
* counts rather than counted wrong.
|
|
12
|
+
*
|
|
13
|
+
* Pure: no I/O.
|
|
14
|
+
*/
|
|
15
|
+
import { SCALE_OF } from './definition.js';
|
|
16
|
+
import { FORM_LANGUAGES } from './words.js';
|
|
17
|
+
/** The recommend score of counts per score 0–10: promoters' share minus detractors', as a whole-number percentage. */
|
|
18
|
+
export function recommendScoreOf(counts) {
|
|
19
|
+
const answered = counts.reduce((sum, n) => sum + n, 0);
|
|
20
|
+
if (answered === 0)
|
|
21
|
+
return null;
|
|
22
|
+
const promoters = (counts[9] ?? 0) + (counts[10] ?? 0);
|
|
23
|
+
const detractors = counts.slice(0, 7).reduce((sum, n) => sum + n, 0);
|
|
24
|
+
const score = Math.round(((promoters - detractors) * 100) / answered);
|
|
25
|
+
// Never "-0".
|
|
26
|
+
return score === 0 ? 0 : score;
|
|
27
|
+
}
|
|
28
|
+
const isLanguage = (value) => typeof value === 'string' && FORM_LANGUAGES.includes(value);
|
|
29
|
+
/** A form's answers, counted. */
|
|
30
|
+
export function summarise(form, answers) {
|
|
31
|
+
const { definition } = form;
|
|
32
|
+
const byLanguage = Object.fromEntries(definition.languages.map((language) => [language, 0]));
|
|
33
|
+
for (const answer of answers)
|
|
34
|
+
if (isLanguage(answer.language))
|
|
35
|
+
byLanguage[answer.language] = (byLanguage[answer.language] ?? 0) + 1;
|
|
36
|
+
const questions = {};
|
|
37
|
+
let recommendScore = null;
|
|
38
|
+
for (const question of definition.questions) {
|
|
39
|
+
const given = answers.map((answer) => answer.values[question.id]).filter((value) => value !== undefined && value !== null && value !== '');
|
|
40
|
+
switch (question.kind) {
|
|
41
|
+
case 'one':
|
|
42
|
+
case 'several': {
|
|
43
|
+
const choices = Object.fromEntries(question.choices.map((choice) => [choice.id, 0]));
|
|
44
|
+
let answered = 0;
|
|
45
|
+
for (const value of given) {
|
|
46
|
+
const picks = (question.kind === 'one' ? [value] : Array.isArray(value) ? value : []).filter((pick) => typeof pick === 'string' && pick in choices);
|
|
47
|
+
if (picks.length === 0)
|
|
48
|
+
continue;
|
|
49
|
+
answered += 1;
|
|
50
|
+
for (const pick of new Set(picks))
|
|
51
|
+
choices[pick] = (choices[pick] ?? 0) + 1;
|
|
52
|
+
}
|
|
53
|
+
questions[question.id] = { kind: question.kind, answered, choices };
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case 'score':
|
|
57
|
+
case 'stars': {
|
|
58
|
+
const scale = SCALE_OF[question.kind];
|
|
59
|
+
const counts = Array.from({ length: scale.max - scale.min + 1 }, () => 0);
|
|
60
|
+
for (const value of given) {
|
|
61
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= scale.min && value <= scale.max)
|
|
62
|
+
counts[value - scale.min] += 1;
|
|
63
|
+
}
|
|
64
|
+
const answered = counts.reduce((sum, n) => sum + n, 0);
|
|
65
|
+
if (question.kind === 'score') {
|
|
66
|
+
const score = recommendScoreOf(counts);
|
|
67
|
+
questions[question.id] = {
|
|
68
|
+
kind: 'score',
|
|
69
|
+
answered,
|
|
70
|
+
counts,
|
|
71
|
+
promoters: counts[9] + counts[10],
|
|
72
|
+
passives: counts[7] + counts[8],
|
|
73
|
+
detractors: counts.slice(0, 7).reduce((sum, n) => sum + n, 0),
|
|
74
|
+
recommendScore: score,
|
|
75
|
+
};
|
|
76
|
+
if (question.recommend === true)
|
|
77
|
+
recommendScore = score;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const total = counts.reduce((sum, n, i) => sum + n * (i + 1), 0);
|
|
81
|
+
questions[question.id] = { kind: 'stars', answered, counts, average: answered === 0 ? null : Math.round((total * 10) / answered) / 10 };
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
default:
|
|
86
|
+
questions[question.id] = { kind: question.kind, answered: given.length };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { total: answers.length, byLanguage, recommendScore, questions };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/forms/summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "YOUR WEBSITES": the check each line of the add box is held to.
|
|
3
|
+
*
|
|
4
|
+
* The owner lists the websites that may show a form in a frame. Each line
|
|
5
|
+
* is one website, reduced to its origin (`https://shop.example`: lower
|
|
6
|
+
* case, no path, no trailing slash, no default port). The Privacy page
|
|
7
|
+
* checks every line as it is typed and the server checks the same lines on
|
|
8
|
+
* save with this one function, so the two can never disagree.
|
|
9
|
+
*
|
|
10
|
+
* The checks, in this order, the first that fails naming the line:
|
|
11
|
+
*
|
|
12
|
+
* one-per-line empty, or holds a space, a comma or a `*`
|
|
13
|
+
* https does not start with `https://`
|
|
14
|
+
* address not a website address once read (no host, a user name in
|
|
15
|
+
* it, longer than an origin may be)
|
|
16
|
+
* path names a path, a query or a fragment beyond the origin
|
|
17
|
+
* self this server's own address
|
|
18
|
+
* listed already on the list (or an earlier line of the same batch)
|
|
19
|
+
* ok ready to add
|
|
20
|
+
*
|
|
21
|
+
* Pure: no I/O, no schema, no `node:` import, so a page carries it lightly.
|
|
22
|
+
*/
|
|
23
|
+
/** The most websites the list holds. */
|
|
24
|
+
export declare const WEBSITES_MAX = 50;
|
|
25
|
+
/** The longest origin kept (as the server's own public address). */
|
|
26
|
+
export declare const WEBSITE_ORIGIN_MAX = 255;
|
|
27
|
+
/** The longest line read: anything longer is refused before it is parsed. */
|
|
28
|
+
export declare const WEBSITE_LINE_MAX = 300;
|
|
29
|
+
export declare const WEBSITE_LINE_CODES: readonly ["one-per-line", "https", "address", "path", "self", "listed", "ok"];
|
|
30
|
+
export type WebsiteLineCode = (typeof WEBSITE_LINE_CODES)[number];
|
|
31
|
+
/** One line, checked: its code, and its origin once it was read as one. */
|
|
32
|
+
export interface WebsiteLine {
|
|
33
|
+
line: string;
|
|
34
|
+
code: WebsiteLineCode;
|
|
35
|
+
/** The origin the line reduces to; null when it did not read as an address. */
|
|
36
|
+
origin: string | null;
|
|
37
|
+
}
|
|
38
|
+
export interface WebsiteCheckContext {
|
|
39
|
+
/** This server's public address (`system.publicOrigin`), or null when none is set. */
|
|
40
|
+
self: string | null;
|
|
41
|
+
/** The origins already listed. */
|
|
42
|
+
listed: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
/** One line, checked against the list and this server's own address. */
|
|
45
|
+
export declare function checkWebsiteLine(line: string, ctx: WebsiteCheckContext): WebsiteLine;
|
|
46
|
+
/**
|
|
47
|
+
* Every line of a batch, checked in order: a line naming the same origin as
|
|
48
|
+
* an earlier line of the batch is "already on the list" too, so a batch
|
|
49
|
+
* never adds one website twice.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkWebsiteLines(lines: readonly string[], ctx: WebsiteCheckContext): WebsiteLine[];
|
|
52
|
+
/** Whether a stored value is a listed website's origin as this check makes one. */
|
|
53
|
+
export declare function isWebsiteOrigin(value: string): boolean;
|
|
54
|
+
//# sourceMappingURL=websites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websites.d.ts","sourceRoot":"","sources":["../../src/forms/websites.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,wCAAwC;AACxC,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,eAAO,MAAM,kBAAkB,+EAAgF,CAAC;AAChH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,sFAAsF;IACtF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kCAAkC;IAClC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AA4BD,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,GAAG,WAAW,CAUpF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,WAAW,EAAE,CAOnG;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGtD"}
|