All tests pass

This commit is contained in:
Nick Playfair 2025-06-15 19:56:46 +01:00
parent ab46e608ea
commit 0713337744
3 changed files with 97 additions and 75 deletions

2
src/gerber.d.ts vendored
View File

@ -19,5 +19,5 @@ interface Layers {
} }
interface LayerGenerator { interface LayerGenerator {
getLayers(dir: string, layerNames: string[]): Layers[]; getLayers(dir: string, layerNames: string[]): Promise<Layers[]>;
} }

View File

@ -58,7 +58,7 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
* Temporary test method zip file * Temporary test method zip file
*/ */
public testArchive(fileName: string, tmpDir: string): number { public testArchive(fileName: string, tmpDir: string) {
// Check archive exists // Check archive exists
try { try {
if (!existsSync(fileName)) { if (!existsSync(fileName)) {
@ -78,75 +78,81 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
} }
} }
/** //Take in a directory of layer files and return an array of the layers files
* Take in a directory of layer files and return an array of the layers files // public getLayersOld(dir: string, layerNames: string[]): Promise<Layers[]> {
// if (!existsSync(dir)) throw new Error('Layers folder does not exist');
*/ // //Make sure the layer files exist in the folder
// public getLayers(dir: string, layerNames: string[]) { // layerNames.forEach((layerName) => {
// new Promise((resolve, reject) => { // if (!existsSync(path.join(dir, layerName))) {
// // Make sure the directory exists // throw `Missing layer: ${layerName}`;
// if (!existsSync(dir)) {
// return reject(new Error('Layers folder does not exist.'));
// } // }
// // Check that the required layer files exist in source dir
// let layersValid = true;
// layerNames.forEach((layer) => {
// if (!existsSync(path.join(dir, layer))) layersValid = false;
// });
// if (!layersValid) return reject(new Error('Layer not found.'));
// // Construct array of layers that match the supplied filenames array
// const layers = layerNames.map((layerName) => ({
// filename: layerName,
// gerber: createReadStream(path.join(dir, layerName)),
// }));
// return resolve(layers);
// }); // });
//Construct array of layers
// const layers: Layers[] = layerNames.map((layerName) => ({
// filename: layerName,
// gerber: createReadStream(path.join(dir, layerName)),
// }));
// return layers;
// const layerPromise = new Promise<Layers[]>(function (resolve, reject) {
// const layers: Layers[] = layerNames.map((layerName) => ({
// filename: layerName,
// gerber: createReadStream(path.join(dir, layerName)),
// }));
// resolve(layers);
// });
// return layerPromise;
// } // }
public getLayers(dir: string, layerNames: string[]): Layers[] { //Layer promise
if (!existsSync(dir)) throw new Error('Layers folder does not exist'); public getLayers(dir: string, layerNames: string[]): Promise<Layers[]> {
//Check correct number of layers and folder exists
//Make sure the layer files exist in the folder
layerNames.forEach((layerName) => { layerNames.forEach((layerName) => {
if (!existsSync(path.join(dir, layerName))) { if (!existsSync(path.join(dir, layerName))) {
throw `Missing layer: ${layerName}`; throw `Missing layer: ${layerName}`;
} }
}); });
if (!existsSync(dir)) {
//Construct array of layers throw new Error('Folder not there');
const layers: Layers[] = layerNames.map((layerName) => ({ }
filename: layerName, //Return layer promise
gerber: createReadStream(path.join(dir, layerName)), const layersPromise = new Promise<Layers[]>(function (resolve, reject) {
})); const layers: Layers[] = layerNames.map((layerName: string) => ({
return layers; filename: layerName,
gerber: createReadStream(path.join(dir, layerName)),
}));
resolve(layers);
});
return layersPromise;
} }
/** //Clean up the archive folder in the specified directory
* Clean up the archive folder in the specified directory public static cleanupFiles(dir: string): void {
* @param {string} dir Path to a directory to clean up
*/
static cleanupFiles(dir) {
try { try {
const folder = path.join(dir, 'archive'); const folder = path.join(dir, 'archive');
emptyDirSync(folder); emptyDirSync(folder);
} catch (err) { } catch (error: unknown) {
throw new Error(err); if (error instanceof Error) {
console.error(error.message);
}
} }
} }
/** // * Take an archive containing gerber files, config object, temporary dir
* Take an archive containing gerber files, config object, temporary dir // * and output dir and create a PNG image from the gerber in the output dir
* and output dir and create a PNG image from the gerber in the output dir // * @param {string} gerber Path to an archive file containing gerber
* @param {string} gerber Path to an archive file containing gerber // * @returns {Promise.<string>} Promise to return path to image
* @returns {Promise.<string>} Promise to return path to image
*/ public gerberToImage(gerber: string) {
gerberToImage(gerber) {
// Create output dir if it doesn't exist // Create output dir if it doesn't exist
try { try {
// fs.ensureDirSync(this.imgDir, 0o644); ensureDirSync(this.folderConfig.imgDir);
ensureDirSync(this.imgDir); } catch (error) {
} catch (e) { if (error instanceof Error) {
throw new Error(e); console.error(error.message);
}
} }
// Check temp and output dirs exist // Check temp and output dirs exist
@ -154,24 +160,30 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
if (!existsSync(gerber)) { if (!existsSync(gerber)) {
throw Error('Archive does not exist.'); throw Error('Archive does not exist.');
} }
if (!existsSync(this.tmpDir)) { if (!existsSync(this.folderConfig.tmpDir)) {
throw Error('Temporary folder does not exist.'); throw Error('Temporary folder does not exist.');
} }
if (!existsSync(this.imgDir)) { if (!existsSync(this.folderConfig.imgDir)) {
throw Error('Output folder does not exist.'); throw Error('Output folder does not exist.');
} }
} catch (e) { } catch (error) {
throw new Error(e); if (error instanceof Error) {
console.error(error.message);
}
} }
// Set filenames // Set filenames
//Use the filename of the gerber zip to determine the output png filename
const imageName = path.basename(gerber, '.zip'); const imageName = path.basename(gerber, '.zip');
const destFile = `${path.join(this.imgDir, imageName)}.png`; const destFile = `${path.join(this.folderConfig.imgDir, imageName)}.png`;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
ImageGenerator.extractArchive(gerber, this.tmpDir); if (!this.layerNames) {
ImageGenerator.getLayers( throw new Error('You must supply an array of layer names.');
path.join(this.tmpDir, 'archive'), }
this.extractArchive(gerber, this.folderConfig.tmpDir);
this.getLayers(
path.join(this.folderConfig.tmpDir, 'archive'),
this.layerNames, this.layerNames,
) )
.then(pcbStackup) .then(pcbStackup)
@ -184,11 +196,11 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
.toFile(destFile); .toFile(destFile);
}) })
.then(() => { .then(() => {
ImageGenerator.cleanupFiles(this.tmpDir); ImageGenerator.cleanupFiles(this.folderConfig.tmpDir);
resolve(destFile); resolve(destFile);
}) })
.catch((e) => { .catch((e) => {
ImageGenerator.cleanupFiles(this.tmpDir); ImageGenerator.cleanupFiles(this.folderConfig.tmpDir);
reject(new Error(e)); reject(new Error(e));
}); });
}); });
@ -200,27 +212,29 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
* @param {string} gerber Path to an archive file containing gerber * @param {string} gerber Path to an archive file containing gerber
* @returns {Promise.<stream.Readable>} Promise that resolves to a PNG stream * @returns {Promise.<stream.Readable>} Promise that resolves to a PNG stream
*/ */
gerberToStream(gerber) { gerberToStream(gerber: string) {
// Check temp and output dirs exist // Check temp and output dirs exist
try { try {
if (!existsSync(gerber)) { if (!existsSync(gerber)) {
throw Error('Archive does not exist.'); throw Error('Archive does not exist.');
} }
if (!existsSync(this.tmpDir)) { if (!existsSync(this.folderConfig.tmpDir)) {
throw Error('Temporary folder does not exist.'); throw Error('Temporary folder does not exist.');
} }
if (!existsSync(this.imgDir)) { if (!existsSync(this.folderConfig.imgDir)) {
throw Error('Output folder does not exist.'); throw Error('Output folder does not exist.');
} }
} catch (e) { } catch (error) {
throw new Error(e); if (error instanceof Error) {
console.error(error.message);
}
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
ImageGenerator.extractArchive(gerber, this.tmpDir); this.extractArchive(gerber, this.folderConfig.tmpDir);
ImageGenerator.getLayers( this.getLayers(
path.join(this.tmpDir, 'archive'), path.join(this.folderConfig.tmpDir, 'archive'),
this.layerNames, this.layerNames!,
) )
.then(pcbStackup) .then(pcbStackup)
.then((stackup) => { .then((stackup) => {
@ -231,7 +245,7 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
.png({ compressionLevel: this.imgConfig.compLevel }) .png({ compressionLevel: this.imgConfig.compLevel })
.toBuffer() .toBuffer()
.then((buffer) => { .then((buffer) => {
ImageGenerator.cleanupFiles(this.tmpDir); ImageGenerator.cleanupFiles(this.folderConfig.tmpDir);
const stream = new Readable(); const stream = new Readable();
stream.push(buffer); stream.push(buffer);
stream.push(null); stream.push(null);
@ -239,7 +253,7 @@ class ImageGenerator implements ZipExtractor, LayerGenerator {
}); });
}) })
.catch((e) => { .catch((e) => {
ImageGenerator.cleanupFiles(this.tmpDir); ImageGenerator.cleanupFiles(this.folderConfig.tmpDir);
reject(new Error(e)); reject(new Error(e));
}); });
}); });

View File

@ -109,14 +109,21 @@ describe('Passing in', () => {
}); });
}); });
// Testing static methods
//Layer methods //Layer methods
describe('Getting layers', () => { describe('Getting layers', () => {
const imgGen = new ImageGenerator(folderConfig, imgConfig); const imgGen = new ImageGenerator(folderConfig, imgConfig);
test('should return an array of layers', () => { test('should return a promise of array of layers', () => {
expect(imgGen.getLayers(testLayers, layerNames)).toBeInstanceOf(Array); expect(imgGen.getLayers(testLayers, layerNames)).resolves.toBeInstanceOf(
Array,
);
}); });
// test('should return a promise of array of layers', () => {
// return imgGen.getLayers(testLayers, layerNames).then((data) => {
// expect(data).toBeInstanceOf(Array);
// });
// });
test('should throw error if the layers folder is not valid', () => { test('should throw error if the layers folder is not valid', () => {
expect(() => { expect(() => {
imgGen.getLayers('some_invalid_folder', layerNames); imgGen.getLayers('some_invalid_folder', layerNames);
@ -129,6 +136,7 @@ describe('Getting layers', () => {
}).toThrow(); }).toThrow();
}); });
}); });
//Archive methods //Archive methods
describe('When extracting an archive', () => { describe('When extracting an archive', () => {
const imgGen = new ImageGenerator(folderConfig, imgConfig); const imgGen = new ImageGenerator(folderConfig, imgConfig);