-
Notifications
You must be signed in to change notification settings - Fork 567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add typescript declarations formats #557
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}); | ||
}); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}); | ||
}); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -358,6 +358,126 @@ module.exports = { | |
}).join('\n'); | ||
}, | ||
|
||
// TypeScript 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" | ||
* } | ||
* ] | ||
* } | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @memberof Formats | ||
* @kind member | ||
* @example | ||
* ```typescript | ||
* 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": { | ||
* "ts": { | ||
* "transformGroup": "js", | ||
* "files": [ | ||
* { | ||
* "format": "javascript/module", | ||
* "destination": "colors.js" | ||
* }, | ||
* { | ||
* "format": "typescript/module-declarations", | ||
* "destination": "colors.d.ts" | ||
* } | ||
* ] | ||
* } | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @memberof Formats | ||
* @kind member | ||
* @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 | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* 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) { | ||
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' + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry @Tiamanti, one more question for you... The DesignToken interface and the Prop interface are fairly similar - minus optional fields. Is there a way to tie these together somehow so that we use a single source of truth? Or combine them? If we decide to change the structure later by adding additional metadata properties, it would be nice to only have one place to fix. I apologize again if my TypeScript naivety is showing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Tiamanti did you have thoughts here? We will likely do another release candidate of 3.0 here shortly - and it might be the last one. Would love to get this PR in as part of that. Thanks for all your hard work! |
||
'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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not perfect solution but will work for most cases.
I'm currently working on way to optimise this without bringing third party libraries like json-to-ts.