@kernlang/python 3.5.8-canary.210.1.239de0e0 → 3.5.8-canary.212.1.1d9726e6

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.
@@ -9,7 +9,7 @@ import { generateConfig, generateConst, generateError, generateEvent, generateEx
9
9
  // Data layer generators (model, repository, cache, dependency, service, union)
10
10
  import { generatePythonCache, generatePythonDependency, generatePythonModel, generatePythonRepository, generatePythonService, generatePythonUnion, } from './generators/data.js';
11
11
  // Ground layer generators (derive, transform, action, guard, assume, invariant, each, collect, branch, resolve, expect, recover)
12
- import { generateAction, generateAssume, generateBranch, generateClamp, generateCollect, generateDerive, generateEach, generateExpect, generateGuard, generateInvariant, generateObjectMerge, generateRecover, generateResolve, generateTransform, setDispatcher, } from './generators/ground.js';
12
+ import { generateAction, generateAssume, generateBranch, generateClamp, generateCoalesce, generateCollect, generateCount, generateCountBy, generateDerive, generateEach, generateExpect, generateFirstDefined, generateFirstTruthy, generateGroupBy, generateGuard, generateIndexBy, generateInvariant, generateObjectMerge, generateObjectOmit, generateObjectPick, generatePartition, generateRecover, generateResolve, generateTransform, generateUniqueBy, setDispatcher, } from './generators/ground.js';
13
13
  // Infra generators (job, storage, email)
14
14
  import { generatePythonEmail, generatePythonJob, generatePythonStorage } from './generators/infra.js';
15
15
  // Re-export helpers and annotation emitters for external consumers
@@ -17,7 +17,7 @@ export { emitPyLowConfidenceTodo, emitPyReasonAnnotations, firstChild, kids, p }
17
17
  // Re-export individual generators so existing deep imports keep working
18
18
  export { generateConfig, generateConst, generateError, generateEvent, generateFunction, generateImport, generateInterface, generateMachine, generateModule, generateStore, generateTest, generateType, generateUse, } from './generators/core.js';
19
19
  export { formatPythonDefault, generatePythonCache, generatePythonDependency, generatePythonModel, generatePythonRepository, generatePythonService, generatePythonUnion, mapColumnToPython, } from './generators/data.js';
20
- export { generateAction, generateAssume, generateBranch, generateClamp, generateCollect, generateDerive, generateEach, generateExpect, generateGuard, generateInvariant, generateObjectMerge, generateRecover, generateResolve, generateTransform, } from './generators/ground.js';
20
+ export { generateAction, generateAssume, generateBranch, generateClamp, generateCoalesce, generateCollect, generateCount, generateCountBy, generateDerive, generateEach, generateExpect, generateFirstDefined, generateFirstTruthy, generateGroupBy, generateGuard, generateIndexBy, generateInvariant, generateObjectMerge, generateObjectOmit, generateObjectPick, generatePartition, generateRecover, generateResolve, generateTransform, generateUniqueBy, } from './generators/ground.js';
21
21
  export { generatePythonEmail, generatePythonJob, generatePythonStorage, } from './generators/infra.js';
22
22
  /** Generate Python for any core language node. Returns string lines. */
23
23
  export function generatePythonCoreNode(node, options = {}) {
@@ -77,8 +77,18 @@ export function generatePythonCoreNode(node, options = {}) {
77
77
  return generateDerive(node);
78
78
  case 'clamp':
79
79
  return generateClamp(node);
80
+ case 'firstTruthy':
81
+ return generateFirstTruthy(node);
82
+ case 'coalesce':
83
+ return generateCoalesce(node);
84
+ case 'firstDefined':
85
+ return generateFirstDefined(node);
80
86
  case 'objectMerge':
81
87
  return generateObjectMerge(node);
88
+ case 'objectOmit':
89
+ return generateObjectOmit(node);
90
+ case 'objectPick':
91
+ return generateObjectPick(node);
82
92
  case 'transform':
83
93
  return generateTransform(node);
84
94
  case 'action':
@@ -93,6 +103,18 @@ export function generatePythonCoreNode(node, options = {}) {
93
103
  return generateEach(node);
94
104
  case 'collect':
95
105
  return generateCollect(node);
106
+ case 'count':
107
+ return generateCount(node);
108
+ case 'countBy':
109
+ return generateCountBy(node);
110
+ case 'uniqueBy':
111
+ return generateUniqueBy(node);
112
+ case 'groupBy':
113
+ return generateGroupBy(node);
114
+ case 'partition':
115
+ return generatePartition(node);
116
+ case 'indexBy':
117
+ return generateIndexBy(node);
96
118
  case 'branch':
97
119
  return generateBranch(node);
98
120
  case 'resolve':
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-python.js","sourceRoot":"","sources":["../src/codegen-python.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codegen-python.js","sourceRoot":"","sources":["../src/codegen-python.ts"],"names":[],"mappings":"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"}
@@ -43,10 +43,14 @@
43
43
  * needing to rewrite `body.x` → `body["x"]`. The wrapping is internal —
44
44
  * adapters and external callers always see a plain `dict`.
45
45
  */
46
- import { getChildren, getFirstChild, getProps } from '@kernlang/core';
46
+ import { emitStringKeyArray, getChildren, getFirstChild, getProps, parseKeys, parsePortableNonNegativeIntLiteral, parsePortablePathSegments, splitPortableExpressionList, } from '@kernlang/core';
47
47
  import { isUnsupportedJsHandlerBody, unsupportedRawHandlerBody } from '../../fastapi-raw-handler.js';
48
48
  import { derivePathParams, escapePyStr, indentHandler, slugify } from '../../fastapi-utils.js';
49
- import { toSnakeCase } from '../../type-map.js';
49
+ import { emitPythonRoutePluckHelper, emitPythonRouteSortKeyHelper, pythonRouteCompactPredicate, } from '../../portable-collection-emitter.js';
50
+ import { pythonRouteRecordExpr, pythonRouteRecordPickExpr } from '../../portable-object-emitter.js';
51
+ import { emitPythonPredicateHelpers } from '../../portable-predicate-emitter.js';
52
+ import { mapTsTypeToPython, toPythonBindingName, toSnakeCase } from '../../type-map.js';
53
+ import { KERN_JS_OBJECT_HELPERS_PY } from '../expr/helpers.js';
50
54
  import { rewriteExpr } from '../expr/index.js';
51
55
  function indentHoistedDef(def, indent) {
52
56
  return def.split('\n').map((line) => `${indent}${line}`);
@@ -84,6 +88,27 @@ function extractExprCode(val) {
84
88
  function extractCodeOrString(val) {
85
89
  return extractExprCode(val);
86
90
  }
91
+ function pushJsObjectKeyCoercion(lines, indent, keyName) {
92
+ lines.push(`${indent}if ${keyName} is None:`);
93
+ lines.push(`${indent} ${keyName} = "null"`);
94
+ lines.push(`${indent}elif isinstance(${keyName}, bool):`);
95
+ lines.push(`${indent} ${keyName} = "true" if ${keyName} else "false"`);
96
+ lines.push(`${indent}elif isinstance(${keyName}, float):`);
97
+ lines.push(`${indent} if ${keyName} != ${keyName}:`);
98
+ lines.push(`${indent} ${keyName} = "NaN"`);
99
+ lines.push(`${indent} elif ${keyName} == float("inf"):`);
100
+ lines.push(`${indent} ${keyName} = "Infinity"`);
101
+ lines.push(`${indent} elif ${keyName} == float("-inf"):`);
102
+ lines.push(`${indent} ${keyName} = "-Infinity"`);
103
+ lines.push(`${indent} elif ${keyName}.is_integer():`);
104
+ lines.push(`${indent} ${keyName} = str(int(${keyName}))`);
105
+ lines.push(`${indent} else:`);
106
+ lines.push(`${indent} ${keyName} = str(${keyName})`);
107
+ lines.push(`${indent}elif not isinstance(${keyName}, (str, int)):`);
108
+ lines.push(`${indent} raise TypeError("keyed reshape selector must produce a scalar key")`);
109
+ lines.push(`${indent}else:`);
110
+ lines.push(`${indent} ${keyName} = str(${keyName})`);
111
+ }
87
112
  function mapJsDefaultToPython(def) {
88
113
  if (def === undefined || def === null)
89
114
  return 'None';
@@ -301,6 +326,388 @@ function generatePurePythonStmt(child, indent, pathParams, bodyFields, authUser,
301
326
  }
302
327
  break;
303
328
  }
329
+ case 'count': {
330
+ const name = toPythonBindingName(String(p.name || ''), 'count');
331
+ if (!name)
332
+ break;
333
+ const collection = rewriteExprPure(extractCodeOrString(p.in).trim(), indent);
334
+ lines.push(...collection.hoists);
335
+ const item = String(p.item || 'item');
336
+ const where = p.where ? extractCodeOrString(p.where) : undefined;
337
+ const predicateStr = p.predicate ? extractExprCode(p.predicate) || String(p.predicate) : undefined;
338
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
339
+ if (predicateStr && where) {
340
+ throw new Error("count node cannot combine 'where' and 'predicate'");
341
+ }
342
+ if (predicateStr) {
343
+ const predicateExpr = rewriteExprPure(predicateStr, indent);
344
+ lines.push(...predicateExpr.hoists);
345
+ const absentVar = `__KernAbsent_${name}`;
346
+ const getPathVar = `__kern_get_path_${name}`;
347
+ const equalVar = `__kern_equal_${name}`;
348
+ const evalPredVar = `__kern_eval_predicate_${name}`;
349
+ const predicateValueVar = `__kern_predicate_${name}`;
350
+ lines.push(...emitPythonPredicateHelpers(indent, absentVar, getPathVar, equalVar, evalPredVar));
351
+ lines.push(`${indent}${predicateValueVar} = ${predicateExpr.expr}`);
352
+ lines.push(`${indent}${name}${typeAnnotation} = sum(1 for ${item} in ${collection.expr} if ${evalPredVar}(${predicateValueVar}, ${item}))`);
353
+ }
354
+ else if (where) {
355
+ const whereExpr = rewriteExprPure(where, indent);
356
+ lines.push(...whereExpr.hoists);
357
+ lines.push(`${indent}${name}${typeAnnotation} = sum(1 for ${item} in ${collection.expr} if ${whereExpr.expr})`);
358
+ }
359
+ else {
360
+ lines.push(`${indent}${name}${typeAnnotation} = len(${collection.expr})`);
361
+ }
362
+ break;
363
+ }
364
+ case 'filter': {
365
+ const name = toPythonBindingName(String(p.name || ''), 'filter');
366
+ if (!name)
367
+ throw new Error("filter node requires a 'name' prop");
368
+ const inVal = extractCodeOrString(p.in).trim();
369
+ const collection = rewriteExprPure(inVal, indent);
370
+ lines.push(...collection.hoists);
371
+ const where = p.where ? extractExprCode(p.where) : undefined;
372
+ const predicateStr = p.predicate ? extractExprCode(p.predicate) || String(p.predicate) : undefined;
373
+ const item = String(p.item || 'item');
374
+ if (predicateStr && where) {
375
+ throw new Error("filter node cannot combine 'where' and 'predicate'");
376
+ }
377
+ if (predicateStr) {
378
+ const predicateExpr = rewriteExprPure(predicateStr, indent);
379
+ lines.push(...predicateExpr.hoists);
380
+ const absentVar = `__KernAbsent_${name}`;
381
+ const getPathVar = `__kern_get_path_${name}`;
382
+ const equalVar = `__kern_equal_${name}`;
383
+ const evalPredVar = `__kern_eval_predicate_${name}`;
384
+ const predicateValueVar = `__kern_predicate_${name}`;
385
+ lines.push(...emitPythonPredicateHelpers(indent, absentVar, getPathVar, equalVar, evalPredVar));
386
+ lines.push(`${indent}${predicateValueVar} = ${predicateExpr.expr}`);
387
+ lines.push(`${indent}${name} = [${item} for ${item} in ${collection.expr} if ${evalPredVar}(${predicateValueVar}, ${item})]`);
388
+ }
389
+ else if (where) {
390
+ const whereExpr = rewriteExprPure(where, indent);
391
+ lines.push(...whereExpr.hoists);
392
+ lines.push(`${indent}${name} = [${item} for ${item} in ${collection.expr} if ${whereExpr.expr}]`);
393
+ }
394
+ else {
395
+ throw new Error("filter node requires a 'where' or 'predicate' prop");
396
+ }
397
+ break;
398
+ }
399
+ case 'compact': {
400
+ const name = toPythonBindingName(String(p.name || ''), 'compact');
401
+ if (!name)
402
+ throw new Error("compact node requires a 'name' prop");
403
+ const inVal = extractCodeOrString(p.in).trim();
404
+ if (!inVal)
405
+ throw new Error("compact node requires an 'in' prop");
406
+ const item = 'item';
407
+ const collection = rewriteExprPure(inVal, indent);
408
+ lines.push(...collection.hoists);
409
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
410
+ lines.push(`${indent}${name}${typeAnnotation} = [${item} for ${item} in ${collection.expr} if ${pythonRouteCompactPredicate(item)}]`);
411
+ break;
412
+ }
413
+ case 'pluck': {
414
+ const name = toPythonBindingName(String(p.name || ''), 'pluck');
415
+ if (!name)
416
+ throw new Error("pluck node requires a 'name' prop");
417
+ const inVal = extractCodeOrString(p.in).trim();
418
+ if (!inVal)
419
+ throw new Error("pluck node requires an 'in' prop");
420
+ const propVal = extractCodeOrString(p.prop).trim();
421
+ if (!propVal)
422
+ throw new Error("pluck node requires a 'prop' prop");
423
+ const collection = rewriteExprPure(inVal, indent);
424
+ lines.push(...collection.hoists);
425
+ const segments = parsePortablePathSegments(propVal, child, 'prop');
426
+ const pathExpr = emitStringKeyArray(segments);
427
+ const helperName = `__kern_pluck_${name}`;
428
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
429
+ emitPythonRoutePluckHelper(lines, indent, helperName, pathExpr);
430
+ lines.push(`${indent}${name}${typeAnnotation} = [${helperName}(__kern_item) for __kern_item in ${collection.expr}]`);
431
+ break;
432
+ }
433
+ case 'take':
434
+ case 'drop': {
435
+ const kind = child.type;
436
+ const name = toPythonBindingName(String(p.name || ''), kind);
437
+ if (!name)
438
+ throw new Error(`${kind} node requires a 'name' prop`);
439
+ const inVal = extractCodeOrString(p.in).trim();
440
+ if (!inVal)
441
+ throw new Error(`${kind} node requires an 'in' prop`);
442
+ const nVal = extractCodeOrString(p.n).trim();
443
+ if (!nVal)
444
+ throw new Error(`${kind} node requires an 'n' prop`);
445
+ const collection = rewriteExprPure(inVal, indent);
446
+ lines.push(...collection.hoists);
447
+ const n = parsePortableNonNegativeIntLiteral(nVal, child, 'n');
448
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
449
+ const slice = kind === 'take' ? `[:${n}]` : `[${n}:]`;
450
+ lines.push(`${indent}${name}${typeAnnotation} = ${collection.expr}${slice}`);
451
+ break;
452
+ }
453
+ case 'sort': {
454
+ const name = toPythonBindingName(String(p.name || ''), 'sort');
455
+ if (!name)
456
+ throw new Error("sort node requires a 'name' prop");
457
+ const inVal = extractCodeOrString(p.in).trim();
458
+ if (!inVal)
459
+ throw new Error("sort node requires an 'in' prop");
460
+ const collection = rewriteExprPure(inVal, indent);
461
+ lines.push(...collection.hoists);
462
+ const compareSource = extractCodeOrString(p.compare).trim();
463
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
464
+ if (compareSource) {
465
+ const a = toPythonBindingName(String(p.a || 'a'), 'sort a');
466
+ const b = toPythonBindingName(String(p.b || 'b'), 'sort b');
467
+ if (a === b) {
468
+ throw new Error('portable route `sort` comparator operands must use distinct `a=` and `b=` names.');
469
+ }
470
+ const compare = rewriteExprPure(compareSource, indent);
471
+ if (compare.hoists.length > 0) {
472
+ throw new Error('portable route `sort compare=` cannot contain closures or expressions that need hoisted helpers.');
473
+ }
474
+ imports.add('import functools');
475
+ lines.push(`${indent}${name}${typeAnnotation} = sorted(${collection.expr}, key=functools.cmp_to_key(lambda ${a}, ${b}: ${compare.expr}))`);
476
+ }
477
+ else {
478
+ const helperName = `__kern_sort_key_${name}`;
479
+ emitPythonRouteSortKeyHelper(lines, indent, helperName);
480
+ lines.push(`${indent}${name}${typeAnnotation} = sorted(${collection.expr}, key=${helperName})`);
481
+ }
482
+ break;
483
+ }
484
+ case 'objectMerge': {
485
+ const name = toPythonBindingName(String(p.name || ''), 'objectMerge');
486
+ if (!name)
487
+ throw new Error("objectMerge node requires a 'name' prop");
488
+ const rawSources = extractCodeOrString(p.sources).trim();
489
+ if (!rawSources)
490
+ throw new Error("objectMerge node requires a 'sources' prop");
491
+ const sources = splitPortableExpressionList(rawSources, 'objectMerge sources=');
492
+ if (sources.length < 2)
493
+ throw new Error('portable route `objectMerge` requires at least two source expressions.');
494
+ const emitted = [];
495
+ for (const source of sources) {
496
+ if (source.startsWith('...')) {
497
+ throw new Error('portable route `objectMerge` sources must not start with `...`; spreading is implicit.');
498
+ }
499
+ const rewritten = rewriteExprPure(source, indent);
500
+ lines.push(...rewritten.hoists);
501
+ emitted.push(`**${pythonRouteRecordExpr(rewritten.expr)}`);
502
+ }
503
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
504
+ lines.push(`${indent}${name}${typeAnnotation} = {${emitted.join(', ')}}`);
505
+ break;
506
+ }
507
+ case 'objectPick': {
508
+ const name = toPythonBindingName(String(p.name || ''), 'objectPick');
509
+ if (!name)
510
+ throw new Error("objectPick node requires a 'name' prop");
511
+ const inVal = extractCodeOrString(p.in).trim();
512
+ if (!inVal)
513
+ throw new Error("objectPick node requires an 'in' prop");
514
+ const rawKeys = extractCodeOrString(p.keys).trim();
515
+ if (!rawKeys)
516
+ throw new Error("objectPick node requires a 'keys' prop");
517
+ const source = rewriteExprPure(inVal, indent);
518
+ lines.push(...source.hoists);
519
+ const keys = emitStringKeyArray(parseKeys(rawKeys, child, 'objectPick keys='));
520
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
521
+ lines.push(`${indent}${name}${typeAnnotation} = ${pythonRouteRecordPickExpr(source.expr, keys)}`);
522
+ break;
523
+ }
524
+ case 'objectOmit': {
525
+ const name = toPythonBindingName(String(p.name || ''), 'objectOmit');
526
+ if (!name)
527
+ throw new Error("objectOmit node requires a 'name' prop");
528
+ const inVal = extractCodeOrString(p.in).trim();
529
+ if (!inVal)
530
+ throw new Error("objectOmit node requires an 'in' prop");
531
+ const rawKeys = extractCodeOrString(p.keys).trim();
532
+ if (!rawKeys)
533
+ throw new Error("objectOmit node requires a 'keys' prop");
534
+ const source = rewriteExprPure(inVal, indent);
535
+ lines.push(...source.hoists);
536
+ const keys = emitStringKeyArray(parseKeys(rawKeys, child, 'objectOmit keys='));
537
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
538
+ lines.push(`${indent}${name}${typeAnnotation} = {key: value for key, value in ${pythonRouteRecordExpr(source.expr)}.items() if key not in ${keys}}`);
539
+ break;
540
+ }
541
+ case 'objectKeys':
542
+ case 'objectValues':
543
+ case 'objectEntries': {
544
+ const nodeType = child.type;
545
+ const name = toPythonBindingName(String(p.name || ''), nodeType);
546
+ if (!name)
547
+ throw new Error(`${nodeType} node requires a 'name' prop`);
548
+ const inVal = extractCodeOrString(p.in).trim();
549
+ if (!inVal)
550
+ throw new Error(`${nodeType} node requires an 'in' prop`);
551
+ const source = rewriteExprPure(inVal, indent);
552
+ lines.push(...source.hoists);
553
+ imports.add(KERN_JS_OBJECT_HELPERS_PY);
554
+ const helper = nodeType === 'objectKeys'
555
+ ? '_kern_js_object_keys'
556
+ : nodeType === 'objectValues'
557
+ ? '_kern_js_object_values'
558
+ : '_kern_js_object_entries';
559
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
560
+ lines.push(`${indent}${name}${typeAnnotation} = ${helper}(${pythonRouteRecordExpr(source.expr)})`);
561
+ break;
562
+ }
563
+ case 'uniqueBy': {
564
+ const name = toPythonBindingName(String(p.name || ''), 'uniqueBy');
565
+ if (!name)
566
+ throw new Error("uniqueBy node requires a 'name' prop");
567
+ const inVal = extractCodeOrString(p.in).trim();
568
+ if (!inVal)
569
+ throw new Error("uniqueBy node requires an 'in' prop");
570
+ const byVal = extractCodeOrString(p.by).trim();
571
+ if (!byVal)
572
+ throw new Error("uniqueBy node requires a 'by' prop");
573
+ const item = String(p.item || 'item');
574
+ const collection = rewriteExprPure(inVal, indent);
575
+ const by = rewriteExprPure(byVal, `${indent} `);
576
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
577
+ const seenName = `__kern_seen_${name}`;
578
+ const seenObjectsName = `__kern_seen_objects_${name}`;
579
+ const keyName = `__kern_key_${name}`;
580
+ const seenKeyName = `__kern_seen_key_${name}`;
581
+ const seenObjectName = `__kern_seen_object_${name}`;
582
+ lines.push(...collection.hoists);
583
+ lines.push(`${indent}${name}${typeAnnotation} = []`);
584
+ lines.push(`${indent}${seenName} = set()`);
585
+ lines.push(`${indent}${seenObjectsName} = []`);
586
+ lines.push(`${indent}for ${item} in ${collection.expr}:`);
587
+ lines.push(...by.hoists);
588
+ lines.push(`${indent} ${keyName} = ${by.expr}`);
589
+ lines.push(`${indent} if ${keyName} is None:`);
590
+ lines.push(`${indent} ${seenKeyName} = ("null", None)`);
591
+ lines.push(`${indent} elif isinstance(${keyName}, bool):`);
592
+ lines.push(`${indent} ${seenKeyName} = ("boolean", ${keyName})`);
593
+ lines.push(`${indent} elif isinstance(${keyName}, float) and ${keyName} != ${keyName}:`);
594
+ lines.push(`${indent} ${seenKeyName} = ("number", "NaN")`);
595
+ lines.push(`${indent} elif isinstance(${keyName}, (int, float)):`);
596
+ lines.push(`${indent} ${seenKeyName} = ("number", ${keyName})`);
597
+ lines.push(`${indent} elif isinstance(${keyName}, str):`);
598
+ lines.push(`${indent} ${seenKeyName} = ("string", ${keyName})`);
599
+ lines.push(`${indent} else:`);
600
+ lines.push(`${indent} for ${seenObjectName} in ${seenObjectsName}:`);
601
+ lines.push(`${indent} if ${keyName} is ${seenObjectName}:`);
602
+ lines.push(`${indent} break`);
603
+ lines.push(`${indent} else:`);
604
+ lines.push(`${indent} ${seenObjectsName}.append(${keyName})`);
605
+ lines.push(`${indent} ${name}.append(${item})`);
606
+ lines.push(`${indent} continue`);
607
+ lines.push(`${indent} if ${seenKeyName} not in ${seenName}:`);
608
+ lines.push(`${indent} ${seenName}.add(${seenKeyName})`);
609
+ lines.push(`${indent} ${name}.append(${item})`);
610
+ break;
611
+ }
612
+ case 'groupBy': {
613
+ const name = toSnakeCase(String(p.name || ''));
614
+ if (!name)
615
+ throw new Error("groupBy node requires a 'name' prop");
616
+ const inVal = extractCodeOrString(p.in).trim();
617
+ if (!inVal)
618
+ throw new Error("groupBy node requires an 'in' prop");
619
+ const byVal = extractCodeOrString(p.by).trim();
620
+ if (!byVal)
621
+ throw new Error("groupBy node requires a 'by' prop");
622
+ const item = String(p.item || 'item');
623
+ const collection = rewriteExprPure(inVal, indent);
624
+ const by = rewriteExprPure(byVal, `${indent} `);
625
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
626
+ const keyName = `__kern_key_${name}`;
627
+ lines.push(...collection.hoists);
628
+ lines.push(`${indent}${name}${typeAnnotation} = {}`);
629
+ lines.push(`${indent}for ${item} in ${collection.expr}:`);
630
+ lines.push(...by.hoists);
631
+ lines.push(`${indent} ${keyName} = ${by.expr}`);
632
+ pushJsObjectKeyCoercion(lines, `${indent} `, keyName);
633
+ lines.push(`${indent} ${name}.setdefault(${keyName}, []).append(${item})`);
634
+ break;
635
+ }
636
+ case 'partition': {
637
+ const passName = toPythonBindingName(String(p.pass || ''), 'partition');
638
+ const failName = toPythonBindingName(String(p.fail || ''), 'partition');
639
+ if (!passName || !failName)
640
+ throw new Error("partition node requires 'pass' and 'fail' props");
641
+ const inVal = extractCodeOrString(p.in).trim();
642
+ if (!inVal)
643
+ throw new Error("partition node requires an 'in' prop");
644
+ const whereVal = extractCodeOrString(p.where).trim();
645
+ if (!whereVal)
646
+ throw new Error("partition node requires a 'where' prop");
647
+ const item = String(p.item || 'item');
648
+ const collection = rewriteExprPure(inVal, indent);
649
+ const where = rewriteExprPure(whereVal, `${indent} `);
650
+ const elemType = p.type ? mapTsTypeToPython(String(p.type)) : undefined;
651
+ const typeAnnotation = elemType ? `: list[${elemType}]` : '';
652
+ lines.push(...collection.hoists);
653
+ lines.push(`${indent}${passName}${typeAnnotation} = []`);
654
+ lines.push(`${indent}${failName}${typeAnnotation} = []`);
655
+ lines.push(`${indent}for ${item} in ${collection.expr}:`);
656
+ lines.push(...where.hoists);
657
+ lines.push(`${indent} if ${where.expr}:`);
658
+ lines.push(`${indent} ${passName}.append(${item})`);
659
+ lines.push(`${indent} else:`);
660
+ lines.push(`${indent} ${failName}.append(${item})`);
661
+ break;
662
+ }
663
+ case 'indexBy': {
664
+ const name = toPythonBindingName(String(p.name || ''), 'indexBy');
665
+ if (!name)
666
+ throw new Error("indexBy node requires a 'name' prop");
667
+ const inVal = extractCodeOrString(p.in).trim();
668
+ if (!inVal)
669
+ throw new Error("indexBy node requires an 'in' prop");
670
+ const byVal = extractCodeOrString(p.by).trim();
671
+ if (!byVal)
672
+ throw new Error("indexBy node requires a 'by' prop");
673
+ const item = String(p.item || 'item');
674
+ const collection = rewriteExprPure(inVal, indent);
675
+ const by = rewriteExprPure(byVal, `${indent} `);
676
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
677
+ const keyName = `__kern_key_${name}`;
678
+ lines.push(...collection.hoists);
679
+ lines.push(`${indent}${name}${typeAnnotation} = {}`);
680
+ lines.push(`${indent}for ${item} in ${collection.expr}:`);
681
+ lines.push(...by.hoists);
682
+ lines.push(`${indent} ${keyName} = ${by.expr}`);
683
+ pushJsObjectKeyCoercion(lines, `${indent} `, keyName);
684
+ lines.push(`${indent} ${name}[${keyName}] = ${item}`);
685
+ break;
686
+ }
687
+ case 'countBy': {
688
+ const name = toPythonBindingName(String(p.name || ''), 'countBy');
689
+ if (!name)
690
+ throw new Error("countBy node requires a 'name' prop");
691
+ const inVal = extractCodeOrString(p.in).trim();
692
+ if (!inVal)
693
+ throw new Error("countBy node requires an 'in' prop");
694
+ const byVal = extractCodeOrString(p.by).trim();
695
+ if (!byVal)
696
+ throw new Error("countBy node requires a 'by' prop");
697
+ const item = String(p.item || 'item');
698
+ const collection = rewriteExprPure(inVal, indent);
699
+ const by = rewriteExprPure(byVal, `${indent} `);
700
+ const typeAnnotation = p.type ? `: ${mapTsTypeToPython(String(p.type))}` : '';
701
+ const keyName = `__kern_key_${name}`;
702
+ lines.push(...collection.hoists);
703
+ lines.push(`${indent}${name}${typeAnnotation} = {}`);
704
+ lines.push(`${indent}for ${item} in ${collection.expr}:`);
705
+ lines.push(...by.hoists);
706
+ lines.push(`${indent} ${keyName} = ${by.expr}`);
707
+ pushJsObjectKeyCoercion(lines, `${indent} `, keyName);
708
+ lines.push(`${indent} ${name}[${keyName}] = ${name}.get(${keyName}, 0) + 1`);
709
+ break;
710
+ }
304
711
  case 'effect': {
305
712
  const effectName = toSnakeCase(String(p.name || 'effect'));
306
713
  const triggerNode = getFirstChild(child, 'trigger');
@@ -425,11 +832,29 @@ export function emitPureHandlers(serverNode, imports, root) {
425
832
  const PORTABLE_TYPES = new Set([
426
833
  'derive',
427
834
  'guard',
835
+ 'filter',
428
836
  'handler',
429
837
  'respond',
430
838
  'branch',
431
839
  'each',
432
840
  'collect',
841
+ 'count',
842
+ 'compact',
843
+ 'pluck',
844
+ 'take',
845
+ 'drop',
846
+ 'sort',
847
+ 'objectMerge',
848
+ 'objectOmit',
849
+ 'objectPick',
850
+ 'objectKeys',
851
+ 'objectValues',
852
+ 'objectEntries',
853
+ 'uniqueBy',
854
+ 'groupBy',
855
+ 'partition',
856
+ 'indexBy',
857
+ 'countBy',
433
858
  'effect',
434
859
  'assign',
435
860
  'do',