Skip to content

Handle jsonl - #172

Open
jgindin wants to merge 17 commits into
mainfrom
handle-jsonl
Open

Handle jsonl#172
jgindin wants to merge 17 commits into
mainfrom
handle-jsonl

Conversation

@jgindin

@jgindin jgindin commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Description

Multi-Format Layout Parser (JSON, JSONL, Single-Object)

  • Enhances tryParseJsonArray in utils/json.ts to parse standard JSON arrays ([...]), single JSON objects ({...} → [obj]), and streaming JSON Lines ({...}\n{...}).
  • Updates RawFrame and ChatCleaner to use unified JSONL-tolerant parsing and layout snapshot validation.
  • Adds comprehensive unit tests covering single objects, multi-line JSONL streams, and malformed edge cases.

Pre-launch Checklist

  • I signed the [CLA].
  • I read the [Contributors Guide].
  • I read the [Style Guide].
  • I have added updates to the [CHANGELOG].
  • I updated/added relevant documentation.
  • My code changes (if any) have tests.
  • If my branch is on fork, I have verified that scripts/e2e_test.sh passes.

If you need help, consider asking for advice on the [discussion board].

jgindin added 17 commits August 18, 2026 12:17
Create SafeUrlValidatorService for http/https validation.
Create DomainOriginVerificationService for strict iframe networking validation.
Wire bypassSecurityTrustResourceUrl inside rendered-frame.ts through the rigorous URL validator.
Swap the check in preview-bridge.ts for the strict origin verification.
Fix LLM concurrency in ChatCoordinator submitPrompt.
Fix Monaco model.dispose() in a2ui-composer-monaco-editor.
Inject takeUntilDestroyed in api-key-selector.ts and renderer-selector.ts.
Delete debug/mock-rules/ entirely.
Rip out console.error patch hacks from ChatCoordinator.
Delete obsolete storage key ACTIVE_DRAFT.
…ks into decoupled targets accurately abandoning monolithic arrays globally
…mentations and un-deferred webrtc layout code gracefully
…ngestion

- Implement TrackEventDirective applying declarative tracking boundaries natively.
- Construct FileIngestionService strictly leveraging @angular/cdk/clipboard utilities.
- Construct ShareService cleanly encapsulating clipboard interactions.
- Sweep all active standalone UI components throughout the app, converting default ChangeDetection behavior to ChangeDetectionStrategy.OnPush.
- Strip FileReader native accesses from ChatPanel into the FileIngestionService.
- Swap template tracking to the directive.
- Rip out the legacy shareDesign() bloated component implementation comprehensively.
- Delete deprecated inner test asserts and old inline code.
When a design link is shared and loaded, cleanSharedA2uiUrl removes
the 'a2ui', 'renderer', and 'rendererId' parameters from the window
hash and search parameters using history.replaceState so they do
not linger in the address bar.

Additionally, update StartupResolution to map queryRendererUrl to
its corresponding static or custom renderer configuration and persist
allowed unknown URLs into LocalStorage. Update Settings view to
default to the active renderer selection instead of an unselected
state. Include rendererId alongside renderer in share URL hashes.
Update tryParseJsonArray in shell utils/json.ts to parse:
- Standard JSON arrays ([...])
- Single JSON objects ({...} -> [obj])
- JSON Lines ({...}\n{...} -> [obj1, obj2, ...])

Update RawFrame to use tryParseJsonArray when parsing layout JSON.
Update ChatCleaner to validate layout snapshots using isLayoutArray.
Add unit tests covering JSON Lines, single objects, and edge cases.
@github-actions

Copy link
Copy Markdown
Contributor

⚡ A2UI Composer PR Preview

Your automated preview is successfully live (commit 27b9296):
👉 Launch PR Preview

Note: This environment will be wiped automatically when the PR is merged or closed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the workspace by modularizing several services, including origin verification, payload parsing, error formatting, file ingestion, URL validation, and sharing. It also introduces base classes for selectors, adds event tracking directives, and removes the mock rules debug component. The review feedback focuses on hardening string processing utility methods (such as tryParseJsonArray, parseAndHealJsonLines, and attemptSyntaxHealing) with guard clauses to handle nullish or undefined inputs safely, as well as retaining fallback logic and tests for parsing single JSON objects to ensure backwards compatibility.

Comment on lines 24 to 48
export function tryParseJsonArray(content: string): unknown[] | null {
const trimmed = content.trim();
if (trimmed.length === 0) {
return null;
}

if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
try {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) {
return parsed;
}
} catch (e) {
// Ignore and return null
// Ignore array parse errors
}
} else if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
try {
const parsed = JSON.parse(trimmed);
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
return [parsed];
}
} catch (e) {
// Ignore object parse errors
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

When refactoring or updating parsing/sanitization logic, do not remove existing fallback blocks (such as those supporting single JSON objects instead of arrays) if doing so would alter existing functionality or risk breaking backwards compatibility. Please retain the fallback logic for single JSON objects. Additionally, we should harden this string processing utility method with a guard clause to safely handle nullish or undefined inputs by returning a safe default (null), per our general rules.

export function tryParseJsonArray(content: string | null | undefined): unknown[] | null {
  if (content == null) {
    return null;
  }
  const trimmed = content.trim();
  if (trimmed.length === 0) {
    return null;
  }

  if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
    try {
      const parsed = JSON.parse(trimmed);
      return [parsed];
    } catch (e) {
      return null;
    }
  }

  if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
    try {
      const parsed = JSON.parse(trimmed);
      if (Array.isArray(parsed)) {
        return parsed;
      }
    } catch (e) {
      // Ignore array parse errors
    }
  }
  return null;
}
References
  1. Harden string processing utility methods with guard clauses to safely handle nullish or undefined inputs by returning safe defaults, and ensure corresponding unit tests are added to verify resilience against nullish values.
  2. When refactoring or updating parsing/sanitization logic, do not remove existing fallback blocks (such as those supporting single JSON objects instead of arrays) if doing so would alter existing functionality or risk breaking backwards compatibility.

Comment on lines +31 to +50
export function parseAndHealJsonLines(content: string): ParseResult {
let wasHealed = false;

// Attempt full JSON parsing before line-by-line processing
const parsedArray = tryParseJsonArray(content);
if (parsedArray) {
return {blocks: parsedArray, wasHealed: false};
}

try {
const parsedSingle = JSON.parse(content);
if (Array.isArray(parsedSingle)) {
return {blocks: parsedSingle, wasHealed};
}
if (parsedSingle && typeof parsedSingle === 'object') {
return {blocks: [parsedSingle], wasHealed};
}
} catch {
// Continue to line-by-line healing
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

We should harden this string processing utility method with a guard clause to safely handle nullish or undefined inputs by returning a safe default ({blocks: [], wasHealed: false}), per our general rules.

export function parseAndHealJsonLines(content: string | null | undefined): ParseResult {
  if (content == null) {
    return {blocks: [], wasHealed: false};
  }
  let wasHealed = false;

  // Attempt full JSON parsing before line-by-line processing
  const parsedArray = tryParseJsonArray(content);
  if (parsedArray) {
    return {blocks: parsedArray, wasHealed: false};
  }
References
  1. Harden string processing utility methods with guard clauses to safely handle nullish or undefined inputs by returning safe defaults, and ensure corresponding unit tests are added to verify resilience against nullish values.

Comment on lines +93 to +94
export function attemptSyntaxHealing(line: string): unknown | null {
let patched = line.trim();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Harden this string processing utility method with a guard clause to safely handle nullish or undefined inputs by returning a safe default (null), per our general rules.

Suggested change
export function attemptSyntaxHealing(line: string): unknown | null {
let patched = line.trim();
export function attemptSyntaxHealing(line: string | null | undefined): unknown | null {
if (line == null) {
return null;
}
let patched = line.trim();
References
  1. Harden string processing utility methods with guard clauses to safely handle nullish or undefined inputs by returning safe defaults, and ensure corresponding unit tests are added to verify resilience against nullish values.

Comment on lines +39 to +42
it('parses a single JSON object as a single-element array', () => {
expect(tryParseJsonArray('{"not": "an array"}')).toEqual([{not: 'an array'}]);
expect(tryParseJsonArray(' {"foo": "bar"} ')).toEqual([{foo: 'bar'}]);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since we must not remove existing fallback blocks (such as those supporting single JSON objects instead of arrays) to maintain backwards compatibility, we should keep this test verifying that a single JSON object is parsed successfully instead of expecting null.

Suggested change
it('parses a single JSON object as a single-element array', () => {
expect(tryParseJsonArray('{"not": "an array"}')).toEqual([{not: 'an array'}]);
expect(tryParseJsonArray(' {"foo": "bar"} ')).toEqual([{foo: 'bar'}]);
});
it('returns a single-element array for a single JSON object', () => {
expect(tryParseJsonArray('{"not": "an array"}')).toEqual([{"not": "an array"}]);
expect(tryParseJsonArray(' {"foo": "bar"} ')).toEqual([{"foo": "bar"}]);
});
References
  1. When refactoring or updating parsing/sanitization logic, do not remove existing fallback blocks (such as those supporting single JSON objects instead of arrays) if doing so would alter existing functionality or risk breaking backwards compatibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant