Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Fixed
- `parse()` now strips a leading UTF-8 byte order mark (BOM) before `JSON.parse`, so BOM-prefixed SBOMs (common from Windows tooling and some generators) no longer crash with a cryptic "Unexpected token" error

### Added
- Real devDependencies: `typescript`, `vitest`, `@vitest/coverage-v8`, `typescript-eslint`, `@types/node`
- `src/types.ts` — Full domain model: `SBOM`, `Component`, `CVEEntry`, `ChangeReport`, `VersionChange`, `SBOMFormat`, `ReportFormat`
Expand Down
17 changes: 17 additions & 0 deletions src/__tests__/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,21 @@ describe('parse (JSON string input)', () => {
const sbom = parse(JSON.stringify(cyclonedxFixture));
expect(sbom.components).toHaveLength(2);
});

it('strips a leading UTF-8 BOM before parsing', () => {
// Some SBOM generators / Windows tooling emit BOM-prefixed JSON, which is
// valid on disk but makes a naive JSON.parse throw "Unexpected token".
const withBom = '' + JSON.stringify(cyclonedxFixture);
const sbom = parse(withBom);
expect(sbom.format).toBe('cyclonedx');
expect(sbom.components).toHaveLength(2);
});

it('only strips a BOM at the very start, not elsewhere', () => {
// A BOM appearing inside a string value must be preserved verbatim.
const sbom = parse(
JSON.stringify({ bomFormat: 'CycloneDX', components: [{ name: 'ab' }] }),
);
expect(sbom.components[0].name).toBe('ab');
});
});
6 changes: 5 additions & 1 deletion src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ export function parseSPDX(obj: Record<string, unknown>): SBOM {
* Parse a JSON string or object into an SBOM, auto-detecting format.
*/
export function parse(input: string | Record<string, unknown>): SBOM {
const obj: Record<string, unknown> = typeof input === 'string' ? JSON.parse(input) : input;
// Strip a leading UTF-8 byte order mark (U+FEFF) before parsing. Several SBOM
// generators and Windows text tooling emit BOM-prefixed JSON, which is valid
// on disk but makes JSON.parse throw a cryptic "Unexpected token" error.
const obj: Record<string, unknown> =
typeof input === 'string' ? JSON.parse(input.replace(/^\uFEFF/, '')) : input;
const format = detectFormat(obj);

switch (format) {
Expand Down
Loading