-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from observerly/feature/header/parseHeadersFro…
…mBlocks feat: add parseHeadersFromBlocks to header module in @observerly/fits
- Loading branch information
Showing
3 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/*****************************************************************************************************************/ | ||
|
||
// @author Michael Roberts <[email protected]> | ||
// @package @observerly/fits | ||
// @license Copyright © 2021-2023 observerly | ||
|
||
/*****************************************************************************************************************/ | ||
|
||
import { describe, expect, it } from 'vitest' | ||
|
||
import type { FITSBlock } from '../../types' | ||
import { parseHeadersFromBlocks } from '../parseHeadersFromBlocks' | ||
|
||
/*****************************************************************************************************************/ | ||
|
||
describe('parseHeadersFromBlocks', () => { | ||
it('should correctly parse standard headers without CONTINUE keys', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'SIMPLE', | ||
value: true, | ||
comment: 'file conforms to FITS standard' | ||
}, | ||
{ | ||
key: 'BITPIX', | ||
value: 16, | ||
comment: 'number of bits per data pixel' | ||
}, | ||
{ | ||
key: 'NAXIS', | ||
value: 2, | ||
comment: 'number of data axes' | ||
} | ||
], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(3) | ||
expect(headersMap.get('SIMPLE')).toEqual({ | ||
key: 'SIMPLE', | ||
value: true, | ||
comment: 'file conforms to FITS standard' | ||
}) | ||
expect(headersMap.get('BITPIX')).toEqual({ | ||
key: 'BITPIX', | ||
value: 16, | ||
comment: 'number of bits per data pixel' | ||
}) | ||
expect(headersMap.get('NAXIS')).toEqual({ | ||
key: 'NAXIS', | ||
value: 2, | ||
comment: 'number of data axes' | ||
}) | ||
}) | ||
|
||
it('should correctly handle CONTINUE keys by appending their values to the previous header', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'COMMENT', | ||
value: 'This is a long comment that spans multiple', | ||
comment: 'initial part' | ||
}, | ||
{ | ||
key: 'CONTINUE', | ||
value: 'lines for better readability.', | ||
comment: 'continued part' | ||
}, | ||
{ | ||
key: 'END', | ||
value: true, | ||
comment: 'end of header' | ||
} | ||
], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(2) | ||
expect(headersMap.get('COMMENT')).toEqual({ | ||
key: 'COMMENT', | ||
value: 'This is a long comment that spans multiple lines for better readability.', | ||
comment: 'initial part' | ||
}) | ||
expect(headersMap.get('END')).toEqual({ key: 'END', value: true, comment: 'end of header' }) | ||
}) | ||
|
||
it('should handle multiple CONTINUE keys sequentially', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'COMMENT', | ||
value: 'First part of the comment', | ||
comment: 'initial' | ||
}, | ||
{ | ||
key: 'CONTINUE', | ||
value: 'second part', | ||
comment: 'continued' | ||
}, | ||
{ | ||
key: 'CONTINUE', | ||
value: 'third part', | ||
comment: 'continued' | ||
}, | ||
{ | ||
key: 'BITPIX', | ||
value: -32, | ||
comment: 'number of bits per data pixel' | ||
} | ||
], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(2) | ||
expect(headersMap.get('COMMENT')).toEqual({ | ||
key: 'COMMENT', | ||
value: 'First part of the comment second part third part', | ||
comment: 'initial' | ||
}) | ||
expect(headersMap.get('BITPIX')).toEqual({ | ||
key: 'BITPIX', | ||
value: -32, | ||
comment: 'number of bits per data pixel' | ||
}) | ||
}) | ||
|
||
it('should return an empty map when no headers are provided', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(0) | ||
}) | ||
|
||
it('should handle multiple blocks with overlapping headers and CONTINUE keys', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'COMMENT', | ||
value: 'Block1 comment part1', | ||
comment: 'initial' | ||
}, | ||
{ | ||
key: 'CONTINUE', | ||
value: 'part2', | ||
comment: 'continued' | ||
} | ||
], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
}, | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'COMMENT', | ||
value: 'Block2 comment part1', | ||
comment: 'initial' | ||
}, | ||
{ | ||
key: 'CONTINUE', | ||
value: 'part2', | ||
comment: 'continued' | ||
} | ||
], | ||
offsetStart: 2880, | ||
offsetEnd: 5760 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(1) | ||
expect(headersMap.get('COMMENT')).toEqual({ | ||
key: 'COMMENT', | ||
value: 'Block2 comment part1 part2', | ||
comment: 'initial' | ||
}) | ||
}) | ||
|
||
it('should ignore CONTINUE keys if there is no previous header', () => { | ||
const blocks: FITSBlock[] = [ | ||
{ | ||
buffer: '...', | ||
headers: [ | ||
{ | ||
key: 'CONTINUE', | ||
value: 'orphaned continue', | ||
comment: 'no previous header' | ||
}, | ||
{ | ||
key: 'BITPIX', | ||
value: 8, | ||
comment: 'number of bits per data pixel' | ||
} | ||
], | ||
offsetStart: 0, | ||
offsetEnd: 2880 | ||
} | ||
] | ||
|
||
const headersMap = parseHeadersFromBlocks(blocks) | ||
|
||
expect(headersMap.size).toBe(1) | ||
expect(headersMap.get('BITPIX')).toEqual({ | ||
key: 'BITPIX', | ||
value: 8, | ||
comment: 'number of bits per data pixel' | ||
}) | ||
// The 'CONTINUE' key should be ignored as there is no previous header | ||
}) | ||
}) | ||
|
||
/*****************************************************************************************************************/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/*****************************************************************************************************************/ | ||
|
||
// @author Michael Roberts <[email protected]> | ||
// @package @observerly/fits | ||
// @license Copyright © 2021-2023 observerly | ||
|
||
/*****************************************************************************************************************/ | ||
|
||
import type { FITSBlock, FITSHeader } from '../types' | ||
|
||
/*****************************************************************************************************************/ | ||
|
||
/** | ||
* | ||
* parseHeadersFromBlocks | ||
* | ||
* @param blocks - Array of FITS blocks to parse headers from | ||
* @returns Map of headers parsed from the blocks | ||
*/ | ||
export const parseHeadersFromBlocks = (blocks: FITSBlock[]): Map<string, FITSHeader> => { | ||
const headers = new Map<string, FITSHeader>() | ||
|
||
// Flatten all headers from blocks into a single array | ||
const headerLines = blocks.flatMap(block => block.headers) | ||
|
||
// Keep track of the previous header for handling 'CONTINUE' keys | ||
let previousHeader: FITSHeader | null = null | ||
|
||
for (const header of headerLines) { | ||
if (header.key !== 'CONTINUE') { | ||
// Add the new header to the map and update the previous header reference | ||
headers.set(header.key, header) | ||
previousHeader = header | ||
} else if (previousHeader) { | ||
// Append 'CONTINUE' values to the previous header's value | ||
previousHeader.value += ` ${header.value}` | ||
} | ||
} | ||
|
||
return headers | ||
} | ||
|
||
/*****************************************************************************************************************/ |