Skip to content

Commit

Permalink
Merge pull request #16 from kreuzerk/feature/restructuring
Browse files Browse the repository at this point in the history
chore(structure): restructure library
  • Loading branch information
nivekcode authored Mar 3, 2020
2 parents 1747469 + 86f5944 commit 391d955
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 120 deletions.
13 changes: 12 additions & 1 deletion src/bin/svg-to-ts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
#!/usr/bin/env node
import * as packgeJSON from '../../package.json';
import commander from 'commander';
import { convert, Delimiter } from '../lib/convert';
import { convert } from '../lib/convert';
import { Delimiter } from '../lib/generators/generators';

export interface ConvertionOptions {
delimiter: Delimiter;
typeName: string;
prefix: string;
fileName: string;
interfaceName: string;
srcFiles: string[];
outputDirectory: string;
}

const DEFAULTS = {
fileName: 'my-icons',
Expand Down
115 changes: 22 additions & 93 deletions src/lib/convert.ts
Original file line number Diff line number Diff line change
@@ -1,124 +1,53 @@
import snakeCase from 'lodash.snakecase';
import camelCase from 'lodash.camelcase';
import kebapCase from 'lodash.kebabcase';
import * as prettier from 'prettier/standalone';
import chalk from 'chalk';
import typescriptParser from 'prettier/parser-typescript';
import { Glob } from 'glob';
import * as util from 'util';
import * as path from 'path';
import * as fs from 'fs';

import { svgo } from './svgo';
import { getInterfaceDefinition, getSvgConstant, getTypeDefinition } from './definitions';

const readfile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);
const getFilesFromRegex = util.promisify(Glob);

export interface ConvertionOptions {
delimiter: Delimiter;
typeName: string;
prefix: string;
fileName: string;
interfaceName: string;
srcFiles: string[];
outputDirectory: string;
}
import {
generateInterfaceDefinition,
generateSvgConstant,
generateTypeDefinition,
generateTypeName,
generateVariableName
} from './generators/generators';
import { getFilePathsFromRegex } from './regex-helpers';
import { extractSvgContent, writeIconsFile } from './file-helpers';
import { ConvertionOptions } from '../bin/svg-to-ts';

export enum Delimiter {
CAMEL = 'CAMEL',
KEBAB = 'KEBAB',
SNAKE = 'SNAKE'
}
const typesDelimitor = ' | ';

export const convert = async (convertionOptions: ConvertionOptions): Promise<void> => {
const { typeName, prefix, delimiter, interfaceName, outputDirectory, srcFiles } = convertionOptions;
let svgConstants = '';
let types = getTypeDefinition(convertionOptions.typeName);
let types = generateTypeDefinition(typeName);

try {
const typesDelimitor = ' | ';
const srcFilesRegexExpressions = convertionOptions.srcFiles;
const filePaths: string[] = [];

for (const regex of srcFilesRegexExpressions) {
const directoryFiles = await getFilesFromRegex(regex, {
nodir: true
});
if (directoryFiles.length === 0) {
console.log(chalk.blue.bold('svg-to-ts:'), chalk.yellow(`No matching files for regex: "${regex}"`));
} else {
filePaths.push(...directoryFiles);
}
}

const filePaths = await getFilePathsFromRegex(srcFiles);
for (let i = 0; i < filePaths.length; i++) {
const fileNameWithEnding = path.basename(filePaths[i]);
const [filenameWithoutEnding, extension] = fileNameWithEnding.split('.');

if (extension === 'svg') {
const rawSvg = await extractSvgContent(filePaths[i]);
const optimizedSvg = await svgo.optimize(rawSvg);
const variableName = getVariableName(convertionOptions, filenameWithoutEnding);
const typeName = getTypeName(filenameWithoutEnding, convertionOptions.delimiter);
types += `'${typeName}'${typesDelimitor}`;
svgConstants += getSvgConstant(variableName, convertionOptions.interfaceName, typeName, optimizedSvg.data);
const variableName = generateVariableName(prefix, filenameWithoutEnding);
const typeName = generateTypeName(filenameWithoutEnding, delimiter);
const svgConstant = generateSvgConstant(variableName, interfaceName, typeName, optimizedSvg.data);

svgConstants += svgConstant;
types += i === filePaths.length - 1 ? `'${typeName}';` : `'${typeName}'${typesDelimitor}`;
}
}

if (svgConstants !== '') {
types = types.substring(0, types.length - typesDelimitor.length) + ';';
const fileContent = generateFileContent(svgConstants, types, convertionOptions);
const fileContent = (svgConstants += types += generateInterfaceDefinition(interfaceName, typeName));
await writeIconsFile(convertionOptions, fileContent);
console.log(
chalk.blue.bold('svg-to-ts:'),
chalk.green('Icons file successfully generated under'),
chalk.green.underline(convertionOptions.outputDirectory)
chalk.green.underline(outputDirectory)
);
}
} catch (error) {
console.log(chalk.blue.bold('svg-to-ts:'), chalk.red('Something went wrong', error));
}
};

const getTypeName = (filenameWithoutEnding, delimiter: Delimiter): string => {
if (delimiter === Delimiter.CAMEL) {
return `${camelCase(filenameWithoutEnding)}`;
}
if (delimiter === Delimiter.KEBAB) {
return `${kebapCase(filenameWithoutEnding)}`;
}
return `${snakeCase(filenameWithoutEnding)}`;
};

const generateFileContent = (svgContstants: string, types: string, convertionOptions: ConvertionOptions): string => {
const fileContent = (svgContstants += types += getInterfaceDefinition(
convertionOptions.interfaceName,
convertionOptions.typeName
));
return prettier.format(fileContent, {
parser: 'typescript',
plugins: [typescriptParser],
singleQuote: true
});
};

const writeIconsFile = async (convertionOptions: ConvertionOptions, fileContent: string): Promise<void> => {
if (!fs.existsSync(convertionOptions.outputDirectory)) {
fs.mkdirSync(convertionOptions.outputDirectory);
}
await writeFile(path.join(convertionOptions.outputDirectory, `${convertionOptions.fileName}.ts`), fileContent);
};

const getVariableName = (convertionOptions: ConvertionOptions, filenameWithoutEnding): string => {
return `${convertionOptions.prefix}${capitalize(camelCase(filenameWithoutEnding))}`;
};

const extractSvgContent = async (filePath: string): Promise<string> => {
const fileContentRaw = await readfile(filePath, 'utf-8');
return fileContentRaw.replace(/\r?\n|\r/g, ' ');
};

const capitalize = (value: string): string => {
return value.charAt(0).toUpperCase() + value.slice(1);
};
21 changes: 0 additions & 21 deletions src/lib/definitions.ts

This file was deleted.

33 changes: 33 additions & 0 deletions src/lib/file-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as util from 'util';
import * as fs from 'fs';
import * as path from 'path';
import * as prettier from 'prettier/standalone';
import typescriptParser from 'prettier/parser-typescript';

import { ConvertionOptions } from '../bin/svg-to-ts';

const readfile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

export const extractSvgContent = async (filePath: string): Promise<string> => {
const fileContentRaw = await readfile(filePath, 'utf-8');
return fileContentRaw.replace(/\r?\n|\r/g, ' ');
};

export const writeIconsFile = async (convertionOptions: ConvertionOptions, fileContent: string): Promise<void> => {
const formatedFileContent = formatContent(fileContent);
if (!fs.existsSync(convertionOptions.outputDirectory)) {
fs.mkdirSync(convertionOptions.outputDirectory);
}
await writeFile(
path.join(convertionOptions.outputDirectory, `${convertionOptions.fileName}.ts`),
formatedFileContent
);
};

const formatContent = (fileContent: string) =>
prettier.format(fileContent, {
parser: 'typescript',
plugins: [typescriptParser],
singleQuote: true
});
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { getInterfaceDefinition, getSvgConstant, getTypeDefinition } from './definitions';
import { generateInterfaceDefinition, generateSvgConstant, generateTypeDefinition } from './generators';

describe('Definitions', () => {
describe('Generators', () => {
it('should return the correct interface definition', () => {
const interfaceName = 'TestIcons';
const typeName = 'myAwesomeIcons';
const expectedDefinition = `export interface ${interfaceName}{
name: ${typeName};
data: string;}`;
expect(getInterfaceDefinition(interfaceName, typeName)).toEqual(expectedDefinition);
expect(generateInterfaceDefinition(interfaceName, typeName)).toEqual(expectedDefinition);
});

it('should return the correct type definition', () => {
const typeName = 'awesomeType';
const expectedTypeDefinition = `type ${typeName} = `;
expect(getTypeDefinition(typeName)).toEqual(expectedTypeDefinition);
expect(generateTypeDefinition(typeName)).toEqual(expectedTypeDefinition);
});

it('should return the correct svg constant definition', () => {
Expand All @@ -26,6 +26,6 @@ describe('Definitions', () => {
name: '${filenameWithoutEnding}',
data: '${data}'
};`;
expect(getSvgConstant(variableName, interfaceName, filenameWithoutEnding, data)).toEqual(expectedSVGConstant);
expect(generateSvgConstant(variableName, interfaceName, filenameWithoutEnding, data)).toEqual(expectedSVGConstant);
});
});
49 changes: 49 additions & 0 deletions src/lib/generators/generators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import snakeCase from 'lodash.snakecase';
import camelCase from 'lodash.camelcase';
import kebapCase from 'lodash.kebabcase';

export enum Delimiter {
CAMEL = 'CAMEL',
KEBAB = 'KEBAB',
SNAKE = 'SNAKE'
}

export const generateInterfaceDefinition = (interfaceName: string, typeName: string) => {
return `export interface ${interfaceName}{
name: ${typeName};
data: string;}`;
};

export const generateTypeDefinition = (typeName: string): string => {
return `export type ${typeName} = `;
};

export const generateSvgConstant = (
variableName: string,
interfaceName: string,
filenameWithoutEnding: string,
data: string
): string => {
return `export const ${variableName}: ${interfaceName} = {
name: '${filenameWithoutEnding}',
data: '${data}'
};`;
};

export const generateTypeName = (filenameWithoutEnding, delimiter: Delimiter): string => {
if (delimiter === Delimiter.CAMEL) {
return `${camelCase(filenameWithoutEnding)}`;
}
if (delimiter === Delimiter.KEBAB) {
return `${kebapCase(filenameWithoutEnding)}`;
}
return `${snakeCase(filenameWithoutEnding)}`;
};

export const generateVariableName = (prefix: string, filenameWithoutEnding): string => {
return `${prefix}${capitalize(camelCase(filenameWithoutEnding))}`;
};

const capitalize = (value: string): string => {
return value.charAt(0).toUpperCase() + value.slice(1);
};
22 changes: 22 additions & 0 deletions src/lib/regex-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import chalk from 'chalk';
import * as util from 'util';
import { Glob } from 'glob';

const getFilesFromRegex = util.promisify(Glob);

export const getFilePathsFromRegex = async (srcFiles: string[]) => {
const srcFilesRegexExpressions = srcFiles;
const filePaths: string[] = [];

for (const regex of srcFilesRegexExpressions) {
const directoryFiles = await getFilesFromRegex(regex, {
nodir: true
});
if (directoryFiles.length === 0) {
console.log(chalk.blue.bold('svg-to-ts:'), chalk.yellow(`No matching files for regex: "${regex}"`));
} else {
filePaths.push(...directoryFiles);
}
}
return filePaths;
};

0 comments on commit 391d955

Please sign in to comment.