diff --git a/README.md b/README.md index a6a92a5e..f08b806b 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ module.exports = { indent: 2 }, ts: { - // select what kind of types you want to generate (default `['enum', 'constant', 'literalId', 'literalKey']`) + // select what kind of types you want to generate (default `['enum', 'constant', 'charEnum', 'literalId', 'literalKey']`) types: ['constant', 'literalId'], // render the types with `'` instead of `"` (default is `"`) singleQuotes: true diff --git a/src/generators/asset-types/__tests__/__snapshots__/ts.ts.snap b/src/generators/asset-types/__tests__/__snapshots__/ts.ts.snap index 3f501f1e..6eac86c0 100644 --- a/src/generators/asset-types/__tests__/__snapshots__/ts.ts.snap +++ b/src/generators/asset-types/__tests__/__snapshots__/ts.ts.snap @@ -1,5 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`\`TS\` asset generator generates charEnum only 1`] = ` +"export const enum MyIconsSetChars { + Foo = \\"\\\\u10a9\\", + Bar = \\"\\\\u04cf\\", +} +" +`; + exports[`\`TS\` asset generator generates constant only 1`] = ` "export const MY_ICONS_SET_CODEPOINTS: Record = { \\"foo\\": \\"4265\\", @@ -63,6 +71,11 @@ export const MY_ICONS_SET_CODEPOINTS: { [key in MyIconsSet]: string } = { [MyIconsSet.Foo]: '4265', [MyIconsSet.Bar]: '1231', }; + +export const enum MyIconsSetChars { + Foo = '\\\\u10a9', + Bar = '\\\\u04cf', +} " `; @@ -84,6 +97,11 @@ export const MY_ICONS_SET_CODEPOINTS: { [key in MyIconsSet]: string } = { [MyIconsSet.i1234]: \\"undefined\\", [MyIconsSet.i5678]: \\"undefined\\", }; + +export const enum MyIconsSetChars { + i1234 = \\"\\\\u10a9\\", + i5678 = \\"\\\\u04cf\\", +} " `; @@ -109,6 +127,11 @@ export const MY_ICONS_SET_CODEPOINTS: { [key in MyIconsSet]: string } = { [MyIconsSet.i5678ab]: \\"undefined\\", [MyIconsSet.Foo]: \\"4265\\", }; + +export const enum MyIconsSetChars { + Foo = \\"\\\\u10a9\\", + i5678ab = \\"\\\\u04cf\\", +} " `; @@ -130,5 +153,10 @@ export const MY_ICONS_SET_CODEPOINTS: { [key in MyIconsSet]: string } = { [MyIconsSet.Foo]: \\"4265\\", [MyIconsSet.Bar]: \\"1231\\", }; + +export const enum MyIconsSetChars { + Foo = \\"\\\\u10a9\\", + Bar = \\"\\\\u04cf\\", +} " `; diff --git a/src/generators/asset-types/__tests__/ts.ts b/src/generators/asset-types/__tests__/ts.ts index 9ed4198f..ce6c4a8b 100644 --- a/src/generators/asset-types/__tests__/ts.ts +++ b/src/generators/asset-types/__tests__/ts.ts @@ -49,6 +49,12 @@ describe('`TS` asset generator', () => { ); }); + test('correctly charEnum declaration', async () => { + expect(await getCleanGen()).toContain( + 'export const enum MyIconsSetChars { Foo = "\\u10a9", Bar = "\\u04cf", }' + ); + }); + test('correctly codepoints declaration', async () => { expect(await getCleanGen()).toContain( 'export const MY_ICONS_SET_CODEPOINTS: { [key in MyIconsSet]: string }' + @@ -150,6 +156,27 @@ describe('`TS` asset generator', () => { expect(cleanResult).not.toContain('export enum MyIconsSet'); }); + test('generates charEnum only', async () => { + const result = await tsGen.generate( + { + ...mockOptions, + formatOptions: { ts: { types: ['charEnum'] } } + }, + null + ); + const cleanResult = cleanWhiteSpace(result as string); + + expect(result).toMatchSnapshot(); + expect(cleanResult).toContain( + 'export const enum MyIconsSetChars' + ); + + expect(cleanResult).not.toContain( + 'export type MyIconsSetId = | "foo" | "bar";' + ); + expect(cleanResult).not.toContain('export enum MyIconsSet'); + }); + test('prevents enum keys that start with digits', async () => { const result = await tsGen.generate( { @@ -170,6 +197,9 @@ describe('`TS` asset generator', () => { expect(cleanResult).toContain( 'export enum MyIconsSet { i1234 = "1234", i5678 = "5678", }' ); + expect(cleanResult).toContain( + 'export const enum MyIconsSetChars { i1234 = "\\u10a9", i5678 = "\\u04cf", }' + ); }); test('prevents enum keys that start with digits when digits and chars', async () => { @@ -196,5 +226,8 @@ describe('`TS` asset generator', () => { expect(cleanResult).toContain( 'export enum MyIconsSet { i1234asdf = "1234asdf", i5678ab = "5678ab", Foo = "foo", }' ); + expect(cleanResult).toContain( + 'export const enum MyIconsSetChars { Foo = "\\u10a9", i5678ab = "\\u04cf", }' + ); }); }); diff --git a/src/generators/asset-types/ts.ts b/src/generators/asset-types/ts.ts index 48a05afb..fa1f71e5 100644 --- a/src/generators/asset-types/ts.ts +++ b/src/generators/asset-types/ts.ts @@ -1,5 +1,6 @@ import { pascalCase, constantCase } from 'change-case'; import { FontGenerator } from '../../types/generator'; +import { AssetsMap } from '../../utils/assets'; const generateEnumKeys = (assetKeys: string[]): Record => assetKeys @@ -13,6 +14,19 @@ const generateEnumKeys = (assetKeys: string[]): Record => }) .reduce((prev, curr) => Object.assign(prev, curr), {}); +const generateCharEnumKeys = (assets: AssetsMap): Record => + Object.keys(assets) + .map(name => { + const id = assets[name].id; + const enumName = pascalCase(name); + const prefix = enumName.match(/^\d/) ? 'i' : ''; + + return { + [id]: `${prefix}${enumName}` + }; + }) + .reduce((prev, curr) => Object.assign(prev, curr), {}); + const generateEnums = ( enumName: string, enumKeys: { [eKey: string]: string }, @@ -26,6 +40,23 @@ const generateEnums = ( '}\n' ].join('\n'); +const generateCharEnums = ( + charEnumName: string, + enumKeys: { [eKey: string]: string }, + codepoints: Record, + quote = '"' +): string => + [ + `export const enum ${charEnumName} {`, + ...Object.entries(enumKeys).map( + (console.log(enumKeys, codepoints), ([enumValue, enumKey]) => + ` ${enumKey} = ${quote}\\u${codepoints[enumValue] + .toString(16) + .padStart(4, '0')}${quote},` + )), + '}\n' + ].join('\n'); + const generateConstant = ({ codepointsName, enumName, @@ -90,18 +121,26 @@ const generator: FontGenerator = { const generateKind: Record = ( Boolean(ts?.types?.length) ? ts.types - : ['enum', 'constant', 'literalId', 'literalKey'] + : ['enum', 'constant', 'charEnum', 'literalId', 'literalKey'] ) .map(kind => ({ [kind]: true })) .reduce((prev, curr) => Object.assign(prev, curr), {}); const enumName = pascalCase(name); + const charEnumName = `${pascalCase(name)}Chars`; const codepointsName = `${constantCase(name)}_CODEPOINTS`; const literalIdName = `${pascalCase(name)}Id`; const literalKeyName = `${pascalCase(name)}Key`; - const names = { enumName, codepointsName, literalIdName, literalKeyName }; + const names = { + enumName, + charEnumName, + codepointsName, + literalIdName, + literalKeyName + }; const enumKeys = generateEnumKeys(Object.keys(assets)); + const charEnumKeys = generateCharEnumKeys(assets); const stringLiteralId = generateKind.literalId ? generateStringLiterals(literalIdName, Object.keys(enumKeys), quote) @@ -113,6 +152,11 @@ const generator: FontGenerator = { const enums = generateKind.enum ? generateEnums(enumName, enumKeys, quote) : null; + + const charEnums = generateKind.charEnum + ? generateCharEnums(charEnumName, charEnumKeys, codepoints, quote) + : null; + const constant = generateKind.constant ? generateConstant({ ...names, @@ -123,7 +167,7 @@ const generator: FontGenerator = { }) : null; - return [stringLiteralId, stringLiteralKey, enums, constant] + return [stringLiteralId, stringLiteralKey, enums, constant, charEnums] .filter(Boolean) .join('\n'); } diff --git a/src/types/format.ts b/src/types/format.ts index 6438e766..1037ef19 100644 --- a/src/types/format.ts +++ b/src/types/format.ts @@ -15,7 +15,7 @@ interface JsonOptions { } interface TsOptions { - types?: ('enum' | 'constant' | 'literalId' | 'literalKey')[]; + types?: ('enum' | 'constant' | 'charEnum' | 'literalId' | 'literalKey')[]; singleQuotes?: boolean; }