@kernhq/module-tracker 0.1.0
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/LICENSE +662 -0
- package/README.md +265 -0
- package/dist/contract/events.d.ts +140 -0
- package/dist/contract/events.d.ts.map +1 -0
- package/dist/contract/events.js +51 -0
- package/dist/contract/events.js.map +1 -0
- package/dist/contract/index.d.ts +6 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +6 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/models.d.ts +2547 -0
- package/dist/contract/models.d.ts.map +1 -0
- package/dist/contract/models.js +1214 -0
- package/dist/contract/models.js.map +1 -0
- package/dist/contract/notifications.d.ts +4 -0
- package/dist/contract/notifications.d.ts.map +1 -0
- package/dist/contract/notifications.js +46 -0
- package/dist/contract/notifications.js.map +1 -0
- package/dist/contract/permissions.d.ts +161 -0
- package/dist/contract/permissions.d.ts.map +1 -0
- package/dist/contract/permissions.js +192 -0
- package/dist/contract/permissions.js.map +1 -0
- package/dist/contract/router.d.ts +9659 -0
- package/dist/contract/router.d.ts.map +1 -0
- package/dist/contract/router.js +732 -0
- package/dist/contract/router.js.map +1 -0
- package/dist/kql/ast.d.ts +90 -0
- package/dist/kql/ast.d.ts.map +1 -0
- package/dist/kql/ast.js +80 -0
- package/dist/kql/ast.js.map +1 -0
- package/dist/kql/dates.d.ts +16 -0
- package/dist/kql/dates.d.ts.map +1 -0
- package/dist/kql/dates.js +54 -0
- package/dist/kql/dates.js.map +1 -0
- package/dist/kql/fields.d.ts +61 -0
- package/dist/kql/fields.d.ts.map +1 -0
- package/dist/kql/fields.js +106 -0
- package/dist/kql/fields.js.map +1 -0
- package/dist/kql/index.d.ts +16 -0
- package/dist/kql/index.d.ts.map +1 -0
- package/dist/kql/index.js +16 -0
- package/dist/kql/index.js.map +1 -0
- package/dist/kql/lexer.d.ts +28 -0
- package/dist/kql/lexer.d.ts.map +1 -0
- package/dist/kql/lexer.js +127 -0
- package/dist/kql/lexer.js.map +1 -0
- package/dist/kql/parser.d.ts +14 -0
- package/dist/kql/parser.d.ts.map +1 -0
- package/dist/kql/parser.js +290 -0
- package/dist/kql/parser.js.map +1 -0
- package/dist/kql/suggest.d.ts +8 -0
- package/dist/kql/suggest.d.ts.map +1 -0
- package/dist/kql/suggest.js +96 -0
- package/dist/kql/suggest.js.map +1 -0
- package/dist/kql/validate.d.ts +10 -0
- package/dist/kql/validate.d.ts.map +1 -0
- package/dist/kql/validate.js +84 -0
- package/dist/kql/validate.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +583 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/kql/compile.d.ts +49 -0
- package/dist/server/kql/compile.d.ts.map +1 -0
- package/dist/server/kql/compile.js +372 -0
- package/dist/server/kql/compile.js.map +1 -0
- package/dist/server/rank.d.ts +23 -0
- package/dist/server/rank.d.ts.map +1 -0
- package/dist/server/rank.js +66 -0
- package/dist/server/rank.js.map +1 -0
- package/dist/server/rich.d.ts +30 -0
- package/dist/server/rich.d.ts.map +1 -0
- package/dist/server/rich.js +97 -0
- package/dist/server/rich.js.map +1 -0
- package/dist/server/router.d.ts +10589 -0
- package/dist/server/router.d.ts.map +1 -0
- package/dist/server/router.js +431 -0
- package/dist/server/router.js.map +1 -0
- package/dist/server/schema.d.ts +6622 -0
- package/dist/server/schema.d.ts.map +1 -0
- package/dist/server/schema.js +581 -0
- package/dist/server/schema.js.map +1 -0
- package/dist/server/services/access.d.ts +53 -0
- package/dist/server/services/access.d.ts.map +1 -0
- package/dist/server/services/access.js +146 -0
- package/dist/server/services/access.js.map +1 -0
- package/dist/server/services/comments.d.ts +36 -0
- package/dist/server/services/comments.d.ts.map +1 -0
- package/dist/server/services/comments.js +231 -0
- package/dist/server/services/comments.js.map +1 -0
- package/dist/server/services/config.d.ts +130 -0
- package/dist/server/services/config.d.ts.map +1 -0
- package/dist/server/services/config.js +797 -0
- package/dist/server/services/config.js.map +1 -0
- package/dist/server/services/db.d.ts +93 -0
- package/dist/server/services/db.d.ts.map +1 -0
- package/dist/server/services/db.js +519 -0
- package/dist/server/services/db.js.map +1 -0
- package/dist/server/services/imports.d.ts +37 -0
- package/dist/server/services/imports.d.ts.map +1 -0
- package/dist/server/services/imports.js +324 -0
- package/dist/server/services/imports.js.map +1 -0
- package/dist/server/services/index.d.ts +36 -0
- package/dist/server/services/index.d.ts.map +1 -0
- package/dist/server/services/index.js +57 -0
- package/dist/server/services/index.js.map +1 -0
- package/dist/server/services/intake.d.ts +47 -0
- package/dist/server/services/intake.d.ts.map +1 -0
- package/dist/server/services/intake.js +268 -0
- package/dist/server/services/intake.js.map +1 -0
- package/dist/server/services/issues.d.ts +763 -0
- package/dist/server/services/issues.d.ts.map +1 -0
- package/dist/server/services/issues.js +1381 -0
- package/dist/server/services/issues.js.map +1 -0
- package/dist/server/services/notify.d.ts +51 -0
- package/dist/server/services/notify.d.ts.map +1 -0
- package/dist/server/services/notify.js +90 -0
- package/dist/server/services/notify.js.map +1 -0
- package/dist/server/services/planning.d.ts +62 -0
- package/dist/server/services/planning.d.ts.map +1 -0
- package/dist/server/services/planning.js +614 -0
- package/dist/server/services/planning.js.map +1 -0
- package/dist/server/services/projects.d.ts +43 -0
- package/dist/server/services/projects.d.ts.map +1 -0
- package/dist/server/services/projects.js +375 -0
- package/dist/server/services/projects.js.map +1 -0
- package/dist/server/services/query.d.ts +24 -0
- package/dist/server/services/query.d.ts.map +1 -0
- package/dist/server/services/query.js +312 -0
- package/dist/server/services/query.js.map +1 -0
- package/dist/server/services/reports.d.ts +30 -0
- package/dist/server/services/reports.d.ts.map +1 -0
- package/dist/server/services/reports.js +295 -0
- package/dist/server/services/reports.js.map +1 -0
- package/dist/server/services/time.d.ts +53 -0
- package/dist/server/services/time.d.ts.map +1 -0
- package/dist/server/services/time.js +192 -0
- package/dist/server/services/time.js.map +1 -0
- package/dist/server/services/transitions.d.ts +61 -0
- package/dist/server/services/transitions.d.ts.map +1 -0
- package/dist/server/services/transitions.js +493 -0
- package/dist/server/services/transitions.js.map +1 -0
- package/dist/server/services/views.d.ts +33 -0
- package/dist/server/services/views.d.ts.map +1 -0
- package/dist/server/services/views.js +195 -0
- package/dist/server/services/views.js.map +1 -0
- package/migrations/0000_init.sql +529 -0
- package/migrations/0001_rls.sql +259 -0
- package/migrations/meta/0000_snapshot.json +4140 -0
- package/migrations/meta/_journal.json +20 -0
- package/package.json +82 -0
- package/src/client/api.ts +15 -0
- package/src/client/format.ts +164 -0
- package/src/client/group.ts +150 -0
- package/src/client/index.ts +60 -0
- package/src/client/kql.ts +492 -0
- package/src/client/rank.ts +87 -0
- package/src/client/types.ts +57 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type SQL } from 'drizzle-orm';
|
|
2
|
+
import type { FieldType } from '../../contract/models.js';
|
|
3
|
+
import type { KqlQuery } from '../../kql/ast.js';
|
|
4
|
+
import { type KqlField } from '../../kql/fields.js';
|
|
5
|
+
/** Names a query mentions that have to be looked up before it can be compiled. */
|
|
6
|
+
export interface RefRequest {
|
|
7
|
+
refType: NonNullable<KqlField['refType']> | 'user' | 'group';
|
|
8
|
+
/** raw text as written in the query */
|
|
9
|
+
text: string;
|
|
10
|
+
}
|
|
11
|
+
/** Result of resolving every {@link RefRequest}: `refType` → lower-cased name → matching ids. */
|
|
12
|
+
export interface RefLookup {
|
|
13
|
+
byType: Map<string, Map<string, string[]>>;
|
|
14
|
+
/** cycles of the queried projects, for `activeCycle()` / `openCycles()` */
|
|
15
|
+
activeCycleIds: string[];
|
|
16
|
+
openCycleIds: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare const emptyLookup: () => RefLookup;
|
|
19
|
+
export interface CompileContext {
|
|
20
|
+
fields: readonly KqlField[];
|
|
21
|
+
lookup: RefLookup;
|
|
22
|
+
userId: string | null;
|
|
23
|
+
now: Date;
|
|
24
|
+
/** custom field key → declared type, for casting `cf.*` comparisons */
|
|
25
|
+
customTypes: Map<string, FieldType>;
|
|
26
|
+
}
|
|
27
|
+
export declare class KqlCompileError extends Error {
|
|
28
|
+
}
|
|
29
|
+
declare const FALSE: SQL<unknown>;
|
|
30
|
+
declare const TRUE: SQL<unknown>;
|
|
31
|
+
/** Collect every reference (label name, status name, user…) the query needs resolved. */
|
|
32
|
+
export declare function collectRefs(query: KqlQuery, fields: readonly KqlField[]): RefRequest[];
|
|
33
|
+
/** True when the query needs the active/open cycle ids of the queried projects. */
|
|
34
|
+
export declare function usesCycleFunctions(query: KqlQuery): boolean;
|
|
35
|
+
type ExprKind = 'text' | 'key' | 'uuid' | 'uuidArray' | 'enum' | 'priority' | 'timestamp' | 'date' | 'number' | 'bool' | 'fulltext';
|
|
36
|
+
interface FieldSql {
|
|
37
|
+
expr: SQL;
|
|
38
|
+
kind: ExprKind;
|
|
39
|
+
}
|
|
40
|
+
/** The SQL expression a KQL field name maps to, or null when the field is unknown. */
|
|
41
|
+
export declare function fieldSql(name: string, ctx: CompileContext): (FieldSql & {
|
|
42
|
+
field: KqlField;
|
|
43
|
+
}) | null;
|
|
44
|
+
/** Compile the `where` part of a parsed query. Returns undefined for an empty query. */
|
|
45
|
+
export declare function compileWhere(query: KqlQuery, ctx: CompileContext): SQL | undefined;
|
|
46
|
+
/** Compile one sort key. Unknown fields fall back to `rank`. */
|
|
47
|
+
export declare function compileOrder(field: string, dir: 'asc' | 'desc', ctx: CompileContext): SQL;
|
|
48
|
+
export { FALSE as sqlFalse, TRUE as sqlTrue };
|
|
49
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/server/kql/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAO,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAiC,QAAQ,EAAY,MAAM,kBAAkB,CAAA;AAGzF,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAG9D,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,GAAG,OAAO,CAAA;IAC5D,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,iGAAiG;AACjG,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;IAC1C,2EAA2E;IAC3E,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,eAAO,MAAM,WAAW,QAAO,SAI7B,CAAA;AAEF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAA;IAC3B,MAAM,EAAE,SAAS,CAAA;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,GAAG,EAAE,IAAI,CAAA;IACT,uEAAuE;IACvE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACpC;AAED,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAI7C,QAAA,MAAM,KAAK,cAAa,CAAA;AACxB,QAAA,MAAM,IAAI,cAAY,CAAA;AAEtB,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,QAAQ,EAAE,GAAG,UAAU,EAAE,CAgBtF;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAO3D;AAMD,KAAK,QAAQ,GACT,MAAM,GACN,KAAK,GACL,MAAM,GACN,WAAW,GACX,MAAM,GACN,UAAU,GACV,WAAW,GACX,MAAM,GACN,QAAQ,GACR,MAAM,GACN,UAAU,CAAA;AAEd,UAAU,QAAQ;IAChB,IAAI,EAAE,GAAG,CAAA;IACT,IAAI,EAAE,QAAQ,CAAA;CACf;AAuED,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,CAAC,QAAQ,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG,IAAI,CASnG;AAgPD,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,cAAc,GAAG,GAAG,GAAG,SAAS,CAGlF;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,GAAG,CAMzF;AAED,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,IAAI,IAAI,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { walkComparisons } from '../../kql/ast.js';
|
|
3
|
+
import { parseDateLiteral, shift, startOfDay, startOfMonth, startOfWeek } from '../../kql/dates.js';
|
|
4
|
+
import { findField } from '../../kql/fields.js';
|
|
5
|
+
import { issues } from '../schema.js';
|
|
6
|
+
export const emptyLookup = () => ({
|
|
7
|
+
byType: new Map(),
|
|
8
|
+
activeCycleIds: [],
|
|
9
|
+
openCycleIds: [],
|
|
10
|
+
});
|
|
11
|
+
export class KqlCompileError extends Error {
|
|
12
|
+
}
|
|
13
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14
|
+
const FALSE = sql `false`;
|
|
15
|
+
const TRUE = sql `true`;
|
|
16
|
+
/** Collect every reference (label name, status name, user…) the query needs resolved. */
|
|
17
|
+
export function collectRefs(query, fields) {
|
|
18
|
+
const out = [];
|
|
19
|
+
const add = (refType, value) => {
|
|
20
|
+
if (value.kind === 'string' || value.kind === 'ident')
|
|
21
|
+
out.push({ refType, text: String(value.value) });
|
|
22
|
+
else if (value.kind === 'func' && value.name.toLowerCase() === 'membersof')
|
|
23
|
+
for (const a of value.args)
|
|
24
|
+
if (a.kind === 'string' || a.kind === 'ident')
|
|
25
|
+
out.push({ refType: 'group', text: String(a.value) });
|
|
26
|
+
};
|
|
27
|
+
walkComparisons(query.where, (cmp) => {
|
|
28
|
+
const field = findField(fields, cmp.field);
|
|
29
|
+
if (!field)
|
|
30
|
+
return;
|
|
31
|
+
const refType = field.refType ?? (field.kind === 'user' ? 'user' : null);
|
|
32
|
+
if (!refType)
|
|
33
|
+
return;
|
|
34
|
+
for (const v of [cmp.value, ...(cmp.values ?? [])])
|
|
35
|
+
if (v)
|
|
36
|
+
add(refType, v);
|
|
37
|
+
});
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** True when the query needs the active/open cycle ids of the queried projects. */
|
|
41
|
+
export function usesCycleFunctions(query) {
|
|
42
|
+
let used = false;
|
|
43
|
+
walkComparisons(query.where, (cmp) => {
|
|
44
|
+
for (const v of [cmp.value, ...(cmp.values ?? [])])
|
|
45
|
+
if (v?.kind === 'func' && ['activecycle', 'opencycles'].includes(v.name.toLowerCase()))
|
|
46
|
+
used = true;
|
|
47
|
+
});
|
|
48
|
+
return used;
|
|
49
|
+
}
|
|
50
|
+
const PRIORITY_RANK = sql `case ${issues.priority} when 'urgent' then 4 when 'high' then 3 when 'medium' then 2 when 'low' then 1 else 0 end`;
|
|
51
|
+
const SYSTEM_SQL = {
|
|
52
|
+
key: { expr: sql `${issues.key}`, kind: 'key' },
|
|
53
|
+
project: { expr: sql `${issues.projectId}`, kind: 'uuid' },
|
|
54
|
+
type: { expr: sql `${issues.typeId}`, kind: 'uuid' },
|
|
55
|
+
title: { expr: sql `${issues.title}`, kind: 'text' },
|
|
56
|
+
status: { expr: sql `${issues.statusId}`, kind: 'enum' },
|
|
57
|
+
statuscategory: { expr: sql `${issues.statusCategory}`, kind: 'enum' },
|
|
58
|
+
priority: { expr: PRIORITY_RANK, kind: 'priority' },
|
|
59
|
+
assignee: { expr: sql `${issues.assigneeIds}`, kind: 'uuidArray' },
|
|
60
|
+
reporter: { expr: sql `${issues.reporterId}`, kind: 'uuid' },
|
|
61
|
+
label: { expr: sql `${issues.labelIds}`, kind: 'uuidArray' },
|
|
62
|
+
component: { expr: sql `${issues.componentIds}`, kind: 'uuidArray' },
|
|
63
|
+
version: { expr: sql `${issues.versionIds}`, kind: 'uuidArray' },
|
|
64
|
+
affectsversion: { expr: sql `${issues.affectsVersionIds}`, kind: 'uuidArray' },
|
|
65
|
+
cycle: { expr: sql `${issues.cycleId}`, kind: 'uuid' },
|
|
66
|
+
milestone: { expr: sql `${issues.milestoneId}`, kind: 'uuid' },
|
|
67
|
+
parent: { expr: sql `${issues.parentId}`, kind: 'uuid' },
|
|
68
|
+
created: { expr: sql `${issues.createdAt}`, kind: 'timestamp' },
|
|
69
|
+
updated: { expr: sql `${issues.updatedAt}`, kind: 'timestamp' },
|
|
70
|
+
completed: { expr: sql `${issues.completedAt}`, kind: 'timestamp' },
|
|
71
|
+
due: { expr: sql `${issues.dueDate}`, kind: 'date' },
|
|
72
|
+
start: { expr: sql `${issues.startDate}`, kind: 'date' },
|
|
73
|
+
estimate: { expr: sql `${issues.estimate}`, kind: 'number' },
|
|
74
|
+
timespent: { expr: sql `${issues.timeSpentSec}`, kind: 'number' },
|
|
75
|
+
watcher: { expr: sql `${issues.watcherIds}`, kind: 'uuidArray' },
|
|
76
|
+
resolution: { expr: sql `${issues.resolution}`, kind: 'text' },
|
|
77
|
+
text: { expr: sql `${issues.search}`, kind: 'fulltext' },
|
|
78
|
+
triage: { expr: sql `${issues.triage}`, kind: 'bool' },
|
|
79
|
+
archived: { expr: sql `(${issues.archivedAt} is not null)`, kind: 'bool' },
|
|
80
|
+
rank: { expr: sql `${issues.rank}`, kind: 'text' },
|
|
81
|
+
};
|
|
82
|
+
const CUSTOM_KIND = {
|
|
83
|
+
text: 'text',
|
|
84
|
+
textarea: 'text',
|
|
85
|
+
number: 'number',
|
|
86
|
+
date: 'date',
|
|
87
|
+
datetime: 'timestamp',
|
|
88
|
+
select: 'enum',
|
|
89
|
+
multiselect: 'text',
|
|
90
|
+
user: 'uuid',
|
|
91
|
+
multiuser: 'text',
|
|
92
|
+
label: 'text',
|
|
93
|
+
url: 'text',
|
|
94
|
+
checkbox: 'bool',
|
|
95
|
+
relation: 'text',
|
|
96
|
+
formula: 'number',
|
|
97
|
+
};
|
|
98
|
+
const CUSTOM_ARRAY = new Set(['multiselect', 'multiuser', 'label']);
|
|
99
|
+
function customExpr(key, type) {
|
|
100
|
+
switch (type) {
|
|
101
|
+
case 'number':
|
|
102
|
+
case 'formula':
|
|
103
|
+
return sql `nullif(${issues.custom}->>${key}, '')::numeric`;
|
|
104
|
+
case 'date':
|
|
105
|
+
return sql `nullif(${issues.custom}->>${key}, '')::date`;
|
|
106
|
+
case 'datetime':
|
|
107
|
+
return sql `nullif(${issues.custom}->>${key}, '')::timestamptz`;
|
|
108
|
+
case 'checkbox':
|
|
109
|
+
return sql `nullif(${issues.custom}->>${key}, '')::boolean`;
|
|
110
|
+
default:
|
|
111
|
+
return sql `${issues.custom}->>${key}`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** The SQL expression a KQL field name maps to, or null when the field is unknown. */
|
|
115
|
+
export function fieldSql(name, ctx) {
|
|
116
|
+
const field = findField(ctx.fields, name);
|
|
117
|
+
if (!field)
|
|
118
|
+
return null;
|
|
119
|
+
if (field.custom) {
|
|
120
|
+
const type = ctx.customTypes.get(field.custom.key) ?? field.custom.fieldType;
|
|
121
|
+
return { field, expr: customExpr(field.custom.key, type), kind: CUSTOM_KIND[type] };
|
|
122
|
+
}
|
|
123
|
+
const sys = SYSTEM_SQL[field.name.toLowerCase()];
|
|
124
|
+
return sys ? { ...sys, field } : null;
|
|
125
|
+
}
|
|
126
|
+
// =====================================================================================
|
|
127
|
+
// value resolution
|
|
128
|
+
// =====================================================================================
|
|
129
|
+
function idsFor(ctx, refType, text) {
|
|
130
|
+
const map = ctx.lookup.byType.get(refType);
|
|
131
|
+
const hit = map?.get(text.toLowerCase());
|
|
132
|
+
if (hit?.length)
|
|
133
|
+
return hit;
|
|
134
|
+
return UUID_RE.test(text) ? [text] : [];
|
|
135
|
+
}
|
|
136
|
+
/** Resolve a KQL value used against a uuid / ref field into concrete ids. */
|
|
137
|
+
function resolveIds(value, field, ctx) {
|
|
138
|
+
if (value.kind === 'func') {
|
|
139
|
+
const name = value.name.toLowerCase();
|
|
140
|
+
if (name === 'currentuser')
|
|
141
|
+
return ctx.userId ? [ctx.userId] : [];
|
|
142
|
+
if (name === 'activecycle')
|
|
143
|
+
return ctx.lookup.activeCycleIds;
|
|
144
|
+
if (name === 'opencycles')
|
|
145
|
+
return ctx.lookup.openCycleIds;
|
|
146
|
+
if (name === 'membersof') {
|
|
147
|
+
const arg = value.args[0];
|
|
148
|
+
const key = arg && (arg.kind === 'string' || arg.kind === 'ident') ? String(arg.value) : '';
|
|
149
|
+
return idsFor(ctx, 'group', key);
|
|
150
|
+
}
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
if (value.kind === 'string' || value.kind === 'ident') {
|
|
154
|
+
const refType = field.refType ?? (field.kind === 'user' ? 'user' : null);
|
|
155
|
+
return refType ? idsFor(ctx, refType, String(value.value)) : [String(value.value)];
|
|
156
|
+
}
|
|
157
|
+
if (value.kind === 'number')
|
|
158
|
+
return [String(value.value)];
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
/** Resolve a KQL value used against a date/timestamp field into an instant. */
|
|
162
|
+
function resolveInstant(value, ctx) {
|
|
163
|
+
if (value.kind === 'date') {
|
|
164
|
+
const at = parseDateLiteral(value.value);
|
|
165
|
+
return at ? { at, dayPrecision: /^\d{4}-\d{2}-\d{2}$/.test(value.value) } : null;
|
|
166
|
+
}
|
|
167
|
+
if (value.kind === 'reldate')
|
|
168
|
+
return { at: shift(ctx.now, value.amount, value.unit), dayPrecision: false };
|
|
169
|
+
if (value.kind === 'func') {
|
|
170
|
+
const arg = value.args[0];
|
|
171
|
+
const offset = arg?.kind === 'number' ? arg.value : 0;
|
|
172
|
+
switch (value.name.toLowerCase()) {
|
|
173
|
+
case 'now':
|
|
174
|
+
return { at: ctx.now, dayPrecision: false };
|
|
175
|
+
case 'startofday':
|
|
176
|
+
return { at: startOfDay(ctx.now, offset), dayPrecision: false };
|
|
177
|
+
case 'startofweek':
|
|
178
|
+
return { at: startOfWeek(ctx.now, offset), dayPrecision: false };
|
|
179
|
+
case 'startofmonth':
|
|
180
|
+
return { at: startOfMonth(ctx.now, offset), dayPrecision: false };
|
|
181
|
+
default:
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const literalText = (value) => value.kind === 'string' || value.kind === 'ident'
|
|
188
|
+
? String(value.value)
|
|
189
|
+
: value.kind === 'number'
|
|
190
|
+
? String(value.value)
|
|
191
|
+
: value.kind === 'bool'
|
|
192
|
+
? String(value.value)
|
|
193
|
+
: value.kind === 'date'
|
|
194
|
+
? value.value
|
|
195
|
+
: '';
|
|
196
|
+
// =====================================================================================
|
|
197
|
+
// comparison compilation
|
|
198
|
+
// =====================================================================================
|
|
199
|
+
const negate = (condition, negated) => (negated ? sql `(not (${condition}))` : condition);
|
|
200
|
+
function compareOrdered(expr, op, param) {
|
|
201
|
+
switch (op) {
|
|
202
|
+
case '=':
|
|
203
|
+
return sql `${expr} = ${param}`;
|
|
204
|
+
case '!=':
|
|
205
|
+
return sql `(${expr} is distinct from ${param})`;
|
|
206
|
+
case '<':
|
|
207
|
+
return sql `${expr} < ${param}`;
|
|
208
|
+
case '<=':
|
|
209
|
+
return sql `${expr} <= ${param}`;
|
|
210
|
+
case '>':
|
|
211
|
+
return sql `${expr} > ${param}`;
|
|
212
|
+
case '>=':
|
|
213
|
+
return sql `${expr} >= ${param}`;
|
|
214
|
+
default:
|
|
215
|
+
throw new KqlCompileError(`Operator "${op}" is not supported here`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function compileComparison(cmp, ctx) {
|
|
219
|
+
const target = fieldSql(cmp.field, ctx);
|
|
220
|
+
if (!target)
|
|
221
|
+
throw new KqlCompileError(`Unknown field "${cmp.field}"`);
|
|
222
|
+
const { expr, kind, field } = target;
|
|
223
|
+
const isArrayCustom = !!field.custom && CUSTOM_ARRAY.has(field.custom.fieldType);
|
|
224
|
+
if (cmp.op === 'is-empty' || cmp.op === 'is-not-empty') {
|
|
225
|
+
const empty = kind === 'uuidArray'
|
|
226
|
+
? sql `coalesce(array_length(${expr}, 1), 0) = 0`
|
|
227
|
+
: isArrayCustom
|
|
228
|
+
? sql `(${issues.custom}->${field.custom.key} is null or jsonb_array_length(coalesce(${issues.custom}->${field.custom.key}, '[]'::jsonb)) = 0)`
|
|
229
|
+
: kind === 'text' || kind === 'key' || kind === 'enum'
|
|
230
|
+
? sql `(${expr} is null or ${expr} = '')`
|
|
231
|
+
: sql `${expr} is null`;
|
|
232
|
+
return cmp.op === 'is-empty' ? empty : sql `(not (${empty}))`;
|
|
233
|
+
}
|
|
234
|
+
const values = cmp.values ?? (cmp.value ? [cmp.value] : []);
|
|
235
|
+
if (!values.length)
|
|
236
|
+
throw new KqlCompileError(`"${cmp.field}" needs a value`);
|
|
237
|
+
const negated = cmp.op === '!=' || cmp.op === 'not-in' || cmp.op === '!~';
|
|
238
|
+
const membership = cmp.op === 'in' || cmp.op === 'not-in' || cmp.op === '=' || cmp.op === '!=';
|
|
239
|
+
// `null` means "unset" for every field
|
|
240
|
+
if (values.length === 1 && values[0].kind === 'null')
|
|
241
|
+
return negate(sql `${expr} is null`, negated);
|
|
242
|
+
switch (kind) {
|
|
243
|
+
case 'uuidArray': {
|
|
244
|
+
const ids = values.flatMap((v) => resolveIds(v, field, ctx));
|
|
245
|
+
if (!ids.length)
|
|
246
|
+
return negate(FALSE, negated);
|
|
247
|
+
return negate(sql `${expr} && ${sql.param(ids)}::uuid[]`, negated);
|
|
248
|
+
}
|
|
249
|
+
case 'uuid': {
|
|
250
|
+
const ids = values.flatMap((v) => resolveIds(v, field, ctx));
|
|
251
|
+
if (!ids.length)
|
|
252
|
+
return negate(FALSE, negated);
|
|
253
|
+
return negate(sql `${expr} = any(${sql.param(ids)}::uuid[])`, negated);
|
|
254
|
+
}
|
|
255
|
+
case 'priority': {
|
|
256
|
+
const ranks = values.map((v) => priorityRank(literalText(v)));
|
|
257
|
+
if (membership) {
|
|
258
|
+
if (ranks.some((r) => r === null))
|
|
259
|
+
throw new KqlCompileError('Unknown priority');
|
|
260
|
+
return negate(sql `${expr} = any(${sql.param(ranks)}::int[])`, negated);
|
|
261
|
+
}
|
|
262
|
+
const rank = ranks[0];
|
|
263
|
+
if (rank === null)
|
|
264
|
+
throw new KqlCompileError('Unknown priority');
|
|
265
|
+
return compareOrdered(expr, cmp.op, sql `${rank}`);
|
|
266
|
+
}
|
|
267
|
+
case 'enum': {
|
|
268
|
+
if (field.name.toLowerCase() === 'status') {
|
|
269
|
+
const ids = values.flatMap((v) => resolveIds(v, field, ctx));
|
|
270
|
+
if (!ids.length)
|
|
271
|
+
return negate(FALSE, negated);
|
|
272
|
+
return negate(sql `${expr} = any(${sql.param(ids)}::text[])`, negated);
|
|
273
|
+
}
|
|
274
|
+
const texts = values.map((v) => literalText(v).toLowerCase());
|
|
275
|
+
if (!membership)
|
|
276
|
+
return compareOrdered(expr, cmp.op, sql `${texts[0]}`);
|
|
277
|
+
return negate(sql `lower(${expr}) = any(${sql.param(texts)}::text[])`, negated);
|
|
278
|
+
}
|
|
279
|
+
case 'number': {
|
|
280
|
+
const nums = values.map((v) => (v.kind === 'number' ? v.value : Number(literalText(v))));
|
|
281
|
+
if (nums.some((n) => Number.isNaN(n)))
|
|
282
|
+
throw new KqlCompileError(`"${cmp.field}" expects a number`);
|
|
283
|
+
if (!membership)
|
|
284
|
+
return compareOrdered(expr, cmp.op, sql `${nums[0]}`);
|
|
285
|
+
return negate(sql `${expr} = any(${sql.param(nums)}::numeric[])`, negated);
|
|
286
|
+
}
|
|
287
|
+
case 'bool': {
|
|
288
|
+
const v = values[0];
|
|
289
|
+
const bool = v.kind === 'bool' ? v.value : literalText(v).toLowerCase() === 'true';
|
|
290
|
+
return negate(sql `coalesce(${expr}, false) = ${bool}`, negated);
|
|
291
|
+
}
|
|
292
|
+
case 'timestamp':
|
|
293
|
+
case 'date': {
|
|
294
|
+
const resolved = values.map((v) => resolveInstant(v, ctx));
|
|
295
|
+
const first = resolved[0];
|
|
296
|
+
if (!first)
|
|
297
|
+
throw new KqlCompileError(`"${cmp.field}" expects a date`);
|
|
298
|
+
const isDateColumn = kind === 'date';
|
|
299
|
+
const param = (at) => isDateColumn ? sql `${at.toISOString().slice(0, 10)}::date` : sql `${at.toISOString()}::timestamptz`;
|
|
300
|
+
if (cmp.op === '=' || cmp.op === '!=') {
|
|
301
|
+
// a plain day means the whole day, not one instant
|
|
302
|
+
if (first.dayPrecision && !isDateColumn) {
|
|
303
|
+
const next = new Date(first.at.getTime() + 86_400_000);
|
|
304
|
+
return negate(sql `(${expr} >= ${param(first.at)} and ${expr} < ${param(next)})`, negated);
|
|
305
|
+
}
|
|
306
|
+
return negate(sql `${expr} = ${param(first.at)}`, negated);
|
|
307
|
+
}
|
|
308
|
+
if (cmp.op === 'in' || cmp.op === 'not-in') {
|
|
309
|
+
const parts = resolved.filter(Boolean).map((r) => sql `${expr} = ${param(r.at)}`);
|
|
310
|
+
return negate(sql `(${sql.join(parts, sql ` or `)})`, negated);
|
|
311
|
+
}
|
|
312
|
+
return compareOrdered(expr, cmp.op, param(first.at));
|
|
313
|
+
}
|
|
314
|
+
case 'fulltext': {
|
|
315
|
+
const q = values.map(literalText).join(' ');
|
|
316
|
+
return negate(sql `${expr} @@ plainto_tsquery('simple', ${q})`, negated);
|
|
317
|
+
}
|
|
318
|
+
case 'key': {
|
|
319
|
+
const texts = values.map((v) => literalText(v).toUpperCase());
|
|
320
|
+
if (cmp.op === '~' || cmp.op === '!~')
|
|
321
|
+
return negate(sql `${expr} ilike ${`%${texts[0]}%`}`, negated);
|
|
322
|
+
return negate(sql `${expr} = any(${sql.param(texts)}::text[])`, negated);
|
|
323
|
+
}
|
|
324
|
+
default: {
|
|
325
|
+
// text-ish, including array-valued custom fields
|
|
326
|
+
if (isArrayCustom) {
|
|
327
|
+
const texts = values.map(literalText);
|
|
328
|
+
const contains = sql `coalesce(${issues.custom}->${field.custom.key}, '[]'::jsonb) @> ${JSON.stringify(texts.slice(0, 1))}::jsonb`;
|
|
329
|
+
if (cmp.op === 'in' || cmp.op === 'not-in') {
|
|
330
|
+
const parts = texts.map((t) => sql `coalesce(${issues.custom}->${field.custom.key}, '[]'::jsonb) @> ${JSON.stringify([t])}::jsonb`);
|
|
331
|
+
return negate(sql `(${sql.join(parts, sql ` or `)})`, negated);
|
|
332
|
+
}
|
|
333
|
+
return negate(contains, negated);
|
|
334
|
+
}
|
|
335
|
+
const texts = values.map(literalText);
|
|
336
|
+
if (cmp.op === '~' || cmp.op === '!~')
|
|
337
|
+
return negate(sql `${expr} ilike ${`%${texts[0]}%`}`, negated);
|
|
338
|
+
if (!membership)
|
|
339
|
+
return compareOrdered(expr, cmp.op, sql `${texts[0]}`);
|
|
340
|
+
return negate(sql `${expr} = any(${sql.param(texts)}::text[])`, negated);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const priorityRank = (text) => ({ none: 0, low: 1, medium: 2, high: 3, urgent: 4 })[text.toLowerCase()] ?? null;
|
|
345
|
+
function compileExpr(expr, ctx) {
|
|
346
|
+
switch (expr.kind) {
|
|
347
|
+
case 'cmp':
|
|
348
|
+
return compileComparison(expr, ctx);
|
|
349
|
+
case 'not':
|
|
350
|
+
return sql `(not (${compileExpr(expr.child, ctx)}))`;
|
|
351
|
+
case 'and':
|
|
352
|
+
return sql `(${sql.join(expr.children.map((c) => compileExpr(c, ctx)), sql ` and `)})`;
|
|
353
|
+
case 'or':
|
|
354
|
+
return sql `(${sql.join(expr.children.map((c) => compileExpr(c, ctx)), sql ` or `)})`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
/** Compile the `where` part of a parsed query. Returns undefined for an empty query. */
|
|
358
|
+
export function compileWhere(query, ctx) {
|
|
359
|
+
if (!query.where)
|
|
360
|
+
return undefined;
|
|
361
|
+
return compileExpr(query.where, ctx);
|
|
362
|
+
}
|
|
363
|
+
/** Compile one sort key. Unknown fields fall back to `rank`. */
|
|
364
|
+
export function compileOrder(field, dir, ctx) {
|
|
365
|
+
const target = fieldSql(field, ctx);
|
|
366
|
+
const expr = target?.expr ?? sql `${issues.rank}`;
|
|
367
|
+
const direction = dir === 'desc' ? sql `desc` : sql `asc`;
|
|
368
|
+
// sorting must be deterministic even when the key is null
|
|
369
|
+
return sql `${expr} ${direction} nulls last`;
|
|
370
|
+
}
|
|
371
|
+
export { FALSE as sqlFalse, TRUE as sqlTrue };
|
|
372
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/server/kql/compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fractional indexing for manual ordering.
|
|
3
|
+
*
|
|
4
|
+
* A rank is a base-62 fraction written without the leading `0.`, so plain lexicographic ordering of
|
|
5
|
+
* the strings equals numeric ordering of the fractions. Inserting between two neighbours only writes
|
|
6
|
+
* the moved row — never the rest of the list — which is what makes drag-and-drop cheap on a board
|
|
7
|
+
* with thousands of issues.
|
|
8
|
+
*
|
|
9
|
+
* Invariant: a rank never ends in `0`, otherwise there would be no room left below it.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RankError extends Error {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A rank strictly between `before` and `after`.
|
|
15
|
+
* `before = null` means "at the very start", `after = null` means "at the very end".
|
|
16
|
+
*/
|
|
17
|
+
export declare function rankBetween(before: string | null, after: string | null): string;
|
|
18
|
+
/** `count` evenly spread ranks between two neighbours, in order. */
|
|
19
|
+
export declare function rankSequence(before: string | null, after: string | null, count: number): string[];
|
|
20
|
+
/** First rank of an empty list. */
|
|
21
|
+
export declare const initialRank: () => string;
|
|
22
|
+
export declare const isValidRank: (rank: string) => boolean;
|
|
23
|
+
//# sourceMappingURL=rank.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rank.d.ts","sourceRoot":"","sources":["../../src/server/rank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,qBAAa,SAAU,SAAQ,KAAK;CAAG;AA2BvC;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE/E;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAUjG;AAED,mCAAmC;AACnC,eAAO,MAAM,WAAW,QAAO,MAAiC,CAAA;AAEhE,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,OAC2C,CAAA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fractional indexing for manual ordering.
|
|
3
|
+
*
|
|
4
|
+
* A rank is a base-62 fraction written without the leading `0.`, so plain lexicographic ordering of
|
|
5
|
+
* the strings equals numeric ordering of the fractions. Inserting between two neighbours only writes
|
|
6
|
+
* the moved row — never the rest of the list — which is what makes drag-and-drop cheap on a board
|
|
7
|
+
* with thousands of issues.
|
|
8
|
+
*
|
|
9
|
+
* Invariant: a rank never ends in `0`, otherwise there would be no room left below it.
|
|
10
|
+
*/
|
|
11
|
+
const DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
12
|
+
const BASE = DIGITS.length;
|
|
13
|
+
export class RankError extends Error {
|
|
14
|
+
}
|
|
15
|
+
const digit = (c) => {
|
|
16
|
+
const i = DIGITS.indexOf(c);
|
|
17
|
+
if (i < 0)
|
|
18
|
+
throw new RankError(`Invalid rank digit "${c}"`);
|
|
19
|
+
return i;
|
|
20
|
+
};
|
|
21
|
+
/** Strictly between `a` and `b` (both exclusive); `''` is the lower bound, `null` the upper one. */
|
|
22
|
+
function midpoint(a, b) {
|
|
23
|
+
if (b !== null && a >= b)
|
|
24
|
+
throw new RankError(`Ranks out of order: "${a}" >= "${b}"`);
|
|
25
|
+
if (a.endsWith('0') || b?.endsWith('0'))
|
|
26
|
+
throw new RankError('Rank must not end with the lowest digit');
|
|
27
|
+
if (b !== null) {
|
|
28
|
+
let common = 0;
|
|
29
|
+
while ((a[common] ?? '0') === b[common])
|
|
30
|
+
common++;
|
|
31
|
+
if (common > 0)
|
|
32
|
+
return b.slice(0, common) + midpoint(a.slice(common), b.slice(common));
|
|
33
|
+
}
|
|
34
|
+
const digitA = a ? digit(a[0]) : 0;
|
|
35
|
+
const digitB = b !== null && b.length > 0 ? digit(b[0]) : BASE;
|
|
36
|
+
if (digitB - digitA > 1)
|
|
37
|
+
return DIGITS[Math.round((digitA + digitB) / 2)];
|
|
38
|
+
// the leading digits are adjacent: descend into `a`'s tail
|
|
39
|
+
if (b !== null && b.length > 1)
|
|
40
|
+
return b.slice(0, 1);
|
|
41
|
+
return DIGITS[digitA] + midpoint(a.slice(1), null);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A rank strictly between `before` and `after`.
|
|
45
|
+
* `before = null` means "at the very start", `after = null` means "at the very end".
|
|
46
|
+
*/
|
|
47
|
+
export function rankBetween(before, after) {
|
|
48
|
+
return midpoint(before ?? '', after);
|
|
49
|
+
}
|
|
50
|
+
/** `count` evenly spread ranks between two neighbours, in order. */
|
|
51
|
+
export function rankSequence(before, after, count) {
|
|
52
|
+
if (count <= 0)
|
|
53
|
+
return [];
|
|
54
|
+
const out = [];
|
|
55
|
+
let cursor = before;
|
|
56
|
+
for (let i = 0; i < count; i++) {
|
|
57
|
+
const next = rankBetween(cursor, after);
|
|
58
|
+
out.push(next);
|
|
59
|
+
cursor = next;
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/** First rank of an empty list. */
|
|
64
|
+
export const initialRank = () => rankBetween(null, null);
|
|
65
|
+
export const isValidRank = (rank) => rank.length > 0 && !rank.endsWith('0') && [...rank].every((c) => DIGITS.includes(c));
|
|
66
|
+
//# sourceMappingURL=rank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rank.js","sourceRoot":"","sources":["../../src/server/rank.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RichDoc } from '../contract/models.js';
|
|
2
|
+
/**
|
|
3
|
+
* Helpers for the Tiptap/ProseMirror JSON stored in issue descriptions and comments.
|
|
4
|
+
* Mention nodes are `{ type: 'mention', attrs: { id, label, kind: 'user' | 'group' } }`.
|
|
5
|
+
*/
|
|
6
|
+
export type PmNode = {
|
|
7
|
+
type?: string;
|
|
8
|
+
text?: string;
|
|
9
|
+
attrs?: Record<string, unknown>;
|
|
10
|
+
content?: PmNode[];
|
|
11
|
+
marks?: Array<{
|
|
12
|
+
type: string;
|
|
13
|
+
attrs?: Record<string, unknown>;
|
|
14
|
+
}>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Plain-text rendering used for search, notifications and previews.
|
|
18
|
+
* Top-level blocks are separated by a blank line and nested ones (list items, table cells) by a
|
|
19
|
+
* single newline, so `textToDoc(x)` round-trips back to `x`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function docToText(doc: RichDoc | PmNode | null | undefined): string;
|
|
22
|
+
/** User ids mentioned in a document. Mentions inside code are ignored. */
|
|
23
|
+
export declare function extractMentions(doc: RichDoc | PmNode | null | undefined): string[];
|
|
24
|
+
/** Build a minimal document from plain text (email ingest, intake forms, automations). */
|
|
25
|
+
export declare function textToDoc(text: string): RichDoc;
|
|
26
|
+
/** Short single-line preview (notifications, search snippets). */
|
|
27
|
+
export declare function preview(text: string, max?: number): string;
|
|
28
|
+
/** Strip an email reply quote so a threaded reply does not repeat the whole conversation. */
|
|
29
|
+
export declare function stripQuotedReply(text: string): string;
|
|
30
|
+
//# sourceMappingURL=rich.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich.d.ts","sourceRoot":"","sources":["../../src/server/rich.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAEpD;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAA;CACjE,CAAA;AAqBD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAyB1E;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAelF;AAED,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAU/C;AAED,kEAAkE;AAClE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,MAAM,CAGvD;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMrD"}
|