mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Format entire codebase with Prettier (mechanical, no behavior change)
This commit is contained in:
@@ -13,7 +13,7 @@ flow, the detail panel) calls into this module; nothing here reaches back out.
|
||||
|
||||
## 1. Why infer types at all
|
||||
|
||||
A dataset is just rows of values. The UI wants to *describe* it without
|
||||
A dataset is just rows of values. The UI wants to _describe_ it without
|
||||
re-parsing the payload every time: how many rows and columns, what the columns
|
||||
are called, and roughly what each column contains. The inferred type drives the
|
||||
small type indicator next to each column name in the dataset detail panel and
|
||||
@@ -50,7 +50,7 @@ Given the values of a single column, decide its type.
|
||||
entirely empty, or there are zero rows), default to `string`. There is no
|
||||
evidence for any other type.
|
||||
3. **Run the type checks in precedence order.** For each candidate type, ask:
|
||||
*does **every** surviving value match this type?* The first candidate for
|
||||
_does **every** surviving value match this type?_ The first candidate for
|
||||
which the answer is yes wins. This is the **"all values match → that type,
|
||||
else fall back"** rule: one stray value that doesn't fit knocks the column
|
||||
down to the next candidate, and ultimately to `string`.
|
||||
@@ -62,7 +62,7 @@ overlap, and we want the most specific interpretation that fits.
|
||||
|
||||
1. **boolean** first. The strings `"true"`/`"false"` are not numbers and not
|
||||
dates, so booleans never collide with the other checks — but putting them
|
||||
first keeps a `0`/`1`-free true/false column out of `string`. (We do *not*
|
||||
first keeps a `0`/`1`-free true/false column out of `string`. (We do _not_
|
||||
treat `0`/`1` as boolean; that's a number column.)
|
||||
2. **number** second. `Number("2024")` is a perfectly good number, so a column
|
||||
of bare years would read as `number` — which is the honest answer. Numbers
|
||||
@@ -82,7 +82,7 @@ overlap, and we want the most specific interpretation that fits.
|
||||
whitespace so `Number("") === 0` doesn't sneak through.
|
||||
- **boolean**: native `boolean` values pass; otherwise the trimmed,
|
||||
lower-cased string must be exactly `"true"` or `"false"`.
|
||||
- **date**: guard *before* parsing. Require the trimmed value to look
|
||||
- **date**: guard _before_ parsing. Require the trimmed value to look
|
||||
date-shaped (a leading `YYYY-MM-DD` or `YYYY/MM/DD`, or `M/D/YYYY`) **and**
|
||||
then confirm `Date.parse` returns a finite timestamp. The shape guard is
|
||||
essential: `Date.parse` will happily accept `"42"` or `"March"` on some
|
||||
@@ -155,7 +155,7 @@ export function inferColumnType(values: readonly unknown[]): ColumnType {
|
||||
- **Do** ignore empty cells before classifying.
|
||||
- **Do** keep the precedence boolean → number → date → string.
|
||||
- **Do** guard date detection with a shape regex before trusting `Date.parse`.
|
||||
- **Don't** classify a column unless *every* present value matches — one
|
||||
- **Don't** classify a column unless _every_ present value matches — one
|
||||
outlier means `string`.
|
||||
- **Don't** add more types (integer, float, datetime, json). Four, no more.
|
||||
- **Don't** let `Number("")`, `Date.parse("42")`, or `0`/`1` leak into the wrong
|
||||
@@ -169,13 +169,13 @@ A **profile** is the set of derived summary fields stored on a dataset record so
|
||||
the UI can describe it without re-parsing the payload. Per the data model, a
|
||||
profiled dataset carries:
|
||||
|
||||
| Field | Type | Meaning |
|
||||
| ------------- | --------------------------------- | -------------------------------------- |
|
||||
| `rowCount` | `number \| null` | Data rows, or `null` when N/A. |
|
||||
| `columnCount` | `number \| null` | Columns, or `null` when N/A. |
|
||||
| `columns` | `string[]` | Column names, in order. |
|
||||
| `columnTypes` | `Array<{ name; type }>` | Per-column inferred type (see §2). |
|
||||
| `size` | `number` | Approximate payload size in bytes. |
|
||||
| Field | Type | Meaning |
|
||||
| ------------- | ----------------------- | ---------------------------------- |
|
||||
| `rowCount` | `number \| null` | Data rows, or `null` when N/A. |
|
||||
| `columnCount` | `number \| null` | Columns, or `null` when N/A. |
|
||||
| `columns` | `string[]` | Column names, in order. |
|
||||
| `columnTypes` | `Array<{ name; type }>` | Per-column inferred type (see §2). |
|
||||
| `size` | `number` | Approximate payload size in bytes. |
|
||||
|
||||
`null` row/column counts and an empty `columns`/`columnTypes` are how the UI
|
||||
shows **"N/A"** — see §3.2.
|
||||
@@ -274,7 +274,7 @@ export function profileData(
|
||||
}
|
||||
```
|
||||
|
||||
Parsing CSV/TSV text and detecting the payload shape happen *upstream* of
|
||||
Parsing CSV/TSV text and detecting the payload shape happen _upstream_ of
|
||||
`profileData`; this function takes already-parsed rows so it stays pure and
|
||||
trivially testable. The caller passes `null` for URL and non-tabular datasets.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user