Skip to content

Commit 433d817

Browse files
committed
Add types and refactor our imageFile helpers
* Extracts types to a definition file * Adds TS_NODE_FILES env var to allow ts-node to pick up our definition file
1 parent 8c246b7 commit 433d817

File tree

6 files changed

+60
-55
lines changed

6 files changed

+60
-55
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
"node": "9.4.x"
77
},
88
"scripts": {
9-
"test": "mocha --exit",
9+
"test": "TS_NODE_FILES=true mocha --exit",
1010
"build": "tsc && npm run build:assets",
1111
"build:assets": "cp -r {src,dist}/img",
1212
"dev": "concurrently --kill-others --prefix=name --names=server,eslint --prefix-colors=green,magenta \"npm run dev:server\" \"npm run dev:lint\"",
13-
"dev:server": "onchange -i -k 'src/**/*.ts' -- ts-node test/server.ts",
13+
"dev:server": "TS_NODE_FILES=true onchange -i -k 'src/**/*.ts' -- ts-node test/server.ts",
1414
"dev:lint": "onchange -i -k 'src/**/*.ts' -- tslint -t stylish 'src/**/*.ts'",
1515
"prepublishOnly": "npm run build"
1616
},

src/lib/imageFiles.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,23 @@
11
import fs from 'fs';
22
import path from 'path';
33

4-
const DEFAULT_IMAGE_DIR = path.join(__dirname, '..', 'img');
4+
const IMAGE_DIR = path.join(__dirname, '..', 'img');
55

6-
export const dirFor = (type, imageDir = DEFAULT_IMAGE_DIR) => {
7-
if (type) {
8-
return path.join(imageDir, type);
9-
}
6+
const imageFiles: (path: string) => string[] = p =>
7+
fs.readdirSync(p).filter(fileName => fileName.match(/\.png$/));
108

11-
return imageDir;
12-
};
9+
const imageDir: (type: ImageType) => string = type =>
10+
type ? path.join(IMAGE_DIR, type) : IMAGE_DIR;
1311

14-
export const allNames = (type, imageDir = DEFAULT_IMAGE_DIR) => {
15-
return fs
16-
.readdirSync(dirFor(type, imageDir))
17-
.filter(imageFileName => {
18-
return imageFileName.match(/\.png/);
19-
})
20-
.map(imageFileName => {
21-
return imageFileName.replace(/\.png/, '');
22-
});
23-
};
12+
export const allNames: (type: ImageType) => string[] = type =>
13+
imageFiles(imageDir(type)).map(imageFileName =>
14+
imageFileName.replace(/\.png/, ''),
15+
);
2416

25-
export const allPaths = (type, imageDir = DEFAULT_IMAGE_DIR) => {
26-
const dir = dirFor(type, imageDir);
27-
return allNames(type, imageDir).map(name => path.join(dir, name + '.png'));
17+
export const allPaths: (type: ImageType) => string[] = type => {
18+
const dir = imageDir(type);
19+
return imageFiles(dir).map(file => path.join(dir, file));
2820
};
2921

30-
export const pathFor = (type, fileName, imageDir = DEFAULT_IMAGE_DIR) => {
31-
return path.join(dirFor(type, imageDir), fileName + '.png');
32-
};
22+
export const pathTo: (type: ImageType, name: string) => string = (type, name) =>
23+
path.join(imageDir(type), name + '.png');

src/lib/potato.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ import { sumAndDiff } from './hashingFunctions';
22
import { allPaths } from './imageFiles';
33
import SlotMachine from './slotMachine';
44

5-
export interface FaceParts {
6-
color: string;
7-
eyes: string;
8-
nose: string;
9-
mouth: string;
10-
}
11-
125
const colors = [
136
'#81bef1',
147
'#ad8bf2',
@@ -29,7 +22,7 @@ class Potato {
2922
private mouthMachine = new SlotMachine(allPaths('mouth'), sumAndDiff),
3023
) {}
3124

32-
parts(string): FaceParts {
25+
parts(string): Face {
3326
return {
3427
color: this.colorMachine.pull(string),
3528
eyes: this.eyesMachine.pull(string),

src/routes/index.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import Router from 'express';
22
import uuid from 'uuid';
33

4-
import { allNames, pathFor } from '../lib/imageFiles';
4+
import { allNames, pathTo } from '../lib/imageFiles';
55
import { combine } from '../lib/imager';
66
import potato from '../lib/potato';
77

8-
const partTypes = ['eyes', 'nose', 'mouth'];
8+
const imageTypes: ImageType[] = ['eyes', 'nose', 'mouth'];
99

1010
const router = Router();
1111

@@ -16,13 +16,10 @@ const sendImage = ({ stdout, response }) => {
1616
};
1717

1818
router.get('/list', (req, res) => {
19-
const response = { face: {} };
19+
const face = {};
20+
imageTypes.forEach(type => (face[type] = allNames(type)));
2021

21-
partTypes.forEach(type => {
22-
response.face[type] = allNames(type);
23-
});
24-
25-
return res.set('Content-Type', 'application/json').send(response);
22+
return res.set('Content-Type', 'application/json').send({ face });
2623
});
2724

2825
router.get('/:size?/random', (req, res) => {
@@ -42,22 +39,20 @@ router.get('/:size?/:id', (req, res, next) => {
4239
});
4340

4441
router.get('/face/:eyes/:nose/:mouth/:color/:size?', (req, res, next) => {
45-
const faceParts = { color: '#' + req.params.color };
46-
47-
partTypes.forEach(type => {
48-
const possibleFileNames = allNames(type);
49-
const requestedFileName = req.params[type];
50-
51-
let fileName;
52-
if (possibleFileNames.includes(requestedFileName)) {
53-
fileName = requestedFileName;
54-
} else if (requestedFileName === 'x') {
55-
fileName = '';
56-
} else {
57-
fileName = possibleFileNames[0];
42+
const faceParts = { color: `#${req.params.color}` };
43+
44+
imageTypes.forEach(type => {
45+
const requestedName = req.params[type];
46+
const names = allNames(type);
47+
let name = names[0];
48+
49+
if (names.includes(requestedName)) {
50+
name = requestedName;
51+
} else if (requestedName === 'x') {
52+
name = '';
5853
}
5954

60-
faceParts[type] = pathFor(type, fileName);
55+
faceParts[type] = pathTo(type, name);
6156
});
6257

6358
return combine(faceParts, req.params.size, (err, stdout) =>

src/types/index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type ImageType = 'eyes' | 'nose' | 'mouth';
2+
type FaceParts = ImageType | 'color';
3+
4+
interface Face {
5+
color: string;
6+
eyes: string;
7+
nose: string;
8+
mouth: string;
9+
}

test/lib/imageFiles.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { expect } from 'chai';
2+
3+
import { allNames, allPaths } from '../../src/lib/imageFiles';
4+
5+
describe('allNames', () => {
6+
it('lists all image names of a particular type', () => {
7+
expect(allNames('eyes')).to.include.members(['eyes1', 'eyes2']);
8+
});
9+
});
10+
11+
describe('allPaths', () => {
12+
it('lists all image paths of a particular type', () => {
13+
const [mouthPath] = allPaths('mouth');
14+
15+
expect(mouthPath).to.match(/src\/img\/mouth\/mouth\d+.png/);
16+
});
17+
});

0 commit comments

Comments
 (0)