diff --git a/src/dh/dhe-types.d.ts b/src/dh/dhe-types.d.ts new file mode 100644 index 00000000..9c9f6ad4 --- /dev/null +++ b/src/dh/dhe-types.d.ts @@ -0,0 +1,1310 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable @typescript-eslint/no-empty-interface */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable lines-between-class-members */ + +/* eslint-disable max-classes-per-file */ +export default dh; + +export interface dh { + IdeConnection: IdeConnectionConstructor; + Session: IdeSession; + VariableType: VariableType; + i18n: { + DateTimeFormat: DateTimeFormat; + NumberFormat: NumberFormat; + TimeZone: i18nTimeZone; + }; + DateWrapper: DateWrapper; + LongWrapper: LongWrapper; + FilterCondition: FilterConditionStatic; + FilterValue: FilterValueStatic; + plot: Plot; + Axis: Axis; + Table: TableStatic; + Client: ClientStatic; + TreeTable: TreeTableStatic; + Column: Column; + SearchDisplayMode?: SearchDisplayModeStatic; + RangeSet: RangeSet; + IdeSession: IdeSessionStatic; + calendar: CalendarStatic; + CoreClient: CoreClientContructor; + storage: { + FileContents: FileContentsStatic; + }; + ValueType: ValueType; +} + +type VariableType = { + FIGURE: 'Figure'; + OTHERWIDGET: 'OtherWidget'; + PANDAS: 'Pandas'; + TABLE: 'Table'; + TABLEMAP: 'TableMap'; + TREETABLE: 'TreeTable'; + HIERARCHICALTABLE: 'HierarchicalTable'; + PARTITIONEDTABLE: 'PartitionedTable'; +}; + +type ValueType = { + STRING: 'String'; + NUMBER: 'Number'; + DOUBLE: 'Double'; + LONG: 'Long'; + DATETIME: 'Datetime'; + BOOLEAN: 'Boolean'; +}; + +export type ValueTypeUnion = ValueType[keyof ValueType]; + +export interface CalendarStatic { + DayOfWeek: { values: () => string[] }; +} + +/** + * @deprecated + * Used to be a string union, but it can really be any string + */ +export type VariableTypeUnion = string; + +export interface VariableDefinition { + type: T; + + /** + * @deprecated + */ + name?: string; + + title?: string; + + id?: string; +} + +export interface LogItem { + micros: number; + logLevel: string; + message: string; +} + +export interface VariableChanges { + created: VariableDefinition[]; + updated: VariableDefinition[]; + removed: VariableDefinition[]; +} + +export interface CommandResult { + changes: VariableChanges; + error: string; +} + +export interface Position { + line: number; + character: number; +} + +export interface DocumentRange { + start: Position; + end: Position; +} + +export interface TextEdit { + text: string; + range: DocumentRange; +} + +export interface MarkupContent { + value: string; + kind: 'markdown' | 'plaintext'; +} + +export interface CompletionItem { + label: string; + kind: number; + detail: string; + documentation: MarkupContent; + sortText: string; + filterText: string; + textEdit: TextEdit; + insertTextFormat: number; +} + +export interface ParameterInfo { + label: string; + documentation: string; +} + +export interface SignatureInfo { + label: string; + documentation?: MarkupContent; + parameters?: ParameterInfo[]; + activeParameter: number; +} + +export interface Hover { + contents?: MarkupContent; + range?: DocumentRange; +} + +export interface IdeSessionStatic { + EVENT_COMMANDSTARTED: 'commandstarted'; +} + +export interface WorkerConnection { + subscribeToFieldUpdates( + param: (changes: VariableChanges) => void + ): () => void; +} + +export interface IdeSession extends Evented { + subscribeToFieldUpdates( + param: (changes: VariableChanges) => void + ): () => void; + getTable(name: string): Promise; + getFigure(name: string): Promise
; + getTreeTable(name: string): Promise; + getObject( + definition: VariableDefinition + ): Promise
; + getObject( + definition: VariableDefinition + ): Promise
; + getObject( + definition: VariableDefinition + ): Promise; + getObject( + definition: VariableDefinition + ): Promise; + getObject(definition: VariableDefinition): Promise; + onLogMessage(logHandler: (logItem: LogItem) => void): () => void; + runCode(code: string): Promise; + bindTableToVariable(table: Table, variableName: string): Promise; + mergeTables(tables: Table[]): Promise
; + newTable( + columnNames: string[], + columnTypes: string[], + data: string[][], + userTimeZone: string + ): Promise
; + getCompletionItems(params: unknown): Promise; + getSignatureHelp?(params: unknown): Promise; + getHover?(params: unknown): Promise; + closeDocument(params: unknown): void; + openDocument(params: unknown): void; + changeDocument(params: unknown): void; + close(): void; +} + +export interface Evented { + addEventListener(eventType: string, listener: EventListener): RemoverFn; + nextEvent(eventType: string, timeoutInMillis?: number): Promise; + + hasListeners(eventType: string): boolean; + removeEventListener(eventType: string, listener: EventListener): boolean; +} + +export interface Plot { + Figure: Figure; + + SourceType: SourceType; + SeriesPlotStyle: SeriesPlotStyle; + ChartType: ChartType; + AxisType: AxisType; + AxisPosition: AxisPosition; + AxisFormatType: AxisFormatType; + + FigureDescriptor: FigureDescriptor; + ChartDescriptor: ChartDescriptor; + SeriesDescriptor: SeriesDescriptor; + SourceDescriptor: SourceDescriptor; + DownsampleOptions: DownsampleOptions; + + ChartData: typeof ChartData; +} + +export interface RemoverFn { + (): void; +} + +export interface EventListener { + (event: CustomEvent): void; +} + +export interface FigureDescriptor { + title: string; + titleFont?: string; + titleColor?: string; + isResizable?: boolean; + isDefaultTheme?: boolean; + updateInterval?: number; + rows?: number; + cols?: number; + charts: Partial[]; +} +export interface ChartDescriptor { + rowspan?: number; + colspan?: number; + series: Partial[]; + axes: Partial[]; + chartType: string; + title?: string; + titleFont?: string; + titleColor?: string; + showLegend?: boolean; + legendFont?: string; + legendColor?: string; + is3d?: boolean; +} +export interface SeriesDescriptor { + plotStyle: string; + name: string; + linesVisible?: boolean; + shapesVisible?: boolean; + gradientVisible?: boolean; + lineColor?: string; + pointLabelFormat?: string; + xToolTipPattern?: string; + yToolTipPattern?: string; + shapeLabel?: string; + shapeSize?: number; + shapeColor?: string; + shape?: string; +} +export interface SourceDescriptor { + axis?: AxisDescriptor; + table: Table; + columnName: string; + columnType: string; +} +export interface AxisDescriptor { + formatType: string; + type: string; + position: string; + log?: boolean; + label?: string; + labelFont?: string; + ticksFont?: string; + formatPattern?: string; + color?: string; + minRange?: number; + maxRange?: number; + minorTicksVisible?: boolean; + majorTicksVisible?: boolean; + minorTickCount?: number; + gapBetweenMajorTicks?: number; + tickLabelAngle?: number; + invert?: boolean; + isTimeAxis?: boolean; +} +export interface Figure extends Evented { + readonly EVENT_UPDATED: string; + readonly EVENT_DISCONNECT: string; + readonly EVENT_RECONNECT: string; + readonly EVENT_RECONNECTFAILED: string; + readonly EVENT_DOWNSAMPLESTARTED: string; + readonly EVENT_DOWNSAMPLEFINISHED: string; + readonly EVENT_DOWNSAMPLEFAILED: string; + readonly EVENT_DOWNSAMPLENEEDED: string; + readonly EVENT_SERIES_ADDED: string; + + /** Given a client-created figure descriptor, generate a figure that can be subscribed to */ + create(figure: Partial): Promise
; + + readonly title: string; + readonly titleFont: string; + readonly titleColor: string; + readonly isResizable: boolean; + readonly isDefaultTheme: boolean; + readonly updateInterval: number; + readonly cols: number; + readonly rows: number; + readonly charts: Chart[]; + + /** + * Subscribes to all series in this figure. + * @param forceDisableDownsample optional, can be specified to force downsampling to be disabled + */ + subscribe(forceDisableDownsample?: DownsampleOptions): void; + + /** + * Unsubscribes to all series in this figure. + */ + unsubscribe(): void; + + close(): void; +} + +export interface FigureDataUpdatedEvent { + /** + * The series instances which were affected by this event and need to be updated. + */ + readonly series: Series[]; + + /** + * Reads data out for this series from the event which just occurred for the given series. + * The array returned by this method will be cached and reused to minimize the garbage + * created, and to reduce processing time in handling updates. + * + * The pattern when using this is to iterate over the series which this event affects, and + * for each series, iterate over each source. For each series+source, pass them in, along + * with the optional mapping function, and get back the array of data across the entire plot. + * + * @param series + * @param sourceType + * @param mapFn + */ + getArray( + series: Series, + sourceType: SourceType, + mapFn?: MapFn + ): O[]; +} + +export interface MapFn { + (input: I): O; +} + +export interface DownsampleOptions { + readonly DEFAULT: DownsampleOptions; + readonly DISABLE: DownsampleOptions; +} + +export interface SourceType { + readonly X: SourceType; + readonly Y: SourceType; + readonly Z: SourceType; + readonly X_LOW: SourceType; + readonly X_HIGH: SourceType; + readonly Y_LOW: SourceType; + readonly Y_HIGH: SourceType; + readonly TIME: SourceType; + readonly OPEN: SourceType; + readonly HIGH: SourceType; + readonly LOW: SourceType; + readonly CLOSE: SourceType; + readonly SHAPE: SourceType; + readonly SIZE: SourceType; + readonly LABEL: SourceType; + readonly COLOR: SourceType; + readonly PARENT: SourceType; + readonly HOVER_TEXT: SourceType; + readonly TEXT: SourceType; +} +export interface ChartType { + readonly XY: ChartType; + readonly PIE: ChartType; + readonly OHLC: ChartType; + readonly CATEGORY: ChartType; + readonly XYZ: ChartType; + readonly CATEGORY_3D: ChartType; +} +export interface SeriesPlotStyle { + readonly BAR: SeriesPlotStyle; + readonly STACKED_BAR: SeriesPlotStyle; + readonly LINE: SeriesPlotStyle; + readonly AREA: SeriesPlotStyle; + readonly STACKED_AREA: SeriesPlotStyle; + readonly PIE: SeriesPlotStyle; + readonly HISTOGRAM: SeriesPlotStyle; + readonly OHLC: SeriesPlotStyle; + readonly SCATTER: SeriesPlotStyle; + readonly STEP: SeriesPlotStyle; + readonly ERROR_BAR: SeriesPlotStyle; + readonly TREEMAP: SeriesPlotStyle; +} +export interface AxisFormatType { + readonly CATEGORY: AxisFormatType; + readonly NUMBER: AxisFormatType; +} +export interface AxisType { + readonly X: AxisType; + readonly Y: AxisType; + readonly Z: AxisType; + readonly SHAPE: AxisType; + readonly SIZE: AxisType; + readonly LABEL: AxisType; + readonly COLOR: AxisType; +} +export interface AxisPosition { + readonly TOP: AxisPosition; + readonly BOTTOM: AxisPosition; + readonly LEFT: AxisPosition; + readonly RIGHT: AxisPosition; + readonly NONE: AxisPosition; +} + +export interface Chart extends Evented { + readonly EVENT_SERIES_ADDED: string; + + readonly row: number; + readonly column: number; + readonly colspan: number; + readonly rowspan: number; + readonly chartType: ChartType; + readonly title: string; + readonly titleFont: string; + readonly titleColor: string; + readonly showLegend: boolean; + readonly legendFont: string; + readonly legendColor: string; + readonly is3d: boolean; + readonly series: Series[]; + readonly multiSeries: MultiSeries[]; + readonly axes: Axis[]; +} + +export interface Series { + readonly plotStyle: SeriesPlotStyle; + readonly name: string; + readonly isLinesVisible: boolean | null; + readonly isShapesVisible: boolean | null; + readonly isGradientVisible: boolean; + readonly lineColor: string; + readonly pointLabelFormat: string; + readonly xToolTipPattern: string; + readonly yToolTipPattern: string; + readonly shapeLabel: string; + readonly shapeSize: number; + readonly shape: string; + readonly shapeColor: string; + readonly sources: SeriesDataSource[]; + readonly multiSeries: MultiSeries; + readonly oneClick: OneClick; + + subscribe(downsampleOptions?: DownsampleOptions): void; + unsubscribe(): void; +} + +export interface MultiSeries { + readonly plotStyle: SeriesPlotStyle; + readonly name: string; +} + +export interface BusinessPeriod { + open: string; + close: string; +} + +export interface LocalDateWrapper { + toString: () => string; +} +export interface Holiday { + date: LocalDateWrapper; + businessPeriods: BusinessPeriod[]; +} + +export interface BusinessCalendar { + getName: () => string; + timeZone: TimeZone; + businessPeriods: BusinessPeriod[]; + businessDays: string[]; + holidays: Holiday[]; +} + +export interface Axis { + readonly id: string; + readonly formatType: AxisFormatType; + readonly type: AxisType; + readonly position: AxisPosition; + readonly log: boolean; + readonly label: string; + readonly labelFont: string; + readonly ticksFont: string; + readonly formatPattern: string; + readonly minRange: number; + readonly maxRange: number; + readonly isMinorTicksVisible: boolean; + readonly isMajorTicksVisible: boolean; + readonly minorTickCount: number; + readonly gapBetweenMajorTicks: number; + readonly majorTickLocations: number[]; + readonly tickLabelAngle: number; + readonly isInvert: boolean; + readonly isTimeAxis: boolean; + + readonly FORMAT_TYPE_NUMBER: unknown; + readonly businessCalendar: BusinessCalendar; + + /** + * Indicate the density and range of data that the UI needs for this axis, across any series which + * draws on this axis. Ignored for non-time series data, for non-line series. + * @param pixelCount the approx number of pixels wide + * @param min the optional minimum value visible on this axis - even if specified, smaller values may + * be returned, to ensure that lines drawn off the screen. + * @param max the optional max value visible on this axis. If min is specified, max is also expected. + */ + range(pixelCount?: number, min?: any, max?: any): void; +} + +export interface SeriesDataSource { + readonly axis: Axis; + readonly type: SourceType; + readonly columnType: string; +} + +export interface OneClick { + readonly columns: { name: string; type: string }[]; + readonly requireAllFiltersToDisplay: boolean; + + setValueForColumn(columnName: string, value: any): void; + getValueForColumn(columnName: string): any; +} + +export interface Column { + readonly type: string; + readonly name: string; + readonly description: string; + readonly constituentType: string; + + readonly isPartitionColumn: boolean; + readonly isSortable?: boolean; + + filter(): FilterValue; + sort(): Sort; + + formatColor(expression: string): CustomColumn; + formatRowColor(expression: string): CustomColumn; +} + +export interface CustomColumn { + readonly type: string; + readonly name: string; + readonly expression: string; +} + +export interface FilterValueStatic { + ofString(input: unknown): FilterValue; + ofNumber(input: unknown): FilterValue; + ofBoolean(input: unknown): FilterValue; +} +export interface FilterValue { + eq(value: FilterValue): FilterCondition; + eqIgnoreCase(value: FilterValue): FilterCondition; + notEq(value: FilterValue): FilterCondition; + notEqIgnoreCase(value: FilterValue): FilterCondition; + greaterThan(value: FilterValue): FilterCondition; + lessThan(value: FilterValue): FilterCondition; + greaterThanOrEqualTo(value: FilterValue): FilterCondition; + lessThanOrEqualTo(value: FilterValue): FilterCondition; + in(values: FilterValue[]): FilterCondition; + inIgnoreCase(values: FilterValue[]): FilterCondition; + notIn(values: FilterValue[]): FilterCondition; + notInIgnoreCase(values: FilterValue[]): FilterCondition; + contains(value: FilterValue): FilterCondition; + containsIgnoreCase(value: FilterValue): FilterCondition; + isFalse(): FilterCondition; + isTrue(): FilterCondition; + isNull(): FilterCondition; + invoke(method: string, ...args: FilterValue[]): FilterCondition; + matches(value: FilterValue): FilterCondition; + matchesIgnoreCase(value: FilterValue): FilterCondition; +} + +export interface FilterConditionStatic { + invoke(method: string, ...args: FilterValue[]): FilterCondition; + search(value: FilterValue, columns?: FilterValue[]): FilterCondition; +} +export interface FilterCondition { + not(): FilterCondition; + and(first: FilterCondition, ...rest: FilterCondition[]): FilterCondition; + or(first: FilterCondition, ...rest: FilterCondition[]): FilterCondition; + + toString(): string; +} +export interface Sort { + reverse(): Sort; + + readonly column: Column; + readonly direction: 'ASC' | 'DESC' | 'REVERSE' | null; + + readonly isAbs: boolean; + + asc(): Sort; + desc(): Sort; + abs(): Sort; +} + +export interface InputTable { + keys: string[]; + keyColumns: Column[]; + values: string[]; + valueColumns: Column[]; + addRow( + row: Record, + userTimeZone?: string + ): Promise; + addRows( + rows: Record[], + userTimeZone?: string + ): Promise; + addTable(table: Table): Promise; + addTables(tables: Table[]): Promise; + deleteTable(table: Table): Promise; + deleteTables(tables: Table[]): Promise; + table: Table; +} +export interface ColumnGroup { + name: string; + children: string[]; + color?: string; +} + +export interface LayoutHints { + areSavedLayoutsAllowed?: boolean; + frontColumns?: string[]; + backColumns?: string[]; + hiddenColumns?: string[]; + frozenColumns?: string[]; + columnGroups?: ColumnGroup[]; + searchDisplayMode?: keyof SearchDisplayModeStatic; +} + +export interface SearchDisplayModeStatic { + SEARCH_DISPLAY_DEFAULT: 'Default'; + SEARCH_DISPLAY_HIDE: 'Hide'; + SEARCH_DISPLAY_SHOW: 'Show'; +} + +export interface TableStatic { + readonly EVENT_SIZECHANGED: string; + readonly EVENT_UPDATED: string; + readonly EVENT_ROWADDED: string; + readonly EVENT_ROWREMOVED: string; + readonly EVENT_ROWUPDATED: string; + readonly EVENT_SORTCHANGED: string; + readonly EVENT_FILTERCHANGED: string; + readonly EVENT_CUSTOMCOLUMNSCHANGED: string; + readonly EVENT_DISCONNECT: string; + readonly EVENT_RECONNECT: string; + readonly EVENT_RECONNECTFAILED: string; + readonly SIZE_UNCOALESCED: number; + reverse(): Sort; +} + +export interface ClientStatic { + readonly EVENT_REQUEST_FAILED: 'requestfailed'; + readonly EVENT_REQUEST_STARTED: 'requeststarted'; + readonly EVENT_REQUEST_SUCCEEDED: 'requestsucceeded'; +} +export interface Table extends TableTemplate
, TableStatic { + readonly totalSize: number; + + readonly description: string; + + customColumns: string[]; + + readonly layoutHints: LayoutHints; + + readonly isUncoalesced: boolean; + readonly hasInputTable: boolean; + + readonly isClosed: boolean; + readonly pluginName: string; + + applyCustomColumns(columns: (CustomColumn | string)[]): string[]; + + getViewportData(): Promise; + + subscribe(columns: Column[]): TableSubscription; + + selectDistinct(columns: Column[]): Promise
; + copy(): Promise
; + + rollup(config: RollupConfig): Promise; + treeTable(config: TreeTableConfig): Promise; + + inputTable(): Promise; + + freeze(): Promise
; + + snapshot( + rightHandSide: Table, + doInitialSnapshot?: boolean, + stampColumns?: string[] + ): Promise
; + + getColumnStatistics(column: Column): Promise; + + join( + joinType: string, + rightTable: Table, + columnsToMatch: string[], + columnsToAdd?: string[] + ): Promise
; + byExternal(keys: string[], dropKeys?: boolean): Promise; + + fireViewportUpdate(): void; + + seekRow( + startRow: number, + column: Column, + valueType: ValueTypeUnion, + value: unknown, + insensitive?: boolean, + contains?: boolean, + isBackwards?: boolean + ): Promise; +} + +export interface TableViewportSubscription extends Evented { + setViewport(firstRow: number, lastRow: number, columns?: Column[]): void; + getViewportData(): Promise; + snapshot(rows: RangeSet, columns: readonly Column[]): Promise; + close(): void; +} + +export interface ViewportData { + offset: number; + rows: Row[]; + columns: Column[]; +} + +export interface TableSubscription extends Evented { + readonly EVENT_UPDATED: string; + + readonly columns: Column[]; + close(): void; +} + +export interface RangeSet { + ofRange(first: number, last: number): RangeSet; + ofItems(rows: number[]): RangeSet; + ofRanges(ranges: RangeSet[]): RangeSet; + + readonly size: number; + iterator(): JsIterator; +} + +export interface JsIterator { + hasNext(): boolean; + next(): IteratorResult; +} + +export interface LongWrapper { + asNumber(): number; + valueOf(): string; + toString(): string; + ofString(str: string): LongWrapper; +} +export interface DateWrapper extends LongWrapper { + ofJsDate(date: Date): DateWrapper; + asDate(): Date; +} + +export interface TimeZone { + adjustments: number[]; + standardOffset: number; + timeZoneID: string; + id: string; + transitionPoints: number[]; + tzNames: string[]; +} + +export interface i18nTimeZone { + getTimeZone(tzCode: string): TimeZone; +} + +export interface DateTimeFormat { + format( + pattern: string, + date: DateWrapper | Date | number, + timeZone?: TimeZone + ): string; + parse(pattern: string, text: string, timeZone?: TimeZone): DateWrapper; + parseAsDate(pattern: string, text: string): Date; +} + +export interface NumberFormat { + format(pattern: string, number: number): string; + parse(pattern: string, text: string): number; +} + +export interface TableData { + readonly columns: Column[]; + readonly rows: Row[]; + + get(index: number): Row; + get(index: LongWrapper): Row; + + getData(index: number, column: Column): any; + getData(index: LongWrapper, column: Column): any; + + getFormat(index: number, column: Column): Format; + getFormat(index: LongWrapper, column: Column): Format; +} + +export interface UpdateEventData extends TableData { + readonly added: RangeSet; + readonly removed: RangeSet; + readonly modified: RangeSet; + readonly fullIndex: RangeSet; +} + +export interface Row { + readonly index: LongWrapper; + + get(column: Column): any; + + getFormat(column: Column): Format; +} + +export interface Format { + readonly color: string; + readonly backgroundColor: string; + readonly formatString: string; +} + +export interface ColumnStatistics { + readonly statisticsMap: Map; + readonly uniqueValues: Map; + + getType(name: string): string; +} + +export interface TreeTableStatic { + readonly EVENT_UPDATED: string; + readonly EVENT_DISCONNECT: string; + readonly EVENT_RECONNECT: string; + readonly EVENT_RECONNECTFAILED: string; +} + +export interface TableTemplate extends Evented { + readonly size: number; + readonly columns: Column[]; + readonly sort: Sort[]; + readonly filter: FilterCondition[]; + readonly totalsTableConfig: TotalsTableConfig; + + findColumn(name: string): Column; + findColumns(names: string[]): Column[]; + + applySort(sorts: Sort[]): Sort[]; + applyFilter(filters: FilterCondition[]): FilterCondition[]; + selectDistinct(columns: Column[]): Promise
; + + getTotalsTable(config?: TotalsTableConfig): Promise; + getGrandTotalsTable(config?: TotalsTableConfig): Promise; + + setViewport( + firstRow: number, + lastRow: number, + columns?: Column[], + updateIntervalMs?: number + ): TableViewportSubscription; + + copy(): Promise; + close(): void; +} + +export interface TreeTable extends TableTemplate, TreeTableStatic { + readonly isIncludeConstituents: boolean; + readonly groupedColumns: Column[]; + + expand(row: number): void; + expand(row: TreeRow): void; + collapse(row: number): void; + collapse(row: TreeRow): void; + setExpanded( + row: number, + isExpanded: boolean, + expandDescendants?: boolean + ): void; + setExpanded( + row: TreeRow, + isExpanded: boolean, + expandDescendants?: boolean + ): void; + expandAll?(): void; + collapseAll?(): void; + isExpanded(row: number): boolean; + isExpanded(row: TreeRow): boolean; + + getViewportData(): Promise; + + saveExpandedState(): string; + restoreExpandedState(nodesToRestore: string): void; +} +export interface TreeTableData extends TableData { + readonly rows: TreeRow[]; +} +export interface TreeRow extends Row { + readonly isExpanded: boolean; + readonly hasChildren: boolean; + readonly depth: number; +} + +export interface RollupConfig { + groupingColumns: string[] | null; + aggregations: Record | null; + includeConstituents: boolean; + includeOriginalColumns?: boolean; + includeDescriptions: boolean; +} + +export interface TreeTableConfig {} + +export interface TotalsTableConfig { + showTotalsByDefault?: boolean; + showGrandTotalsByDefault?: boolean; + defaultOperation?: string; + groupBy?: readonly string[]; + operationMap: Record; +} + +export interface TotalsTable extends Evented { + readonly size: number; + readonly columns: Column[]; + + readonly sort: Sort[]; + readonly filter: FilterCondition[]; + customColumns: string[]; + + readonly totalsTableConfig: TotalsTableConfig; + + applySort(sorts: Sort[]): Sort[]; + applyFilter(filters: FilterCondition[]): FilterCondition[]; + applyCustomColumns(columns: string[]): string[]; + + setViewport( + firstRow: number, + lastRow: number, + columns?: Column[], + updateIntervalMs?: number + ): void; + getViewportData(): Promise; + + close(): void; +} + +export interface TableMap extends Evented { + readonly size: number; + close(): void; + getKeys(): Promise>; + getTable(key: object): Promise
; +} + +export interface WorkerHeapInfo { + readonly maximumHeapSize: number; + readonly freeMemory: number; + readonly totalHeapSize: number; +} + +export interface QueryConnectable extends Evented { + getWorkerHeapInfo(): Promise; + getConsoleTypes(): Promise; + startSession(type: string): Promise; +} + +export interface IdeConnectionOptions { + authoToken?: string; + serviceId?: string; +} + +export interface IdeConnectionConstructor { + /** @deprecated Use EVENT_DISCONNECT and EVENT_RECONNECT instead */ + HACK_CONNECTION_FAILURE: string; + EVENT_DISCONNECT: string; + EVENT_RECONNECT: string; + EVENT_SHUTDOWN: string; + + new (serverUrl: string, options?: IdeConnectionOptions): IdeConnection; +} + +export interface IdeConnection + extends QueryConnectable, + IdeConnectionConstructor { + close(): void; + running(): Promise; + disconnected(): void; + getObject( + definition: VariableDefinition + ): Promise
; + getObject( + definition: VariableDefinition + ): Promise
; + getObject( + definition: VariableDefinition + ): Promise; + getObject( + definition: VariableDefinition + ): Promise; + getObject(definition: VariableDefinition): Promise; + subscribeToFieldUpdates( + param: (changes: VariableChanges) => void + ): () => void; +} + +export interface ItemDetails { + filename: string; + basename: string; + dirname: string; + type: 'directory' | 'file'; + size: number; + etag?: string; +} + +interface Blob { + readonly size: number; + readonly type: string; + slice(start?: number, end?: number, contentType?: string): Blob; +} + +export interface FileContentsStatic { + blob(blob: Blob): FileContents; + text(...text: string[]): FileContents; + arrayBuffers(...buffers: ArrayBuffer[]): FileContents; +} + +export interface FileContents { + text(): Promise; + arrayBuffer(): Promise; + etag?: string; +} + +export interface LoginOptions { + type: string; + token?: string; +} + +export interface StorageService { + listItems(path: string, glob?: string): Promise; + loadFile(path: string, etag?: string): Promise; + deleteItem(path: string): Promise; + saveFile( + path: string, + contents: FileContents, + allowOverwrite?: boolean + ): Promise; + moveItem(path: string, newPath: string, newFile?: boolean): Promise; + createDirectory(path: string): Promise; +} + +export interface ConnectOptions { + headers?: Record; +} + +export interface CoreClientContructor extends Evented { + EVENT_CONNECT: string; + EVENT_DISCONNECT: string; + EVENT_RECONNECT: string; + EVENT_RECONNECT_AUTH_FAILED: string; + EVENT_REFRESH_TOKEN_UPDATED: string; + LOGIN_TYPE_ANONYMOUS: string; + new (serverUrl: string, options?: ConnectOptions): CoreClient; +} + +export interface CoreClient extends CoreClientContructor { + login(options: LoginOptions): Promise; + getAsIdeConnection(): Promise; + getStorageService(): StorageService; + getServerConfigValues(): Promise<[string, string][]>; + getAuthConfigValues(): Promise<[string, string][]>; + disconnect(): void; +} + +/** + * Helper class to manage snapshots and deltas and keep not only a contiguous JS array of data per column in the + * underlying table, but also support a mapping function to let client code translate data in some way for display and + * keep that cached as well. + */ +declare class ChartData { + constructor(table: Table); + + update(eventDetail: object): void; + getColumn( + columnName: string, + mappingFunc: (input: any) => any, + currentUpdate: TableData + ): Array; + /** + * Removes some column from the cache, avoiding extra computation on incoming events, and possibly freeing some + * memory. If this pair of column name and map function are requested again, it will be recomputed from scratch. + */ + removeColumn(columnName: string, mappingFunc: (input: any) => any): void; +} + +export type { ChartData }; + +/** From iris.ts in other vscode plugin */ + +export type DeserializedRowData = Record & { + data: Record; +}; + +export type SerializedRowData = Record & { + data: string; +}; + +/* eslint-disable @typescript-eslint/naming-convention */ +export type EnterpriseClientStatic = { + EVENT_CONNECT: 'connect'; + EVENT_DISCONNECT: 'disconnect'; + EVENT_RECONNECT: 'reconnect'; + EVENT_RECONNECT_AUTH_FAILED: 'reconnectauthfailed'; + EVENT_CONFIG_ADDED: 'configadded'; + EVENT_CONFIG_REMOVED: 'configremoved'; + EVENT_CONFIG_UPDATED: 'configupdated'; + + LOGIN_TYPE_PASSWORD: 'password'; + LOGIN_TYPE_SAML: 'saml'; +}; + +export interface EnterpriseClientConstructor { + new (websocketUrl: string): EnterpriseClient; +} + +export type EnterpriseDhType = dh & { + Client: EnterpriseClientStatic & EnterpriseClientConstructor; + // RangeSet: RangeSet; + // Table: Table; + // parameterized: Parameterized; + // VariableType: typeof VariableType; + // ConsoleServerAddress: ConsoleServerAddress; + Ide: IdeConstructor; + ConsoleConfig: ConsoleConfigConstructor; + // QueryInfo: QueryInfoStatic; +}; + +export interface EnterpriseClient { + // getQuerySelectionPermissions( + // serialIds: string[] + // ): Promise; + // getEditableQuery(serialId: string): Promise; + getKnownConfigs(): QueryInfo[]; + addEventListener( + type: string, + listener: (event: CustomEvent) => void + ): () => void; + // removeEventListener( + // type: string, + // listener: (event: ClientListenerEvent) => void + // ): void; + // disconnect(): void; + // getDispatcher( + // serverGroup: string, + // heapSizeMB: number, + // engine: string + // ): Promise; + // saveQuery(query: DraftQuery, doRestart: boolean): Promise; + // createQuery(query: DraftQuery): Promise; + createAuthToken(key: string): Promise; + // /** Imports the XML string as queries, and returns the query info. Does _not_ actually create them, use `saveQueries()` to save them. */ + // importQueries: (xml: string) => Promise; + // /** Returns a string containing the XML of all queries specified */ + // exportQueries: (serialIds: string[]) => Promise; + // relogin(token: unknown): Promise; + // getAllGroups(): Promise; + // getAllUsers(): Promise; + // getTemporaryQueueNames(): Promise; + // getScriptPaths(serialId: string | null, owner?: string): Promise; + // getQuerySerialsForDependent(isTemporary: boolean): Promise; + // getDbServersForType(type: string): Promise; + // /** + // * Save queries to the system. + // * @param queries Query info to save + // * @param replaceExisting Whether to replace existing queries or create new ones. If a serial is specified on a query and it is saved and `replaceExisting` is false, it will throw an error if a query with that serial already exists. + // */ + // saveQueries: ( + // queries: readonly EditableQueryInfo[], + // replaceExisting: boolean + // ) => Promise; + // getAuthConfigValues(): Promise; + // onConnected(timeout: number): Promise; + // getConsoleServers(): Promise; + // getDbServers(): Promise; + // getJvmProfiles(): Promise; + // getQueryConstants(): Promise; + // getServerConfigValues(): Promise; + // getBusinessCalendars(): Promise; + // getDefaultCalendar(): Promise; + // getGroupsForUser(): Promise; + // getUserInfo(): Promise; + // getQueryConfigurationTypes(): Promise>; + login(credentials: LoginCredentials): Promise; + // restartQueries(serialIds: string[]): Promise; + // stopQueries(serialIds: string[]): Promise; + // getScriptBody( + // path: string | null, + // owner: string | null, + // serialId: string | null + // ): Promise; +} + +export interface CancelablePromise extends Promise { + cancel: () => void; +} + +export interface ConsoleConfig { + dispatcherHost?: string; + dispatcherPort?: number; + queryDescription: string; + jvmProfile: string; + maxHeapMb: number; + jvmArgs: string[]; + envVars: [string, string][]; + classpath: string[]; + debug: boolean; + detailedGCLogging: boolean; + workerKind: string; + workerCreationJson: string; +} + +export interface ConsoleConfigConstructor { + new (): ConsoleConfig; +} + +export interface LoginCredentials { + username?: string; + type: string; + token: string; + operateAs?: string; +} + +export interface IdeConstructor { + new (client: EnterpriseClient): Ide; +} + +export interface Ide { + createConsole(config: ConsoleConfig): CancelablePromise; + startWorker(config: ConsoleConfig): CancelablePromise; +} + +export interface IdeConnection extends QueryConnectable { + serviceId: string; + processInfoId: string; + running(): Promise; + close(): void; +} + +export interface DhcConnectionDetails { + readonly envoyPrefix: string | null; + readonly grpcUrl: string; + readonly ideUrl: string; + readonly jsApiUrl: string; + readonly serviceId: string; + readonly processInfoId: string; + readonly workerName: string; + + close(): void; + addEventListener: ( + name: string, + callback: (event: CustomEvent) => void + ) => () => void; + removeEventListener(type: string, listener: () => void): void; +} + +export interface QueryInfo { + name: string; + + getTable(name: string): Promise
; + + getFigure(name: string): Promise; + + createWorkspaceData(row: unknown): Promise; + + saveWorkspaceData( + serializedRowData: SerializedRowData, + workspaceStorageVersion: number + ): Promise; +} diff --git a/src/dh/dhe.ts b/src/dh/dhe.ts new file mode 100644 index 00000000..258be240 --- /dev/null +++ b/src/dh/dhe.ts @@ -0,0 +1,74 @@ +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import type { + EnterpriseClient, + EnterpriseDhType as DheType, + QueryInfo, + Table, + DeserializedRowData, + Row, + Column, +} from './dhe-types'; +import { + downloadFromURL, + getTempDir, + polyfillDh, + urlToDirectoryName, +} from '../util'; + +declare global { + // TODO: Whenever we have ES6 / CommonJS jsapi-types we can hopefully do away + // with defining iris on the global object + export const iris: DheType; +} + +/** + * Initialize an `iris` jsapi instance. + * 1. Polyfill the `iris` jsapi + * 2. Download the `iris` jsapi from the server to a tmp location and load it + * @param serverUrl + * @returns + */ +export async function initDheApi(serverUrl: string): Promise { + polyfillDh(); + return getDhe(serverUrl, true); +} + +/** + * Download the `iris` jsapi from the server to a tmp location, load the module, + * and return it. + * @param serverUrl + * @param download + * @returns The `iris` jsapi module + */ +export async function getDhe( + serverUrl: string, + download: boolean +): Promise { + const tmpDir = getTempDir(false, urlToDirectoryName(serverUrl)); + + if (download) { + const dhe = await downloadFromURL( + path.join(serverUrl, 'irisapi/irisapi.nocache.js') + ); + fs.writeFileSync(path.join(tmpDir, 'irisapi.nocache.js'), dhe); + } + + require(path.join(tmpDir, 'irisapi.nocache.js')); + + return iris; +} + +/** + * Get the websocket URL based on the given server url. + * @param serverUrl + */ +export function getWsUrl(serverUrl: string): string { + const url = new URL('/socket', serverUrl); + if (url.protocol === 'http:') { + url.protocol = 'ws:'; + } else { + url.protocol = 'wss:'; + } + return url.href; +} diff --git a/src/services/DheService.ts b/src/services/DheService.ts new file mode 100644 index 00000000..f1375064 --- /dev/null +++ b/src/services/DheService.ts @@ -0,0 +1,50 @@ +import { dh } from '@deephaven/jsapi-types'; +import { ConnectionAndSession } from '../common'; +import { EnterpriseDhType as DheType, EnterpriseClient } from '../dh/dhe-types'; +import DhService from './DhService'; +import { getWsUrl, initDheApi } from '../dh/dhe'; +import { Logger } from '../util'; + +const logger = new Logger('DhcService'); + +export class DheService extends DhService { + protected initApi(): Promise { + return initDheApi(this.serverUrl); + } + + protected async createClient(dhe: DheType): Promise { + try { + const wsUrl = getWsUrl(this.serverUrl); + const client = new dhe.Client(wsUrl); + + await new Promise(resolve => + this.subscriptions.push( + client.addEventListener(dhe.Client.EVENT_CONNECT, resolve) + ) + ); + + return client; + } catch (err) { + logger.error(err); + throw err; + } + } + + protected createSession( + dhe: DheType, + client: EnterpriseClient + ): Promise> { + throw new Error('Method not implemented.'); + } + + protected getPanelHtml(title: string): string { + throw new Error('Method not implemented.'); + } + + protected handlePanelMessage( + message: { id: string; message: string }, + postResponseMessage: (response: unknown) => void + ): Promise { + throw new Error('Method not implemented.'); + } +}