Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
448f5a8
Iteration 299: hashArray + Series.items/iteritems + DataFrame.itertuples
github-actions[bot] May 2, 2026
ba8b123
ci: trigger checks
github-actions[bot] May 2, 2026
75e479e
fix: resolve lint errors in frame.ts
github-actions[bot] May 2, 2026
586e6d5
ci: trigger checks
github-actions[bot] May 2, 2026
794c75e
fix: update hash_array_itertuples playground to conform to standard s…
github-actions[bot] May 2, 2026
5e0d0f4
ci: trigger checks
github-actions[bot] May 2, 2026
9831d1f
Iteration 300: add pd.Grouper spec object
github-actions[bot] May 2, 2026
881d55d
ci: trigger checks
github-actions[bot] May 2, 2026
c30df86
Iteration 301: add pd.api.indexers (BaseIndexer, FixedForwardWindowIn…
github-actions[bot] May 3, 2026
4d31805
ci: trigger checks
github-actions[bot] May 3, 2026
139ae07
Iteration 302: add Series.map() dict/Series/Map overloads + hashBijec…
github-actions[bot] May 4, 2026
d61ff93
fix: update grouper, series-map, window_indexers playground pages to …
Copilot May 5, 2026
8e19ee7
fix: resolve all CI lint errors (import order, NaN namespace, format,…
Copilot May 6, 2026
1f39dd3
Merge remote-tracking branch 'origin/main' into autoloop/build-tsb-pa…
github-actions[bot] May 8, 2026
6994f59
fix: use DataFrame.fromColumns in hash_array_itertuples playground ce…
github-actions[bot] May 9, 2026
340a213
[Autoloop: build-tsb-pandas-typescript-migration] Iteration 305: Add …
github-actions[bot] May 9, 2026
d4367fe
ci: trigger checks
github-actions[bot] May 9, 2026
c363b1a
fix(options): resolve exactOptionalPropertyTypes and circular type al…
github-actions[bot] May 9, 2026
256cfda
ci: trigger checks
github-actions[bot] May 9, 2026
535bdc1
fix(tests): narrow OptionsProxy type to fix noUncheckedIndexedAccess …
github-actions[bot] May 9, 2026
6d5bac0
ci: trigger checks
github-actions[bot] May 9, 2026
1fba96f
fix(lint): add Bun to javascript.globals in biome.json
github-actions[bot] May 9, 2026
a7b45a7
ci: trigger checks
github-actions[bot] May 9, 2026
973e25a
fix(lint): resolve biome errors in playground-cells test and date_range
github-actions[bot] May 9, 2026
02c25ae
ci: trigger checks
github-actions[bot] May 9, 2026
49dbe6d
fix(ci): resolve lint and E2E test failures
github-actions[bot] May 9, 2026
9574104
ci: trigger checks
github-actions[bot] May 9, 2026
38b61b0
fix: resolve biome lint errors in options.ts and grouper.ts
github-actions[bot] May 9, 2026
4fa782a
ci: trigger checks
github-actions[bot] May 9, 2026
40b4be5
fix(options): resolve biome lint errors and rewrite options.html with…
github-actions[bot] May 9, 2026
84c65b5
ci: trigger checks
github-actions[bot] May 9, 2026
1caeed6
fix(options): use non-null assertion after registry.has() check
github-actions[bot] May 9, 2026
67dd68b
ci: trigger checks
github-actions[bot] May 9, 2026
bd7f310
fix(lint): resolve biome errors in frame, options, pd_api, and window…
github-actions[bot] May 9, 2026
df02927
ci: trigger checks
github-actions[bot] May 9, 2026
77f2440
fix: use bracket notation for index signature properties in frame.ts
github-actions[bot] May 9, 2026
e64d3a4
ci: trigger checks
github-actions[bot] May 9, 2026
2dae9f9
fix: resolve biome formatting and import sort errors
github-actions[bot] May 9, 2026
4374850
ci: trigger checks
github-actions[bot] May 9, 2026
1a11528
fix: isListLike returns true for strings (matches pandas semantics)
github-actions[bot] May 9, 2026
5c7cebd
ci: trigger checks
github-actions[bot] May 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"*.d.ts",
"playground/**/*.js",
"playground/serve.ts",
"benchmarks/**"
"benchmarks/**",
".autoloop/**"
]
},
"formatter": {
Expand Down Expand Up @@ -68,6 +69,7 @@
}
},
"javascript": {
"globals": ["Bun"],
"formatter": {
"quoteStyle": "double",
"trailingCommas": "all",
Expand Down
254 changes: 254 additions & 0 deletions playground/grouper.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tsb — Grouper</title>
<style>
:root {
--bg: #0d1117;
--surface: #161b22;
--border: #30363d;
--text: #e6edf3;
--accent: #58a6ff;
--green: #3fb950;
--orange: #d29922;
--red: #f85149;
--font-mono: "Cascadia Code", "Fira Code", "JetBrains Mono", monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.6;
padding: 2rem;
max-width: 900px;
margin: 0 auto;
}
a { color: var(--accent); }
h1 { color: var(--accent); margin-bottom: 0.5rem; }
h2 { margin-top: 0; margin-bottom: 0.5rem; font-size: 1.25rem; }
p { color: #8b949e; margin-bottom: 1rem; }
code {
font-family: var(--font-mono);
font-size: 0.875em;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 0.3rem;
padding: 0.1rem 0.4rem;
}
.back { margin-bottom: 2rem; display: inline-block; }
.subtitle { margin-bottom: 1.5rem; }

#playground-loading {
position: fixed; inset: 0;
background: rgba(13, 17, 23, 0.92);
display: flex; flex-direction: column;
align-items: center; justify-content: center;
z-index: 1000; gap: 1rem;
}
.spinner {
width: 40px; height: 40px;
border: 3px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#playground-status { color: #8b949e; font-size: 0.95rem; }

.section {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 0.75rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.section p { margin-bottom: 0.75rem; }

.playground-block { margin-top: 0.75rem; }
.playground-header {
display: flex; align-items: center; justify-content: space-between;
background: #1c2128;
border: 1px solid var(--border);
border-bottom: none;
border-radius: 0.5rem 0.5rem 0 0;
padding: 0.4rem 0.75rem;
}
.playground-label {
font-size: 0.75rem; color: #8b949e;
text-transform: uppercase; letter-spacing: 0.05em;
}
.playground-actions { display: flex; gap: 0.5rem; }
.playground-actions button {
background: transparent; color: var(--accent);
border: 1px solid var(--border);
border-radius: 0.35rem;
padding: 0.25rem 0.7rem;
font-size: 0.8rem; cursor: pointer;
font-family: system-ui, sans-serif;
transition: background 0.15s, border-color 0.15s;
}
.playground-actions button:hover:not(:disabled) {
background: rgba(88, 166, 255, 0.1);
border-color: var(--accent);
}
.playground-actions button:disabled { opacity: 0.4; cursor: not-allowed; }
.playground-run { font-weight: 600; }

.playground-editor {
display: block; width: 100%; min-height: 80px;
background: #0d1117; color: var(--text);
border: 1px solid var(--border);
border-top: none; border-bottom: none;
padding: 1rem;
font-family: var(--font-mono);
font-size: 0.875rem; line-height: 1.55;
resize: vertical; outline: none;
tab-size: 2; white-space: pre; overflow-x: auto;
}
.playground-editor:focus {
border-color: var(--accent);
box-shadow: inset 0 0 0 1px var(--accent);
}

.playground-output {
background: #1c2333;
border: 1px solid var(--border);
border-radius: 0 0 0.5rem 0.5rem;
padding: 0.75rem 1rem;
font-family: var(--font-mono);
font-size: 0.85rem; color: #8b949e;
white-space: pre-wrap; min-height: 2rem;
word-break: break-word;
}
.playground-output.active { color: var(--green); border-color: var(--green); }
.playground-output.error { color: var(--red); border-color: var(--red); }
.playground-hint {
font-size: 0.75rem; color: #484f58;
margin-top: 0.35rem; text-align: right;
}

footer {
text-align: center;
padding: 2rem 0;
color: #8b949e;
font-size: 0.85rem;
border-top: 1px solid var(--border);
margin-top: 2rem;
}
</style>
</head>
<body>

<div id="playground-loading">
<div class="spinner"></div>
<div id="playground-status">Initializing playground…</div>
</div>

<a class="back" href="index.html">← Back to roadmap</a>
<h1>pd.Grouper</h1>
<p class="subtitle"><code>Grouper</code> is a specification object that encapsulates groupby parameters — mirrors <a href="https://pandas.pydata.org/docs/reference/api/pandas.Grouper.html"><code>pandas.Grouper</code></a>.</p>

<div class="section">
<h2>1 — Key vs Level grouping</h2>
<p>Create a <code>Grouper</code> for column-key grouping or index-level grouping.</p>
<div class="playground-block">
<div class="playground-header">
<span class="playground-label">TypeScript</span>
<div class="playground-actions">
<button class="playground-run" disabled>▶ Run</button>
<button class="playground-reset">↺ Reset</button>
</div>
</div>
<textarea class="playground-editor" spellcheck="false">import { Grouper, isGrouper } from "tsb";

// Group by a column key
const byDept = new Grouper({ key: "dept" });
console.log(byDept.isKeyGrouper()); // true
console.log(byDept.isLevelGrouper()); // false

// Group by an index level
const byLevel = new Grouper({ level: 0 });
console.log(byLevel.isLevelGrouper()); // true

// Frequency-based (time) grouping
const byMonth = new Grouper({ key: "date", freq: "ME" });
console.log(byMonth.isFreqGrouper()); // true

// isGrouper type-guard
console.log(isGrouper(byDept)); // true
console.log(isGrouper("dept")); // false</textarea>
<div class="playground-output">Click ▶ Run to execute</div>
<div class="playground-hint">Ctrl+Enter to run · Tab to indent</div>
</div>
</div>

<div class="section">
<h2>2 — Options &amp; toString</h2>
<p>Full set of Grouper options: <code>freq</code>, <code>sort</code>, <code>dropna</code>, <code>closed</code>, <code>label</code>.</p>
<div class="playground-block">
<div class="playground-header">
<span class="playground-label">TypeScript</span>
<div class="playground-actions">
<button class="playground-run" disabled>▶ Run</button>
<button class="playground-reset">↺ Reset</button>
</div>
</div>
<textarea class="playground-editor" spellcheck="false">import { Grouper } from "tsb";

const g = new Grouper({
key: "date",
freq: "QS", // quarter-start frequency
sort: true, // sort group keys
dropna: false, // keep NaN group keys
closed: "left", // left-closed bins
label: "left", // label bins with left edge
});

console.log(g.toString());
// Grouper(key="date", freq="QS", sort=true, dropna=false)</textarea>
<div class="playground-output">Click ▶ Run to execute</div>
<div class="playground-hint">Ctrl+Enter to run · Tab to indent</div>
</div>
</div>

<div class="section">
<h2>3 — Usage with groupby</h2>
<p>Use <code>g.key!</code> to pass the key directly to <code>groupby()</code>. Full Grouper integration (freq/level) is a future iteration.</p>
<div class="playground-block">
<div class="playground-header">
<span class="playground-label">TypeScript</span>
<div class="playground-actions">
<button class="playground-run" disabled>▶ Run</button>
<button class="playground-reset">↺ Reset</button>
</div>
</div>
<textarea class="playground-editor" spellcheck="false">import { Grouper, DataFrame } from "tsb";

const df = DataFrame.fromColumns({
dept: ["Engineering", "Engineering", "Marketing"],
salary: [100_000, 120_000, 80_000],
});

const g = new Grouper({ key: "dept", sort: true });

// Use the key directly until full Grouper integration lands:
const result = df.groupby(g.key!).mean();
console.log([...result.col("salary").values]); // [110000, 80000]</textarea>
<div class="playground-output">Click ▶ Run to execute</div>
<div class="playground-hint">Ctrl+Enter to run · Tab to indent</div>
</div>
</div>

<footer>
<p>
<a href="index.html">tsb playground</a> ·
Built by <a href="https://github.com/githubnext/autoloop">Autoloop</a>
</p>
</footer>

<script type="module" src="playground-runtime.js"></script>
</body>
</html>
Loading
Loading