From d2e3dc010c6749f879cc99a477a26cd1961afc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szura?= Date: Thu, 11 Feb 2021 17:01:07 +0100 Subject: [PATCH 1/3] feat(formats): add typescript/es6-declarations formats for .d.ts feat(formats): add typescript/module-declarations formats for .d.ts --- .../formats/__snapshots__/all.test.js.snap | 42 +++++-- .../formats/typeScriptEs6Declarations.test.js | 77 +++++++++++++ .../typeScriptModuleDeclarations.test.js | 64 +++++++++++ lib/common/formats.js | 103 ++++++++++++++++++ 4 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 __tests__/formats/typeScriptEs6Declarations.test.js create mode 100644 __tests__/formats/typeScriptModuleDeclarations.test.js diff --git a/__tests__/formats/__snapshots__/all.test.js.snap b/__tests__/formats/__snapshots__/all.test.js.snap index 2ad9fcf56..91c5b09e7 100644 --- a/__tests__/formats/__snapshots__/all.test.js.snap +++ b/__tests__/formats/__snapshots__/all.test.js.snap @@ -9,7 +9,7 @@ exports[`formats all should match android/colors snapshot 1`] = ` --> #FF0000 - + " `; @@ -22,7 +22,7 @@ exports[`formats all should match android/dimens snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -35,7 +35,7 @@ exports[`formats all should match android/fontDimens snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -48,7 +48,7 @@ exports[`formats all should match android/integers snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -61,7 +61,7 @@ exports[`formats all should match android/resources snapshot 1`] = ` --> #FF0000 - + " `; @@ -74,7 +74,7 @@ exports[`formats all should match android/strings snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -150,7 +150,7 @@ exports[`formats all should match ios/colors.m snapshot 1`] = ` #import \\".h\\" -@implementation +@implementation + (UIColor *)color:()colorEnum{ return [[self values] objectAtIndex:colorEnum]; @@ -252,7 +252,7 @@ exports[`formats all should match ios/singleton.m snapshot 1`] = ` #import \\".h\\" -@implementation +@implementation + (NSDictionary *)getProperty:(NSString *)keyPath { return [[self properties] valueForKeyPath:keyPath]; @@ -357,7 +357,7 @@ exports[`formats all should match ios/strings.m snapshot 1`] = ` NSString * const color_red = #FF0000; -@implementation +@implementation + (NSArray *)values { static NSArray* array; @@ -702,3 +702,27 @@ exports[`formats all should match stylus/variables snapshot 1`] = ` $color_red= #FF0000; // comment" `; + +exports[`formats all should match typescript/es6-declarations snapshot 1`] = ` +"/** + * Do not edit directly + * Generated on Sat, 01 Jan 2000 00:00:00 GMT + */ + +export const color_red : string; // comment" +`; + +exports[`formats all should match typescript/module-declarations snapshot 1`] = ` +"/** + * Do not edit directly + * Generated on Sat, 01 Jan 2000 00:00:00 GMT + */ + +export default tokens; +declare interface DesignToken { value: string; name?: string; path?: string[]; comment?: string; attributes?: any; original?: any; } +declare const tokens: { + \\"color\\": { + \\"red\\": DesignToken + } +}" +`; diff --git a/__tests__/formats/typeScriptEs6Declarations.test.js b/__tests__/formats/typeScriptEs6Declarations.test.js new file mode 100644 index 000000000..dc0e327a6 --- /dev/null +++ b/__tests__/formats/typeScriptEs6Declarations.test.js @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with + * the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +var fs = require('fs-extra'); +var helpers = require('../__helpers'); +var formats = require('../../lib/common/formats'); + +var file = { + "destination": "__output/", + "format": "typescript/es6-declarations", + "filter": { + "attributes": { + "category": "color" + } + } +}; + +var dictionary = { + "allProperties": [{ + "name": "red", + "value": "#EF5350", + "original": { + "value": "#EF5350" + }, + "attributes": { + "category": "color", + "type": "base", + "item": "red", + "subitem": "400" + }, + "path": [ + "color", + "base", + "red", + "400" + ] + }] +}; + +var formatter = formats['typescript/es6-declarations'].bind(file); + +describe('formats', () => { + describe('typescript/es6-declarations', () => { + beforeEach(() => { + helpers.clearOutput(); + }); + + afterEach(() => { + helpers.clearOutput(); + }); + + it('should be a valid TS file', () => { + const declarations = './__tests__/__output/output.d.ts'; + fs.writeFileSync(declarations, formatter(dictionary) ); + + // get all lines that begin with export + const lines = fs.readFileSync(declarations, 'utf-8') + .split('\n') + .filter(l => l.indexOf('export') >= 0); + + // assert that any lines have a string type definition + lines.forEach(l => { + expect(l.match(/^export.* : string;$/g).length).toEqual(1); + }); + }); + }); + +}); diff --git a/__tests__/formats/typeScriptModuleDeclarations.test.js b/__tests__/formats/typeScriptModuleDeclarations.test.js new file mode 100644 index 000000000..ddcf25f50 --- /dev/null +++ b/__tests__/formats/typeScriptModuleDeclarations.test.js @@ -0,0 +1,64 @@ +/* + * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with + * the License. A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +var fs = require('fs-extra'); +var helpers = require('../__helpers'); +var formats = require('../../lib/common/formats'); + +var file = { + "destination": "__output/", + "format": "typescript/module-declarations", + "filter": { + "attributes": { + "category": "color" + } + } +}; + +var dictionary = { + "properties": { + "color": { + "red": {"value": "#FF0000"} + } + } +}; + + +var formatter = formats['typescript/module-declarations'].bind(file); + +describe('formats', () => { + describe('typescript/module-declarations', () => { + beforeEach(() => { + helpers.clearOutput(); + }); + + afterEach(() => { + helpers.clearOutput(); + }); + + it('should be a valid TS file', () => { + const declarations = './__tests__/__output/output-module.d.ts'; + fs.writeFileSync(declarations, formatter(dictionary) ); + + // get all lines that have DesignToken + const lines = fs.readFileSync(declarations, 'utf-8') + .split('\n') + .filter(l => l.indexOf(': DesignToken') >= 0); + + // assert that any lines have a DesignToken type definition + lines.forEach(l => { + expect(l.match(/^.*: DesignToken$/g).length).toEqual(1); + }); + }); + }); + +}); diff --git a/lib/common/formats.js b/lib/common/formats.js index ec8f9d92e..2d6f33652 100644 --- a/lib/common/formats.js +++ b/lib/common/formats.js @@ -358,6 +358,109 @@ module.exports = { }).join('\n'); }, + // TypeScript declarations + /** + * Creates TypeScript declarations for ES6 modules + * + * ```json + * { + * "platforms": { + * "js": { + * "transformGroup": "js", + * "files": [ + * { + * "format": "javascript/es6", + * "destination": "colors.js" + * }, + * { + * "format": "typescript/es6-declarations", + * "destination": "colors.d.ts" + * } + * ] + * } + * } + * } + * ``` + * + * @memberof Formats + * @kind member + * @example + * ```js + * export const ColorBackgroundBase : string; + * export const ColorBackgroundAlt : string; + * ``` + */ + 'typescript/es6-declarations': function(dictionary) { + return fileHeader(this.options) + + dictionary.allProperties.map(function(prop) { + var to_ret_prop = 'export const ' + prop.name + ' : string;'; + if (prop.comment) + to_ret_prop = to_ret_prop.concat(' // ' + prop.comment); + return to_ret_prop; + }).join('\n'); + }, + + /** + * Creates TypeScript declarations for CommonJS module + * + * ```json + * { + * "platforms": { + * "js": { + * "transformGroup": "js", + * "files": [ + * { + * "format": "javascript/module", + * "destination": "colors.js" + * }, + * { + * "format": "typescript/module-declarations", + * "destination": "colors.d.ts" + * } + * ] + * } + * } + * } + * ``` + * + * @memberof Formats + * @kind member + * @example + * ```js + * export default tokens; + * declare interface DesignToken { value: string; name?: string; path?: string[]; comment?: string; attributes?: any; original?: any; } + * declare const tokens: { + * "color": { + * "red": DesignToken + * } + * }" + * ``` + */ + 'typescript/module-declarations': function(dictionary) { + function treeWalker(obj) { + let type = Object.create(null); + let has = Object.prototype.hasOwnProperty.bind(obj); + if (has('value')) { + type = 'DesignToken'; + } else { + for (var k in obj) if (has(k)) { + switch (typeof obj[k]) { + case 'object': + type[k] = treeWalker(obj[k]); + } + } + } + return type; + } + + var file = fileHeader(this.options) + + 'export default tokens;\n' + + 'declare interface DesignToken { value: string; name?: string; path?: string[]; comment?: string; attributes?: any; original?: any; }\n' + + 'declare const tokens: ' + + JSON.stringify(treeWalker(dictionary.properties), null, 2); + return file.replace(/"DesignToken"/g,'DesignToken'); + }, + // Android templates /** * Creates a [resource](https://developer.android.com/guide/topics/resources/providing-resources) xml file. It is recommended to use a filter with this format From 1e4757a99b51e0a412f018ba12abfa74cc742d9e Mon Sep 17 00:00:00 2001 From: Michal Szura Date: Sun, 7 Mar 2021 20:02:31 +0100 Subject: [PATCH 2/3] docs(formats): add typescript/es6-declarations docs docs(formats): add typescript/module-declarations docs --- .../formats/__snapshots__/all.test.js.snap | 18 ++--- docs/formats.md | 71 +++++++++++++++++++ lib/common/formats.js | 10 +-- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/__tests__/formats/__snapshots__/all.test.js.snap b/__tests__/formats/__snapshots__/all.test.js.snap index 91c5b09e7..e3981fb6b 100644 --- a/__tests__/formats/__snapshots__/all.test.js.snap +++ b/__tests__/formats/__snapshots__/all.test.js.snap @@ -9,7 +9,7 @@ exports[`formats all should match android/colors snapshot 1`] = ` --> #FF0000 - + " `; @@ -22,7 +22,7 @@ exports[`formats all should match android/dimens snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -35,7 +35,7 @@ exports[`formats all should match android/fontDimens snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -48,7 +48,7 @@ exports[`formats all should match android/integers snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -61,7 +61,7 @@ exports[`formats all should match android/resources snapshot 1`] = ` --> #FF0000 - + " `; @@ -74,7 +74,7 @@ exports[`formats all should match android/strings snapshot 1`] = ` Generated on Sat, 01 Jan 2000 00:00:00 GMT --> - + " `; @@ -150,7 +150,7 @@ exports[`formats all should match ios/colors.m snapshot 1`] = ` #import \\".h\\" -@implementation +@implementation + (UIColor *)color:()colorEnum{ return [[self values] objectAtIndex:colorEnum]; @@ -252,7 +252,7 @@ exports[`formats all should match ios/singleton.m snapshot 1`] = ` #import \\".h\\" -@implementation +@implementation + (NSDictionary *)getProperty:(NSString *)keyPath { return [[self properties] valueForKeyPath:keyPath]; @@ -357,7 +357,7 @@ exports[`formats all should match ios/strings.m snapshot 1`] = ` NSString * const color_red = #FF0000; -@implementation +@implementation + (NSArray *)values { static NSArray* array; diff --git a/docs/formats.md b/docs/formats.md index 3f61b2375..2b605e648 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -772,6 +772,77 @@ export const ColorBackgroundAlt = '#fcfcfcfc'; * * * +### typescript/es6-declarations + + +Creates TypeScript declarations for ES6 modules + +```json +{ + "platforms": { + "ts": { + "transformGroup": "js", + "files": [ + { + "format": "javascript/es6", + "destination": "colors.js" + }, + { + "format": "typescript/es6-declarations", + "destination": "colors.d.ts" + } + ] + } + } +} +``` + +**Example** +```typescript +export const ColorBackgroundBase : string; +export const ColorBackgroundAlt : string; +``` + +* * * + +### typescript/module-declarations + + +Creates TypeScript declarations for CommonJS module + +```json +{ + "platforms": { + "ts": { + "transformGroup": "js", + "files": [ + { + "format": "javascript/module", + "destination": "colors.js" + }, + { + "format": "typescript/module-declarations", + "destination": "colors.d.ts" + } + ] + } + } +} +``` + +**Example** +```typescript +export default tokens; +declare interface DesignToken { value: string; name?: string; path?: string[]; comment?: string; attributes?: any; original?: any; } +declare const tokens: { + "color": { + "red": DesignToken + } +} +``` + +* * * + ### android/resources diff --git a/lib/common/formats.js b/lib/common/formats.js index 2d6f33652..c9130ecfa 100644 --- a/lib/common/formats.js +++ b/lib/common/formats.js @@ -365,7 +365,7 @@ module.exports = { * ```json * { * "platforms": { - * "js": { + * "ts": { * "transformGroup": "js", * "files": [ * { @@ -385,7 +385,7 @@ module.exports = { * @memberof Formats * @kind member * @example - * ```js + * ```typescript * export const ColorBackgroundBase : string; * export const ColorBackgroundAlt : string; * ``` @@ -406,7 +406,7 @@ module.exports = { * ```json * { * "platforms": { - * "js": { + * "ts": { * "transformGroup": "js", * "files": [ * { @@ -426,14 +426,14 @@ module.exports = { * @memberof Formats * @kind member * @example - * ```js + * ```typescript * export default tokens; * declare interface DesignToken { value: string; name?: string; path?: string[]; comment?: string; attributes?: any; original?: any; } * declare const tokens: { * "color": { * "red": DesignToken * } - * }" + * } * ``` */ 'typescript/module-declarations': function(dictionary) { From 2f08fc387b6f58d038a9a52b292d9d694cafb007 Mon Sep 17 00:00:00 2001 From: Michal Szura Date: Sun, 7 Mar 2021 21:17:33 +0100 Subject: [PATCH 3/3] docs(formats): Add note about accurate typescript generation --- docs/formats.md | 17 +++++++++++++++++ lib/common/formats.js | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/docs/formats.md b/docs/formats.md index 2b605e648..cc3f99ccc 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -841,6 +841,23 @@ declare const tokens: { } ``` +As you can see above example output this does not generate 100% accurate d.ts. +This is a compromise between of what style-dictionary can do to help and not bloating the library with rarely used dependencies. + +Thankfully you can extend style-dictionary very easily: + +```js +const JsonToTS = require('json-to-ts'); +StyleDictionaryPackage.registerFormat({ + name: 'typescript/accurate-module-declarations', + formatter: function(dictionary) { + return 'declare const root: RootObject\n' + + 'export default root\n' + + JsonToTS(dictionary.properties).join('\n'); + }, +}); +``` + * * * ### android/resources diff --git a/lib/common/formats.js b/lib/common/formats.js index c9130ecfa..51826c946 100644 --- a/lib/common/formats.js +++ b/lib/common/formats.js @@ -435,6 +435,23 @@ module.exports = { * } * } * ``` + * + * As you can see above example output this does not generate 100% accurate d.ts. + * This is a compromise between of what style-dictionary can do to help and not bloating the library with rarely used dependencies. + * + * Thankfully you can extend style-dictionary very easily: + * + * ```js + * const JsonToTS = require('json-to-ts'); + * StyleDictionaryPackage.registerFormat({ + * name: 'typescript/accurate-module-declarations', + * formatter: function(dictionary) { + * return 'declare const root: RootObject\n' + + * 'export default root\n' + + * JsonToTS(dictionary.properties).join('\n'); + * }, + * }); + * ``` */ 'typescript/module-declarations': function(dictionary) { function treeWalker(obj) {