From 1481c46647808d95dc26ff6c08a0906df09d0316 Mon Sep 17 00:00:00 2001 From: Danny Banks Date: Fri, 6 Nov 2020 16:43:25 -0800 Subject: [PATCH] feat(formats): add file object to formatter method (#439) --- __tests__/buildFile.test.js | 26 ++++++++++------ __tests__/cleanDir.test.js | 6 ++-- __tests__/cleanFile.test.js | 6 ++-- __tests__/formats/all.test.js | 2 +- __tests__/formats/es6Constants.test.js | 2 +- __tests__/formats/javascriptModule.test.js | 2 +- __tests__/formats/javascriptObject.test.js | 2 +- __tests__/formats/javascriptUmd.test.js | 2 +- __tests__/formats/json.test.js | 2 +- __tests__/formats/jsonFlat.test.js | 2 +- __tests__/formats/jsonNested.test.js | 2 +- __tests__/formats/lessIcons.test.js | 2 +- __tests__/formats/lessVariables.test.js | 2 +- __tests__/formats/scssIcons.test.js | 2 +- __tests__/formats/scssMaps.test.js | 2 +- __tests__/formats/scssVariables.test.js | 2 +- lib/buildFile.js | 12 +++++--- lib/buildFiles.js | 2 +- lib/cleanDir.js | 7 ++--- lib/cleanDirs.js | 2 +- lib/cleanFile.js | 5 ++- lib/cleanFiles.js | 2 +- lib/common/formats.js | 36 +++++++++++----------- 23 files changed, 68 insertions(+), 62 deletions(-) diff --git a/__tests__/buildFile.test.js b/__tests__/buildFile.test.js index 225aa9774..55cdd71f6 100644 --- a/__tests__/buildFile.test.js +++ b/__tests__/buildFile.test.js @@ -32,30 +32,30 @@ describe('buildFile', () => { it('should error if format doesnt exist or isnt a function', () => { expect( - buildFile.bind(null, '__tests__/__output/test.txt', {}, {}, {}) + buildFile.bind(null, {destination: '__tests__/__output/test.txt'}, {}, {}) ).toThrow('Please enter a valid file format'); expect( - buildFile.bind(null, '__tests__/__output/test.txt', [], {}, {}) + buildFile.bind(null, {destination: '__tests__/__output/test.txt', format: {}}, {}, {}) ).toThrow('Please enter a valid file format'); expect( - buildFile.bind(null, '__tests__/__output/test.txt', null, {}, {}) + buildFile.bind(null, {destination: '__tests__/__output/test.txt', format: []}, {}, {}) ).toThrow('Please enter a valid file format'); }); it('should error if destination doesnt exist or isnt a string', () => { expect( - buildFile.bind(null, {}, format, {}, {}) + buildFile.bind(null, {format}, {}, {}) ).toThrow('Please enter a valid destination'); expect( - buildFile.bind(null, [], format, {}, {}) + buildFile.bind(null, {format, destination: []}, {}, {}) ).toThrow('Please enter a valid destination'); expect( - buildFile.bind(null, null, format, {}, {}) + buildFile.bind(null, {format, destination: {}}, {}, {}) ).toThrow('Please enter a valid destination'); }); - let dest = './__tests__/__output/test.collisions'; - var PROPERTY_NAME_COLLISION_WARNINGS = GroupMessages.GROUP.PropertyNameCollisionWarnings + ":" + dest; + let destination = './__tests__/__output/test.collisions'; + var PROPERTY_NAME_COLLISION_WARNINGS = GroupMessages.GROUP.PropertyNameCollisionWarnings + ":" + destination; it('should generate warning messages for output name collisions', () => { let name = 'someName'; let properties = { @@ -71,7 +71,7 @@ describe('buildFile', () => { }; GroupMessages.clear(PROPERTY_NAME_COLLISION_WARNINGS); - buildFile(dest, format, {}, properties); + buildFile({destination, format}, {}, properties); let collisions = properties.allProperties.map((properties) => { let propertyPathText = chalk.keyword('orangered')(properties.path.join('.')); @@ -86,7 +86,13 @@ describe('buildFile', () => { }); it('should write to a file properly', () => { - buildFile('test.txt', format, {buildPath: '__tests__/__output/'}, {}); + buildFile({ + destination: 'test.txt', + format + },{ + buildPath: '__tests__/__output/' + },{} + ); expect(helpers.fileExists('./__tests__/__output/test.txt')).toBeTruthy(); }); }); diff --git a/__tests__/cleanDir.test.js b/__tests__/cleanDir.test.js index 57508e165..180c6a95a 100644 --- a/__tests__/cleanDir.test.js +++ b/__tests__/cleanDir.test.js @@ -31,9 +31,9 @@ describe('cleanDir', () => { }); it('should delete a dir properly', () => { - buildFile('test.txt', format, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); - cleanFile('test.txt', format, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); - cleanDir('test.txt', format, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); + buildFile({destination:'test.txt', format}, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); + cleanFile({destination:'test.txt', format}, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); + cleanDir({destination:'test.txt', format}, {buildPath: '__tests__/__output/extradir1/extradir2/'}, {}); expect(helpers.dirDoesNotExist('./__tests__/__output/extradir1/extradir2')).toBeTruthy(); expect(helpers.dirDoesNotExist('./__tests__/__output/extradir1')).toBeTruthy(); }); diff --git a/__tests__/cleanFile.test.js b/__tests__/cleanFile.test.js index 87052d2c9..8f806c79a 100644 --- a/__tests__/cleanFile.test.js +++ b/__tests__/cleanFile.test.js @@ -30,14 +30,14 @@ describe('cleanFile', () => { }); it('should delete a file properly', () => { - buildFile('test.txt', format, {buildPath: '__tests__/__output/'}, {}); - cleanFile('test.txt', format, {buildPath: '__tests__/__output/'}, {}); + buildFile({destination:'test.txt', format}, {buildPath: '__tests__/__output/'}, {}); + cleanFile({destination:'test.txt', format}, {buildPath: '__tests__/__output/'}, {}); expect(helpers.fileDoesNotExist('./__tests__/__output/test.txt')).toBeTruthy(); }); describe('if a file does not exist', () => { it('should not throw', () => { - expect(() => cleanFile('non-existent.txt', format, { buildPath: '__tests__/__output/' }, {})).not.toThrow(); + expect(() => cleanFile({destination: 'non-existent.txt', format}, { buildPath: '__tests__/__output/' }, {})).not.toThrow(); }) }) diff --git a/__tests__/formats/all.test.js b/__tests__/formats/all.test.js index 417033b56..d3aa8431d 100644 --- a/__tests__/formats/all.test.js +++ b/__tests__/formats/all.test.js @@ -67,7 +67,7 @@ describe('formats', () => { global.Date = function() { return constantDate }; var formatter = formats[key].bind(file); - var output = formatter(dictionary, file); + var output = formatter(dictionary, {}, file); // reset the global Date object global.Date = globalDate; diff --git a/__tests__/formats/es6Constants.test.js b/__tests__/formats/es6Constants.test.js index c0728424d..732d6fe74 100644 --- a/__tests__/formats/es6Constants.test.js +++ b/__tests__/formats/es6Constants.test.js @@ -59,7 +59,7 @@ describe('formats', () => { }); it('should be a valid JS file', () => { - fs.writeFileSync('./__tests__/__output/output.js', formatter(dictionary) ); + fs.writeFileSync('./__tests__/__output/output.js', formatter(dictionary, {}, file) ); var test = require('../__output/output.js'); expect(test.red).toEqual(dictionary.allProperties[0].value); }); diff --git a/__tests__/formats/javascriptModule.test.js b/__tests__/formats/javascriptModule.test.js index 6d561ff12..2cc06021b 100644 --- a/__tests__/formats/javascriptModule.test.js +++ b/__tests__/formats/javascriptModule.test.js @@ -47,7 +47,7 @@ describe('formats', () => { }); it('should be a valid JS file', () => { - fs.writeFileSync('./__tests__/__output/output.js', formatter(dictionary) ); + fs.writeFileSync('./__tests__/__output/output.js', formatter(dictionary, {}, file) ); var test = require('../__output/output.js'); expect(test.color.red.value).toEqual(dictionary.properties.color.red.value); }); diff --git a/__tests__/formats/javascriptObject.test.js b/__tests__/formats/javascriptObject.test.js index 94ad8500f..dcb2683c0 100644 --- a/__tests__/formats/javascriptObject.test.js +++ b/__tests__/formats/javascriptObject.test.js @@ -35,7 +35,7 @@ describe('formats', () => { it('should be valid JS syntax', done => { try { - vm.runInNewContext(formatter(dictionary)) + vm.runInNewContext(formatter(dictionary, {}, file)) return done(); } catch (err) { return done(new Error(err)); diff --git a/__tests__/formats/javascriptUmd.test.js b/__tests__/formats/javascriptUmd.test.js index 91752177e..e8a54527d 100644 --- a/__tests__/formats/javascriptUmd.test.js +++ b/__tests__/formats/javascriptUmd.test.js @@ -47,7 +47,7 @@ describe('formats', () => { }); it('should be a valid JS file', () => { - fs.writeFileSync('./__tests__/__output/umd.js', formatter(dictionary) ); + fs.writeFileSync('./__tests__/__output/umd.js', formatter(dictionary, {}, file) ); var test = require('../__output/umd.js'); expect(test.color.red.value).toEqual(dictionary.properties.color.red.value); }); diff --git a/__tests__/formats/json.test.js b/__tests__/formats/json.test.js index b59991b88..795d6edd5 100644 --- a/__tests__/formats/json.test.js +++ b/__tests__/formats/json.test.js @@ -42,7 +42,7 @@ describe('formats', () => { }); it('should be a valid JSON file', () => { - fs.writeFileSync('./__tests__/__output/output.json', formatter(dictionary) ); + fs.writeFileSync('./__tests__/__output/output.json', formatter(dictionary, {}, file) ); var test = require('../__output/output.json'); expect(test.color.red.value).toEqual(dictionary.properties.color.red.value); }); diff --git a/__tests__/formats/jsonFlat.test.js b/__tests__/formats/jsonFlat.test.js index 2bf19a0e6..4c7397a47 100644 --- a/__tests__/formats/jsonFlat.test.js +++ b/__tests__/formats/jsonFlat.test.js @@ -54,7 +54,7 @@ describe('formats', () => { }); it('should be a valid JSON file', () => { - fs.writeFileSync('./__tests__/__output/output.flat.json', formatter(dictionary) ); + fs.writeFileSync('./__tests__/__output/output.flat.json', formatter(dictionary, {}, file) ); var test = require('../__output/output.flat.json'); expect(test['color-base-red']).toEqual(dictionary.allProperties[0].value); }); diff --git a/__tests__/formats/jsonNested.test.js b/__tests__/formats/jsonNested.test.js index 7449f0aed..79263b113 100644 --- a/__tests__/formats/jsonNested.test.js +++ b/__tests__/formats/jsonNested.test.js @@ -50,7 +50,7 @@ describe('formats', function() { }); it('should be a valid JSON file', function() { - fs.writeFileSync('./__tests__/__output/json-nested.json', formatter(dictionary)); + fs.writeFileSync('./__tests__/__output/json-nested.json', formatter(dictionary, {}, file)); var test = require('../__output/json-nested.json'); expect(test.color.base.red.primary) .toEqual(dictionary.properties.color.base.red.primary.value); diff --git a/__tests__/formats/lessIcons.test.js b/__tests__/formats/lessIcons.test.js index 545b008b9..dfbcdf74d 100644 --- a/__tests__/formats/lessIcons.test.js +++ b/__tests__/formats/lessIcons.test.js @@ -49,7 +49,7 @@ describe('formats', () => { describe('less/icons', () => { it('should have a valid less syntax', done => { - less.render(formatter(dictionary, config)) + less.render(formatter(dictionary, config, file)) .then(function(output) { expect(output).toBeDefined(); done(); diff --git a/__tests__/formats/lessVariables.test.js b/__tests__/formats/lessVariables.test.js index 4b229b033..7a09203e5 100644 --- a/__tests__/formats/lessVariables.test.js +++ b/__tests__/formats/lessVariables.test.js @@ -51,7 +51,7 @@ describe('formats', () => { describe('less/variables', () => { it('should have a valid less syntax', done => { - less.render(formatter(dictionary)) + less.render(formatter(dictionary, {}, file)) .then(function(output) { expect(output).toBeDefined(); done(); diff --git a/__tests__/formats/scssIcons.test.js b/__tests__/formats/scssIcons.test.js index ec95d3dc3..466dc52b3 100644 --- a/__tests__/formats/scssIcons.test.js +++ b/__tests__/formats/scssIcons.test.js @@ -50,7 +50,7 @@ describe('formats', () => { it('should have a valid scss syntax', done => { scss.render({ - data: formatter(dictionary, config), + data: formatter(dictionary, config, file), }, function(err, result) { if(err) { return done(new Error(err)); diff --git a/__tests__/formats/scssMaps.test.js b/__tests__/formats/scssMaps.test.js index a7f2e9e64..b21e696e0 100644 --- a/__tests__/formats/scssMaps.test.js +++ b/__tests__/formats/scssMaps.test.js @@ -220,7 +220,7 @@ describe('formats', () => { global.Date = function() { return constantDate }; var formatter = formats[key].bind(file); - var output = formatter(dictionary, file); + var output = formatter(dictionary, {}, file); // reset the global Date object (or node-sass will complain!) global.Date = globalDate; diff --git a/__tests__/formats/scssVariables.test.js b/__tests__/formats/scssVariables.test.js index a30cec3bb..aebe27f5e 100644 --- a/__tests__/formats/scssVariables.test.js +++ b/__tests__/formats/scssVariables.test.js @@ -53,7 +53,7 @@ describe('formats', () => { it('should have a valid scss syntax', done => { scss.render({ - data: formatter(dictionary), + data: formatter(dictionary, {}, file), }, function(err, result) { if(err) { return done(new Error(err)); diff --git a/lib/buildFile.js b/lib/buildFile.js index 364073c96..779052170 100644 --- a/lib/buildFile.js +++ b/lib/buildFile.js @@ -21,19 +21,21 @@ var path = require('path'), * Takes the style property object and a format and returns a * string that can be written to a file. * @memberOf StyleDictionary - * @param {String} destination - * @param {Function} format + * @param {Object} file * @param {Object} platform * @param {Object} dictionary - * @param {Function} filter * @returns {null} */ -function buildFile(destination, format, platform, dictionary, filter) { +function buildFile(file = {}, platform = {}, dictionary = {}) { + var { destination, filter, format } = file || {}; + if (typeof format !== 'function') throw new Error('Please enter a valid file format'); if (typeof destination !== 'string') throw new Error('Please enter a valid destination'); + // to maintain backwards compatability we bind the format to the file object + format = format.bind(file); var fullDestination = destination; // if there is a build path, prepend the full destination with it @@ -75,7 +77,7 @@ function buildFile(destination, format, platform, dictionary, filter) { let propertyNamesCollisionCount = GroupMessages.count(PROPERTY_NAME_COLLISION_WARNINGS); - fs.writeFileSync(fullDestination, format(filteredProperties, platform)); + fs.writeFileSync(fullDestination, format(filteredProperties, platform, file)); console.log((propertyNamesCollisionCount>0 ? '⚠️ ' : chalk.bold.green('✔︎ ')) + ' ' + fullDestination); if(propertyNamesCollisionCount > 0) { diff --git a/lib/buildFiles.js b/lib/buildFiles.js index 7b1089931..d15e5f963 100644 --- a/lib/buildFiles.js +++ b/lib/buildFiles.js @@ -31,7 +31,7 @@ function buildFiles(dictionary, platform) { _.each(platform.files, function (file) { if (file.format) { - buildFile(file.destination, file.format.bind(file), platform, dictionary, file.filter); + buildFile(file, platform, dictionary); } else { throw new Error('Please supply a format'); } diff --git a/lib/cleanDir.js b/lib/cleanDir.js index 5caf90ca0..bc8a63d05 100644 --- a/lib/cleanDir.js +++ b/lib/cleanDir.js @@ -20,14 +20,13 @@ var path = require('path'), * Takes the style property object and a format and returns a * string that can be written to a file. * @memberOf StyleDictionary - * @param {String} destination - * @param {Function} format (unused) + * @param {Object} file * @param {Object} platform * @param {Object} dictionary (unused) - * @param {Function} filter (unused) * @returns {null} */ -function cleanDir(destination, format, platform, dictionary, filter) { +function cleanDir(file = {}, platform = {}, dictionary = {}) { + var { destination } = file; if (typeof destination !== 'string') throw new Error('Please enter a valid destination'); diff --git a/lib/cleanDirs.js b/lib/cleanDirs.js index fdfd08a24..538357d5d 100644 --- a/lib/cleanDirs.js +++ b/lib/cleanDirs.js @@ -32,7 +32,7 @@ function cleanDirs(dictionary, platform) { // while neither the format or dictionary are used by clean file I'm passing them in for symmetry to buildFile _.each(platform.files, function (file) { if (file.format) { - cleanDir(file.destination, file.format.bind(file), platform, dictionary); + cleanDir(file, platform, dictionary); } else { throw new Error('Please supply a format') } diff --git a/lib/cleanFile.js b/lib/cleanFile.js index 4d4eeff8e..70ca7293b 100644 --- a/lib/cleanFile.js +++ b/lib/cleanFile.js @@ -27,7 +27,8 @@ var path = require('path'), * @param {Function} filter (unused) * @returns {null} */ -function cleanFile(destination, format, platform, dictionary, filter) { +function cleanFile(file = {}, platform = {}, dictionary = {}) { + var { destination } = file; if (typeof destination !== 'string') throw new Error('Please enter a valid destination'); @@ -37,8 +38,6 @@ function cleanFile(destination, format, platform, dictionary, filter) { destination = platform.buildPath + destination; } - var dirname = path.dirname(destination); - if (!fs.existsSync(destination)) { console.log(chalk.bold.red('!') + ' ' + destination + ', does not exist'); return; diff --git a/lib/cleanFiles.js b/lib/cleanFiles.js index 5c6c8bb9f..6f5ffc3b8 100644 --- a/lib/cleanFiles.js +++ b/lib/cleanFiles.js @@ -32,7 +32,7 @@ function cleanFiles(dictionary, platform) { // while neither the format or dictionary are used by clean file I'm passing them in for symmetry to buildFile _.each(platform.files, function (file) { if (file.format) { - cleanFile(file.destination, file.format.bind(file), platform, dictionary); + cleanFile(file, platform, dictionary); } else { throw new Error('Please supply a template or formatter') } diff --git a/lib/common/formats.js b/lib/common/formats.js index 79859eb55..bc2ed1ba4 100644 --- a/lib/common/formats.js +++ b/lib/common/formats.js @@ -129,8 +129,8 @@ module.exports = { * } * ``` */ - 'css/variables': function(dictionary) { - return fileHeader(this.options) + + 'css/variables': function(dictionary, config, file) { + return fileHeader(file.options) + ':root {\n' + formattedVariables('css', dictionary.allProperties) + '\n}\n'; @@ -215,7 +215,7 @@ module.exports = { * $color-background-alt: #eeeeee !default; * ``` */ - 'scss/variables': function(dictionary) { + 'scss/variables': function(dictionary, config, file) { return fileHeader(this.options, 'short') + formattedVariables('sass', dictionary.allProperties); }, @@ -230,8 +230,8 @@ module.exports = { * .icon.email:before { content:$content-icon-email; } * ``` */ - 'scss/icons': function(dictionary, config) { - return fileHeader(this.options, 'short') + iconsWithPrefix('$', dictionary.allProperties, config, 'short'); + 'scss/icons': function(dictionary, config, file) { + return fileHeader(file.options, 'short') + iconsWithPrefix('$', dictionary.allProperties, config, 'short'); }, /** @@ -245,7 +245,7 @@ module.exports = { * \@color-background-alt: #eeeeee; * ``` */ - 'less/variables': function(dictionary) { + 'less/variables': function(dictionary, config, file) { return fileHeader(this.options, 'short') + formattedVariables('less', dictionary.allProperties); }, @@ -260,8 +260,8 @@ module.exports = { * .icon.email:before { content:\@content-icon-email; } * ``` */ - 'less/icons': function(dictionary, config) { - return fileHeader(this.options, 'short') + iconsWithPrefix('@', dictionary.allProperties, config, 'short'); + 'less/icons': function(dictionary, config, file) { + return fileHeader(file.options, 'short') + iconsWithPrefix('@', dictionary.allProperties, config, 'short'); }, /** @@ -282,8 +282,8 @@ module.exports = { * } * ``` */ - 'javascript/module': function(dictionary) { - return fileHeader(this.options) + + 'javascript/module': function(dictionary, config, file) { + return fileHeader(file.options) + 'module.exports = ' + JSON.stringify(dictionary.properties, null, 2) + ';'; }, @@ -325,10 +325,10 @@ module.exports = { * } * ``` */ - 'javascript/object': function(dictionary) { - return fileHeader(this.options) + + 'javascript/object': function(dictionary, config, file) { + return fileHeader(file.options) + 'var ' + - (this.name || '_styleDictionary') + + (file.name || '_styleDictionary') + ' = ' + JSON.stringify(dictionary.properties, null, 2) + ';'; @@ -364,9 +364,9 @@ module.exports = { * })) * ``` */ - 'javascript/umd': function(dictionary) { - var name = this.name || '_styleDictionary' - return fileHeader(this.options) + + 'javascript/umd': function(dictionary, config, file) { + var name = file.name || '_styleDictionary' + return fileHeader(file.options) + '(function(root, factory) {\n' + ' if (typeof module === "object" && module.exports) {\n' + ' module.exports = factory();\n' + @@ -414,8 +414,8 @@ module.exports = { * export const ColorBackgroundAlt = '#fcfcfcfc'; * ``` */ - 'javascript/es6': function(dictionary) { - return fileHeader(this.options) + + 'javascript/es6': function(dictionary, config, file) { + return fileHeader(file.options) + dictionary.allProperties.map(function(prop) { var to_ret_prop = 'export const ' + prop.name + ' = ' + JSON.stringify(prop.value) + ';'; if (prop.comment)