-
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.
refactor: sidecar data into separate function
- Loading branch information
Showing
6 changed files
with
201 additions
and
49 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
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,94 @@ | ||
/** | ||
* Handle "sidecar" data - these are JSON files that sit next to rendered template previews, | ||
* containing metadata about the preview, so that we can re-render them later. | ||
* | ||
* @packageDocumentation | ||
*/ | ||
import fs from "fs/promises"; | ||
import { join } from "path"; | ||
|
||
import { TEMPLATE_ENGINES } from "../engines"; | ||
import { TemplatePreview, TemplatePreviews } from "../engines/types"; | ||
import { stopIfCriticalFsError } from "../util/files"; | ||
import createLogger from "../util/logger"; | ||
import { CliOptions, CSVRecord } from "../util/types"; | ||
import { SidecardData } from "./types"; | ||
|
||
const PARTS_SEPARATOR = "__"; | ||
const logger = createLogger("docsoc.sidecar"); | ||
|
||
/** | ||
* Generate the first part of a filename for a record's previews - this part | ||
* identifies the record itself via the fileNamer function. | ||
* @param record The record to generate a prefix for | ||
* @param fileNamer A function that generates a filename for a record | ||
* @returns | ||
*/ | ||
export const getRecordPreviewPrefix = (record: CSVRecord, fileNamer: (record: CSVRecord) => string) => | ||
`${fileNamer(record)}`; | ||
|
||
/** | ||
* Generate predicable prefixes for preview names (including record specific part | ||
* | ||
* @example | ||
* const record = { id: "1", name: "Test Record" }; | ||
* const fileNamer = (record: CSVRecord) => `file_${record["id"]}`; | ||
* getRecordPreviewPrefixForIndividual(record, fileNamer, "nunjucks", { name: "preview1.txt", content: "content1", metadata: { key: "value" } }) | ||
* // => "file_1__nunjucks__preview1.txt" | ||
*/ | ||
export const getRecordPreviewPrefixForIndividual = ( | ||
record: CSVRecord, | ||
fileNamer: (record: CSVRecord) => string, | ||
templateEngine: string, | ||
preview: TemplatePreview, | ||
) => [getRecordPreviewPrefix(record, fileNamer), templateEngine, preview.name].join(PARTS_SEPARATOR); | ||
|
||
/** | ||
* Generate the filename for the metadata file for a record | ||
* @param record The record to generate a metadata filename for | ||
* @param fileNamer A function that generates a filename for a record | ||
* @example | ||
* const record = { id: "1", name: "Test Record" }; | ||
* const fileNamer = (record: CSVRecord) => `file_${record["id"]}`; | ||
* getRecordPreviewPrefixForMetadata(record, fileNamer) | ||
* // => "file_1-metadata.json" | ||
*/ | ||
export const getRecordPreviewPrefixForMetadata = (record: CSVRecord, fileNamer: (record: CSVRecord) => string) => | ||
`${getRecordPreviewPrefix(record, fileNamer)}-metadata.json`; | ||
|
||
/** | ||
* Write the metadata for a record & its associated previews to a JSON file. | ||
* @param record The record to write metadata for | ||
* @param templateEngine The engine used to render the previews | ||
* @param templateOptions The options given to the engine | ||
* @param previews The previews rendered for the record | ||
* @param fileNamer A function that generates a filename for a record | ||
* @param previewsRoot The root directory to write the metadata to | ||
* @returns | ||
*/ | ||
export async function writeMetadata( | ||
record: CSVRecord, | ||
templateEngine: TEMPLATE_ENGINES, | ||
templateOptions: CliOptions["templateOptions"], | ||
previews: TemplatePreviews, | ||
fileNamer: (record: CSVRecord) => string, | ||
previewsRoot: string, | ||
): Promise<void> { | ||
const sidecar: SidecardData = { | ||
record: record, | ||
engine: templateEngine, | ||
engineOptions: templateOptions, | ||
files: previews.map((preview) => ({ | ||
filename: getRecordPreviewPrefixForIndividual(record, fileNamer, templateEngine, preview), | ||
engineData: { | ||
...preview, | ||
content: undefined, | ||
}, | ||
})), | ||
}; | ||
|
||
const metadataFile = getRecordPreviewPrefixForMetadata(record, fileNamer); | ||
logger.debug(`Writing metadata for ${fileNamer(record)} to ${metadataFile}`); | ||
await stopIfCriticalFsError(fs.writeFile(join(previewsRoot, metadataFile), JSON.stringify(sidecar, null, 4))); | ||
return Promise.resolve(); | ||
} |
File renamed without changes.
26 changes: 0 additions & 26 deletions
26
packages/email/docsoc-mail-merge/src/sideCardData/index.ts
This file was deleted.
Oops, something went wrong.
94 changes: 94 additions & 0 deletions
94
packages/email/docsoc-mail-merge/test/sideCarData/index.ts
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,94 @@ | ||
// index.test.ts | ||
import fs from "fs/promises"; | ||
import { join } from "path"; | ||
|
||
import { TEMPLATE_ENGINES } from "../../src/engines"; | ||
import { TemplatePreviews } from "../../src/engines/types"; | ||
import { | ||
getRecordPreviewPrefix, | ||
getRecordPreviewPrefixForIndividual, | ||
getRecordPreviewPrefixForMetadata, | ||
writeMetadata, | ||
} from "../../src/sideCarData/index"; | ||
import { SidecardData } from "../../src/sideCarData/types"; | ||
import { stopIfCriticalFsError } from "../../src/util/files"; | ||
import { CliOptions, CSVRecord } from "../../src/util/types"; | ||
|
||
jest.mock("fs/promises"); | ||
jest.mock("../../src/util/logger", () => { | ||
const logger = { | ||
info: jest.fn(), | ||
debug: jest.fn(), | ||
warn: jest.fn(), | ||
error: jest.fn(), | ||
}; | ||
return () => logger; | ||
}); | ||
jest.mock("../../src/util/files"); | ||
|
||
describe("Sidecar Data Functions", () => { | ||
const mockRecord: CSVRecord = { id: "1", name: "Test Record" }; | ||
const mockFileNamer = (record: CSVRecord) => `file_${record["id"]}`; | ||
const mockTemplateEngine = "nunjucks" as TEMPLATE_ENGINES; | ||
const mockTemplateOptions: CliOptions["templateOptions"] = {}; | ||
const mockPreviews: TemplatePreviews = [{ name: "preview1", content: "content1", metadata: { key: "value" } }]; | ||
const mockPreviewsRoot = "/mock/previews/root"; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
test("getRecordPreviewPrefix should return correct prefix", () => { | ||
const result = getRecordPreviewPrefix(mockRecord, mockFileNamer); | ||
expect(result).toBe("file_1"); | ||
}); | ||
|
||
test("getRecordPreviewPrefixForIndividual should return correct prefix", () => { | ||
const result = getRecordPreviewPrefixForIndividual( | ||
mockRecord, | ||
mockFileNamer, | ||
mockTemplateEngine, | ||
mockPreviews[0], | ||
); | ||
expect(result).toBe(`file_1__${mockTemplateEngine}__preview1`); | ||
}); | ||
|
||
test("getRecordPreviewPrefixForMetadata should return correct metadata filename", () => { | ||
const result = getRecordPreviewPrefixForMetadata(mockRecord, mockFileNamer); | ||
expect(result).toBe("file_1-metadata.json"); | ||
}); | ||
|
||
test("writeMetadata should write metadata to a JSON file", async () => { | ||
const mockSidecar: SidecardData = { | ||
record: mockRecord, | ||
engine: mockTemplateEngine, | ||
engineOptions: mockTemplateOptions, | ||
files: [ | ||
{ | ||
filename: `file_1__${mockTemplateEngine}__preview1`, | ||
engineData: { | ||
name: "preview1", | ||
content: undefined, | ||
metadata: { key: "value" }, | ||
}, | ||
}, | ||
], | ||
}; | ||
|
||
(stopIfCriticalFsError as jest.Mock).mockImplementation((promise) => promise); | ||
|
||
await writeMetadata( | ||
mockRecord, | ||
mockTemplateEngine, | ||
mockTemplateOptions, | ||
mockPreviews, | ||
mockFileNamer, | ||
mockPreviewsRoot, | ||
); | ||
|
||
expect(fs.writeFile).toHaveBeenCalledWith( | ||
join(mockPreviewsRoot, "file_1-metadata.json"), | ||
JSON.stringify(mockSidecar, null, 4), | ||
); | ||
}); | ||
}); |