mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Eng-council sweep: export hygiene, dead code, helper dedup, declare vega-expression
This commit is contained in:
@@ -34,8 +34,7 @@ export const MARK_TYPES = ['bar', 'line', 'point', 'area', 'circle'] as const;
|
||||
export type MarkType = (typeof MARK_TYPES)[number];
|
||||
|
||||
/** The four Vega-Lite field types a channel may carry, in override-menu order. */
|
||||
export const FIELD_TYPES = ['quantitative', 'nominal', 'ordinal', 'temporal'] as const;
|
||||
export type FieldType = (typeof FIELD_TYPES)[number];
|
||||
export type FieldType = 'quantitative' | 'nominal' | 'ordinal' | 'temporal';
|
||||
|
||||
/** The four encoding channels the builder offers, in display order (spec §06). */
|
||||
export const CHANNELS = ['x', 'y', 'color', 'size'] as const;
|
||||
@@ -49,8 +48,7 @@ export type ChannelName = (typeof CHANNELS)[number];
|
||||
* reduce a quantitative field; min/max also order a temporal or ordinal one. See
|
||||
* `validAggregateOps` for the per-type menu.
|
||||
*/
|
||||
export const AGGREGATE_OPS = ['count', 'distinct', 'sum', 'mean', 'median', 'min', 'max'] as const;
|
||||
export type AggregateOp = (typeof AGGREGATE_OPS)[number];
|
||||
export type AggregateOp = 'count' | 'distinct' | 'sum' | 'mean' | 'median' | 'min' | 'max';
|
||||
|
||||
/**
|
||||
* Temporal granularities (Vega-Lite `timeUnit`), coarse → fine, with the combined
|
||||
@@ -71,12 +69,10 @@ export const TIME_UNITS = [
|
||||
export type TimeUnit = (typeof TIME_UNITS)[number];
|
||||
|
||||
/** Sort the categorical axis by its measure (spec §06 → Ranking). */
|
||||
export const SORT_ORDERS = ['ascending', 'descending'] as const;
|
||||
export type SortOrder = (typeof SORT_ORDERS)[number];
|
||||
export type SortOrder = 'ascending' | 'descending';
|
||||
|
||||
/** Part-to-whole stacking for bar/area + a colour series: absolute vs 100%. */
|
||||
export const STACK_MODES = ['zero', 'normalize'] as const;
|
||||
export type StackMode = (typeof STACK_MODES)[number];
|
||||
export type StackMode = 'zero' | 'normalize';
|
||||
|
||||
/**
|
||||
* Comparison operators a guarded filter predicate offers (Vega-Lite field
|
||||
@@ -85,17 +81,7 @@ export type StackMode = (typeof STACK_MODES)[number];
|
||||
* `range`; a category offers membership (`oneOf`). `notEqual` is expressed as a
|
||||
* `{ not: { …equal } }` logical wrapper (Vega-Lite has no bare `!=` predicate).
|
||||
*/
|
||||
export const FILTER_OPS = [
|
||||
'equal',
|
||||
'notEqual',
|
||||
'lt',
|
||||
'lte',
|
||||
'gt',
|
||||
'gte',
|
||||
'range',
|
||||
'oneOf',
|
||||
] as const;
|
||||
export type FilterOp = (typeof FILTER_OPS)[number];
|
||||
export type FilterOp = 'equal' | 'notEqual' | 'lt' | 'lte' | 'gt' | 'gte' | 'range' | 'oneOf';
|
||||
|
||||
/** How a filter expresses its predicate: a guarded shelf, or a raw expression. */
|
||||
export type FilterMode = 'predicate' | 'expression';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import {
|
||||
cellText,
|
||||
computeDatasetProfile,
|
||||
CURRENT_DATASET_VERSION,
|
||||
createDataset,
|
||||
@@ -153,6 +154,17 @@ describe('tabularRows', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cellText', () => {
|
||||
test('strings as-is, null/undefined blank, others as JSON (no "[object Object]")', () => {
|
||||
expect(cellText('plain')).toBe('plain');
|
||||
expect(cellText(null)).toBe('');
|
||||
expect(cellText(undefined)).toBe('');
|
||||
expect(cellText(42)).toBe('42');
|
||||
expect(cellText(false)).toBe('false');
|
||||
expect(cellText({ a: 1 })).toBe('{"a":1}');
|
||||
});
|
||||
});
|
||||
|
||||
describe('snapshotFromText', () => {
|
||||
test('JSON content is parsed and typed json (content beats extension)', () => {
|
||||
const { data, format } = snapshotFromText('[{"a":1}]', 'https://x/data.txt');
|
||||
|
||||
@@ -235,6 +235,16 @@ export function tabularRows(
|
||||
return limit != null && limit >= 0 && rows.length > limit ? rows.slice(0, limit) : rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a `tabularRows` cell for a preview table: strings as-is, null/undefined
|
||||
* empty, anything else (numbers, booleans, nested values) as compact JSON.
|
||||
*/
|
||||
export function cellText(value: unknown): string {
|
||||
if (value == null) return '';
|
||||
if (typeof value === 'string') return value;
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orchestrate profiling for a dataset payload: compute `size` (always), decide
|
||||
* tabular vs N/A by format, and delegate to `profileData`. Identical for inline
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* grammar. It also extracts the `datum.<field>` references so the UI can flag a typo
|
||||
* against the dataset's actual columns before the chart silently renders empty.
|
||||
*
|
||||
* `vega-expression` is a pure dependency already in the bundle (Vega pulls it in for
|
||||
* rendering), so importing it here adds nothing and keeps this module browser-free.
|
||||
* `vega-expression` is declared as a direct dependency but adds no bundle weight —
|
||||
* Vega already ships it for rendering; this import reuses the same copy.
|
||||
*/
|
||||
|
||||
import { parseExpression } from 'vega-expression';
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
export type DataFormat = 'json' | 'csv' | 'tsv' | 'topojson';
|
||||
export type DetectionConfidence = 'high' | 'medium' | 'low';
|
||||
type DetectionConfidence = 'high' | 'medium' | 'low';
|
||||
|
||||
export interface FormatDetection {
|
||||
format: DataFormat | null;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import stringify from 'json-stringify-pretty-compact';
|
||||
|
||||
/** Width budget before an array/object wraps onto multiple lines. */
|
||||
export const DEFAULT_MAX_LINE = 80;
|
||||
const DEFAULT_MAX_LINE = 80;
|
||||
|
||||
/** Default indent (spaces) — matches the editor's default tab size (spec §07). */
|
||||
const DEFAULT_INDENT = 2;
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
import { inferColumnType, isEmpty, isNumeric, type ColumnType } from './type-inference';
|
||||
|
||||
export interface ColumnTypeInfo {
|
||||
interface ColumnTypeInfo {
|
||||
/** The column name. */
|
||||
name: string;
|
||||
/** The inferred display type for the column. */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
/** A category of stored data and its measured size in bytes. */
|
||||
export interface StorageSegment {
|
||||
interface StorageSegment {
|
||||
key: 'snippets' | 'datasets' | 'app';
|
||||
/** User-facing label, centralized here so the component stays presentational. */
|
||||
label: string;
|
||||
|
||||
@@ -181,7 +181,7 @@ const PRESET_IDS = [
|
||||
'dark',
|
||||
] as const;
|
||||
|
||||
export type ChartThemePresetId = (typeof PRESET_IDS)[number];
|
||||
type ChartThemePresetId = (typeof PRESET_IDS)[number];
|
||||
|
||||
/** Empty config — the stock sentinel resolves to "inject nothing". */
|
||||
const STOCK_CONFIG: Config = {};
|
||||
|
||||
Reference in New Issue
Block a user