diff --git a/.circleci/config.yml b/.circleci/config.yml index b836063..9b90845 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -44,7 +44,12 @@ jobs: steps: - checkout - <<: *install_node_modules - - run: bash generate_mocks.sh + - run: + name: Generate Mocks + command: | + bash generate_mocks.sh + test $(find __mocks__/figma/assets -type f -name "*.png" | wc -l | sed -e 's/^[ \t]*//') -eq 6 + test $(find __mocks__/figma/assets -type f -name "*.svg" | wc -l | sed -e 's/^[ \t]*//') -eq 3 unit_tests_node_lts: executor: node @@ -71,6 +76,9 @@ jobs: - <<: *install_node_modules - run: ./node_modules/.bin/pkg cli.js -t node8-linux-x64 --output ./bin/hubble-cli - run: ./bin/hubble-cli --version + - run: + command: | + [ $(npx -c 'echo "$npm_package_version"') = $(./bin/hubble-cli --version) ] workflows: version: 2 diff --git a/.huskyrc b/.huskyrc new file mode 100644 index 0000000..d965519 --- /dev/null +++ b/.huskyrc @@ -0,0 +1,5 @@ +{ + "hooks": { + "pre-commit": "lint-staged", + } +} diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..e6451df --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,10 @@ +{ + "**/*.js": [ + "itp-react-scripts lint -- --fix", + "itp-react-scripts format", + "git add" + ], + "**/*.sh": [ + "command -v shellcheck && shellcheck" + ] +} diff --git a/.prettierignore b/.prettierignore index 4bcf50f..9d757ec 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,6 @@ __mocks__ __tests__ +*.test.js + jest.config.js diff --git a/__mocks__/figma/assets/icon.svg b/__mocks__/figma/assets/icon.svg new file mode 100644 index 0000000..e2d7ab6 --- /dev/null +++ b/__mocks__/figma/assets/icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/__mocks__/figma/assets/icons/hubble/plain.png b/__mocks__/figma/assets/icons/hubble/plain.png new file mode 100644 index 0000000..ba05830 Binary files /dev/null and b/__mocks__/figma/assets/icons/hubble/plain.png differ diff --git a/__mocks__/figma/assets/icons/hubble/plain.svg b/__mocks__/figma/assets/icons/hubble/plain.svg new file mode 100644 index 0000000..ddd27a4 --- /dev/null +++ b/__mocks__/figma/assets/icons/hubble/plain.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/__mocks__/figma/assets/icons/hubble/plain@2x.png b/__mocks__/figma/assets/icons/hubble/plain@2x.png new file mode 100644 index 0000000..0b2ca30 Binary files /dev/null and b/__mocks__/figma/assets/icons/hubble/plain@2x.png differ diff --git a/__mocks__/figma/assets/icons/hubble/plain@3x.png b/__mocks__/figma/assets/icons/hubble/plain@3x.png new file mode 100644 index 0000000..7416174 Binary files /dev/null and b/__mocks__/figma/assets/icons/hubble/plain@3x.png differ diff --git a/__mocks__/figma/assets/illustrations/hubble/telescope.png b/__mocks__/figma/assets/illustrations/hubble/telescope.png new file mode 100644 index 0000000..2e54b35 Binary files /dev/null and b/__mocks__/figma/assets/illustrations/hubble/telescope.png differ diff --git a/__mocks__/figma/assets/illustrations/hubble/telescope.svg b/__mocks__/figma/assets/illustrations/hubble/telescope.svg new file mode 100644 index 0000000..60c6b0d --- /dev/null +++ b/__mocks__/figma/assets/illustrations/hubble/telescope.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/__mocks__/figma/assets/illustrations/hubble/telescope@2x.png b/__mocks__/figma/assets/illustrations/hubble/telescope@2x.png new file mode 100644 index 0000000..5c6724b Binary files /dev/null and b/__mocks__/figma/assets/illustrations/hubble/telescope@2x.png differ diff --git a/__mocks__/figma/assets/illustrations/hubble/telescope@3x.png b/__mocks__/figma/assets/illustrations/hubble/telescope@3x.png new file mode 100644 index 0000000..186c48c Binary files /dev/null and b/__mocks__/figma/assets/illustrations/hubble/telescope@3x.png differ diff --git a/__mocks__/figma/sample_dump.json b/__mocks__/figma/sample_dump.json index 78d8f19..a92309e 100644 --- a/__mocks__/figma/sample_dump.json +++ b/__mocks__/figma/sample_dump.json @@ -6009,7 +6009,7 @@ "schemaVersion": 0, "styles": {}, "name": "Hubble Figma Sample", - "lastModified": "2019-08-01T11:26:57.968542Z", - "thumbnailUrl": "https://s3-alpha-sig.figma.com/thumbnails/4f30cf1c-16d2-49bd-b66b-d44f1ab41059?Expires=1565568000&Signature=djcdoXbZFjHr9SnEl7ynKGKATgiUj3Zp2jTYliAIF6vLo02xtiVYCk7cWhuQTj1-owQ~cUzQltZsY259V1J3hsFUGTumr3cKez5Xj04zPZ2XSpBTJfe3unxZ1h~HV1yaetpTpRcwK891hBI6HAyZBViAUcWb7kys2za9zpYR32D6UvQEZy-FeOUz3iKotpw84Y1bLiBXdZRsAbL8kSDW5M822jhZ2Lx10lY9ZK8duZFxuL61Q0viYJ8kfWxUUmCUMEvaLWY6KYTwHrdTBka8vadT1N~mPKiYZoUMiJsJCtRofM-wwFZjZKvmJ6WJRfVA31LCNyfzMhvfHorhUGbcQQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", - "version": "156404211" + "lastModified": "2019-08-20T13:09:14.221958Z", + "thumbnailUrl": "https://s3-alpha-sig.figma.com/thumbnails/4d046bc9-07c5-4043-82e3-28b4808d2947?Expires=1567382400&Signature=Ac5jWhR-MSNBZvuNpBP~G5NbPulj1XHGvYcV5W9SZ3VX8KAfrC8x3GA9LmnEQ8SqIWw8PqyDWGid7gqIbRVyuIXNP1DvmwaCbJL7ykXvif0fyzabeq3ERyCaxWynY-lrLgLH~L3PL9Iro7y2oAY5sDmXCqYp0hoqdhnEQw1GeUWk4g1HflFTvgy0yJWmJ7xgHsvReZMUl1e3N~Ka7I0qdGrwCtXgI3hhJJu~VTkVQFWo9osU6GdIRgcb19h-qPtbpIw8dVvhMG~3Zf8TEiQvXh2jwUILZ96loh65AHBwBZRJMEuzG4IGquIlBRJe5wjCKTKcS8p0lZ0IfvpwxwQgnQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", + "version": "163204485" } \ No newline at end of file diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain.pdf b/__mocks__/sketch/exported_assets/icons/hubble/plain.pdf new file mode 100644 index 0000000..497a52e Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain.pdf differ diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain.png b/__mocks__/sketch/exported_assets/icons/hubble/plain.png new file mode 100644 index 0000000..8391f2b Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain.png differ diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain.svg b/__mocks__/sketch/exported_assets/icons/hubble/plain.svg new file mode 100644 index 0000000..d8f5f78 --- /dev/null +++ b/__mocks__/sketch/exported_assets/icons/hubble/plain.svg @@ -0,0 +1,20 @@ + + + icons/hubble/plain + Created with sketchtool. + + + + + + + + + + + + + + + + diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain@1.5x.png b/__mocks__/sketch/exported_assets/icons/hubble/plain@1.5x.png new file mode 100644 index 0000000..adff955 Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain@1.5x.png differ diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain@2x.png b/__mocks__/sketch/exported_assets/icons/hubble/plain@2x.png new file mode 100644 index 0000000..28e81db Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain@2x.png differ diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain@3x.png b/__mocks__/sketch/exported_assets/icons/hubble/plain@3x.png new file mode 100644 index 0000000..a0e4bfe Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain@3x.png differ diff --git a/__mocks__/sketch/exported_assets/icons/hubble/plain@4x.png b/__mocks__/sketch/exported_assets/icons/hubble/plain@4x.png new file mode 100644 index 0000000..1c1fbd5 Binary files /dev/null and b/__mocks__/sketch/exported_assets/icons/hubble/plain@4x.png differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.pdf b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.pdf new file mode 100644 index 0000000..d3f9ae3 Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.pdf differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.png b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.png new file mode 100644 index 0000000..cd68b3b Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.png differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.svg b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.svg new file mode 100644 index 0000000..892b4f0 --- /dev/null +++ b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope.svg @@ -0,0 +1,62 @@ + + + illustrations/hubble/telescope + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@1.5x.png b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@1.5x.png new file mode 100644 index 0000000..d264da3 Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@1.5x.png differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@2x.png b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@2x.png new file mode 100644 index 0000000..615afdf Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@2x.png differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@3x.png b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@3x.png new file mode 100644 index 0000000..5dd5d57 Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@3x.png differ diff --git a/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@4x.png b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@4x.png new file mode 100644 index 0000000..2aa7bc3 Binary files /dev/null and b/__mocks__/sketch/exported_assets/illustrations/hubble/telescope@4x.png differ diff --git a/__tests__/__snapshots__/verifyMocks.test.js.snap b/__tests__/__snapshots__/verifyMocks.test.js.snap index f40a668..95ed688 100644 --- a/__tests__/__snapshots__/verifyMocks.test.js.snap +++ b/__tests__/__snapshots__/verifyMocks.test.js.snap @@ -7121,12 +7121,12 @@ Object { "name": "Document", "type": "DOCUMENT", }, - "lastModified": "2019-08-01T11:26:57.968542Z", + "lastModified": "2019-08-20T13:09:14.221958Z", "name": "Hubble Figma Sample", "schemaVersion": 0, "styles": Object {}, - "thumbnailUrl": "https://s3-alpha-sig.figma.com/thumbnails/4f30cf1c-16d2-49bd-b66b-d44f1ab41059?Expires=1565568000&Signature=djcdoXbZFjHr9SnEl7ynKGKATgiUj3Zp2jTYliAIF6vLo02xtiVYCk7cWhuQTj1-owQ~cUzQltZsY259V1J3hsFUGTumr3cKez5Xj04zPZ2XSpBTJfe3unxZ1h~HV1yaetpTpRcwK891hBI6HAyZBViAUcWb7kys2za9zpYR32D6UvQEZy-FeOUz3iKotpw84Y1bLiBXdZRsAbL8kSDW5M822jhZ2Lx10lY9ZK8duZFxuL61Q0viYJ8kfWxUUmCUMEvaLWY6KYTwHrdTBka8vadT1N~mPKiYZoUMiJsJCtRofM-wwFZjZKvmJ6WJRfVA31LCNyfzMhvfHorhUGbcQQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", - "version": "156404211", + "thumbnailUrl": "https://s3-alpha-sig.figma.com/thumbnails/4d046bc9-07c5-4043-82e3-28b4808d2947?Expires=1567382400&Signature=Ac5jWhR-MSNBZvuNpBP~G5NbPulj1XHGvYcV5W9SZ3VX8KAfrC8x3GA9LmnEQ8SqIWw8PqyDWGid7gqIbRVyuIXNP1DvmwaCbJL7ykXvif0fyzabeq3ERyCaxWynY-lrLgLH~L3PL9Iro7y2oAY5sDmXCqYp0hoqdhnEQw1GeUWk4g1HflFTvgy0yJWmJ7xgHsvReZMUl1e3N~Ka7I0qdGrwCtXgI3hhJJu~VTkVQFWo9osU6GdIRgcb19h-qPtbpIw8dVvhMG~3Zf8TEiQvXh2jwUILZ96loh65AHBwBZRJMEuzG4IGquIlBRJe5wjCKTKcS8p0lZ0IfvpwxwQgnQ__&Key-Pair-Id=APKAINTVSUGEWH5XD5UA", + "version": "163204485", } `; diff --git a/bin/hubble-cli b/bin/hubble-cli index 31f273c..e6b7cea 100755 Binary files a/bin/hubble-cli and b/bin/hubble-cli differ diff --git a/cli.js b/cli.js index c530af4..27a6b36 100644 --- a/cli.js +++ b/cli.js @@ -16,6 +16,7 @@ const cli = meow( --useGradientArtboards Use artboard formatting to export gradients instead of using the document gradients. --useStyleDictionaryOutput, -s Generate Style Dictionary compatible output instead of the generic design token format. --token, -t Authorization token when accessing the Figma API. + --exportAssets, -e Export assets from Figma. Examples $ hubble-cli "__mocks/sample_sketchfile.sketch" @@ -51,6 +52,11 @@ const cli = meow( default: false, alias: 's', }, + exportAssets: { + type: 'boolean', + default: false, + alias: 'e', + }, version: { type: 'boolean', alias: 'v', diff --git a/generate_mocks.sh b/generate_mocks.sh index 9187b60..7afcfbf 100755 --- a/generate_mocks.sh +++ b/generate_mocks.sh @@ -6,9 +6,10 @@ FIGMA_FILE="HbgJuBVOwIOcoZMVnpG01LqA" function generate_figma() { echo "Generating mocks for Figma" - node cli.js --dump --token "$FIGMA_TOKEN" "$FIGMA_FILE" && \ + node cli.js --dump --exportAssets --token "$FIGMA_TOKEN" "$FIGMA_FILE" && \ mv hubble-data.json "$MOCKS_DIR/figma/sample_output.json" && \ - mv logdump.json "$MOCKS_DIR/figma/sample_dump.json" + mv logdump.json "$MOCKS_DIR/figma/sample_dump.json" && \ + mv assets "$MOCKS_DIR/figma/assets" echo "Generating mocks for Figma: Style Dictionary" node cli.js --useStyleDictionaryOutput --token "$FIGMA_TOKEN" "$FIGMA_FILE" && \ @@ -16,6 +17,9 @@ function generate_figma() { } function generate_sketch() { + echo "Exporting assets for Sketch" + ./sketchtool.sh "$MOCKS_DIR/sketch/sample_sketchfile.sketch" __mocks__/sketch/exported_assets + echo "Generating mocks for Sketch: Document Styles" node cli.js --dump "$MOCKS_DIR/sketch/sample_sketchfile.sketch" && \ mv hubble-data.json "$MOCKS_DIR/sketch/sample_output.document.json" && \ diff --git a/index.js b/index.js index 1deb2b2..26b5f19 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,14 @@ const fs = require('fs'); +const path = require('path'); + const pkg = require('./package.json'); const getParser = require('./lib/parser'); const getMappers = require('./lib/mappers'); -const { prettyJSON, writeFile } = require('./lib/utils'); +const { prettyJSON, writeFile, downloadFile } = require('./lib/utils'); const mapToStyleDictionaryTokens = require('./lib/styleDictionary'); +const ASSETS_DIR = 'assets'; + module.exports = async (args, flags) => { if (flags.version) return pkg.version; if (args.length <= 0) throw new Error('No file input passed after npm start'); @@ -21,6 +25,7 @@ module.exports = async (args, flags) => { version, response, fileType, + assets, } = await parser.getTokens(); const mappers = getMappers(fileType); @@ -50,6 +55,18 @@ module.exports = async (args, flags) => { await writeFile(`${flags.outputDir}/hubble-data.json`, prettyJSON(mapping)); } + if (flags.exportAssets && assets) { + const fullAssetsDir = path.join(flags.outputDir, ASSETS_DIR); + + if (!fs.existsSync(fullAssetsDir)) { + fs.mkdirSync(fullAssetsDir); + } + + assets.forEach(asset => { + downloadFile(fullAssetsDir, asset); + }); + } + if (flags.dump) { await writeFile(`${flags.outputDir}/logdump.json`, prettyJSON(response)); } diff --git a/lib/figma.js b/lib/figma.js index b61a6e7..51f8f1c 100644 --- a/lib/figma.js +++ b/lib/figma.js @@ -1,3 +1,5 @@ +const { toSnakeCase } = require('./utils'); + /** * Helper function for flattenChildren * @param {Object} element a parent element @@ -45,3 +47,105 @@ exports.findAllTokens = (data, tokenType) => .toLowerCase() .includes(tokenType.toLowerCase()), ); + +/** + * Parses a flattened Figma API response to get all necessary information + * to call the Figma client and receive the image urls. + * + * @param {Array} exportableData + * @return {Array} + */ +const parseImageRequestData = (exportableData) => + exportableData.reduce((acc, component) => { + component.exportSettings.forEach((setting) => { + const { suffix } = setting; + const format = setting.format.toLowerCase(); + let scale = 1; + if (setting.constraint && setting.constraint.type && setting.constraint.type === 'SCALE') { + scale = setting.constraint.value; + } + + const existingElement = acc.find(c => c.format === format && c.scale === scale); + if (existingElement) { + existingElement.ids.push(component.id); + } else { + acc.push({ + ids: [component.id], + format, + scale, + suffix, + }) + } + }); + return acc; + }, []); + +/** + * Calls the images endpoint of the figma api (using figma-js client). + * This call returns an images map where each key is an object id, and each + * value is a url of the image in the requested format. + * See https://www.figma.com/developers/api#get-images-endpoint for more info + * + * @param {Object} client + * @param {string} fileId + * @param {Object} imageRequest + * @return {Object} + */ +const getImageUrls = async (client, fileId, imageRequest) => { + const imageResponse = await client.fileImages(fileId, imageRequest); + return { + format: imageRequest.format, + suffix: imageRequest.suffix, + urls: Object.entries(imageResponse.data.images).map(([id, url]) => ({ id, url })), + }; +}; + +/** + * Retrieves the urls for all images-exportsetting combinations defined in the (flattened) + * figma api response. Returns a map of url, id and full filename (including suffix and extension) + * + * @param {Object} client + * @param {string} fileId + * @param {Array} data + * @return {Array} + */ +exports.retrieveImageUrls = async(client, file, data) => { + try { + // filter out only components containing exportSettings + const exportableLayers = data.filter(component => component.exportSettings); + + // Parse all necessary data for the images request to figma api + const imageRequestData = parseImageRequestData(exportableLayers); + + // Request the image urls for each image-exportsetting combination + const imageRequestResults = await Promise.all(imageRequestData + .map(imageRequest => getImageUrls(client, file, imageRequest)) + ); + + // Now create an array of objects containing the full desired filename and url. + return imageRequestResults.reduce((acc, result) => { + result.urls.forEach(({ id, url }) => { + const matchingFileData = exportableLayers.find(d => d.id === id); + + const fileDirStructure = matchingFileData.name.split('/'); + const fileName = toSnakeCase(fileDirStructure.pop()); + const fullFileDirString = fileDirStructure.length ? `${fileDirStructure.join('/')}/` : ''; + + acc.push({ + id, + fileUrl: url, + fileName: `${fullFileDirString}${fileName}${result.suffix}.${result.format}`, + }); + }); + return acc; + }, []); + } catch (e) { + // TODO: Create documentation page for images in Figma files and use the correct link below + // TODO: Perhaps use more granular error messaging, and make some of them non-critical. Other design token + // export can complete without images + throw new Error(` + Something went wrong while trying to retrieve the images marked as exportable in Figma! + Please see https://github.com/inthepocket/hubble-sketch-plugin/wiki on how to structure your Figma file. + `); + } +} diff --git a/lib/parser/index.js b/lib/parser/index.js index 1b75e34..6bdafc0 100644 --- a/lib/parser/index.js +++ b/lib/parser/index.js @@ -1,7 +1,7 @@ const sketch2json = require('sketch2json'); const Figma = require('figma-js'); -const { findAllTokens, flattenChildren } = require('../figma'); +const { findAllTokens, flattenChildren, retrieveImageUrls } = require('../figma'); const { isSketch } = require('../utils'); const { getPageArrays, @@ -49,6 +49,7 @@ const parseTokens = async (args, flags) => { borders: getBordersFromArtboard(primitivesPage.layers), blurs: getBlursFromArtboard(primitivesPage.layers), fonts: response.meta.fonts, + assets: null, version: response.meta.appVersion, // Sketch Application Version fileType: FILE_TYPES.SKETCH, response, @@ -58,7 +59,7 @@ const parseTokens = async (args, flags) => { } } else { try { - const { token } = flags; + const { token, exportAssets } = flags; if (!token) throw new Error('Please add a Figma API authorization token'); const client = Figma.Client({ personalAccessToken: token }); @@ -75,6 +76,11 @@ const parseTokens = async (args, flags) => { const response = flattenChildren(data.document); + let assets = null; + if (exportAssets) { + assets = await retrieveImageUrls(client, file, response); + } + return { colors: findAllTokens(response, 'color'), textStyles: findAllTokens(response, 'textstyle'), @@ -86,12 +92,22 @@ const parseTokens = async (args, flags) => { shadows: findAllTokens(response, 'shadow'), borders: findAllTokens(response, 'border'), blurs: findAllTokens(response, 'blur'), + assets, version: 'v1', // Figma API Version fileType: FILE_TYPES.FIGMA, response: data, }; } catch (err) { - throw new Error(err); + if (err.response) { + const httpCode = err.response.status; + if (httpCode === 404) { + throw new Error(`The Figma file was not found. Double check if the provided id "${file}" is correct and the file exists.`) + } else if (httpCode === 403) { + throw new Error(`Invalid Figma token. Double check if the provided token is correct, and you have access rights to the file.`); + } + } + + throw err; } } }; diff --git a/lib/utils.js b/lib/utils.js index 22e2ee9..90d40e2 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,6 +2,9 @@ const camelcase = require('camelcase'); const colorConvert = require('color-convert'); const colorNamer = require('color-namer'); const fs = require('fs'); +const url = require('url'); +const http = require('http'); +const path = require('path'); const { promisify } = require('util'); const writeFile = promisify(fs.writeFile); @@ -142,6 +145,49 @@ module.exports = { return coordinates ? coordinates.map(parseFloat) : []; }, + /** + * Downloads a file from a given url with a given name, and places it in the + * downloadDir. If the fileName contains directories, it attempts to create these + * in the downloadDir. + */ + downloadFile: (downloadDir, { fileUrl, fileName }) => { + const options = { + host: url.parse(fileUrl).host, + port: 80, + path: url.parse(fileUrl).pathname + }; + + const fileDirStructure = fileName.split('/'); + if (fileDirStructure.length > 1) { + const fileDir = path.join(downloadDir, fileDirStructure.slice(0, -1).join('/')); + if (!fs.existsSync(fileDir)) { + fs.mkdirSync(fileDir, { recursive: true }) + } + } + + const file = fs.createWriteStream(path.join(downloadDir, fileName)); + + http.get(options, (result) => { + result + .on('data', data => { + file.write(data); + }) + .on('end', () => { + file.end(); + }); + }); + }, + + /** + * Snake case convertor implementation, by of https://github.com/huynhsamha + */ + toSnakeCase: str => !str ? '' : String(str) + .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, '') + .replace(/([a-z])([A-Z])/g, (m, a, b) => `${a}_${b.toLowerCase()}`) + .replace(/[^A-Za-z0-9]+|_+/g, '_') + .toLowerCase() + , + tokenize, convertNSColorToRGB, getNamedColorFromRGB, diff --git a/package-lock.json b/package-lock.json index 81c1429..9652e07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "hubble-scripts", - "version": "4.1.0", + "version": "4.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1011,65 +1011,6 @@ "to-fast-properties": "^2.0.0" } }, - "@iamstarkov/listr-update-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@iamstarkov/listr-update-renderer/-/listr-update-renderer-0.4.1.tgz", - "integrity": "sha512-IJyxQWsYDEkf8C8QthBn5N8tIUR9V9je6j3sMIpAkonaadjbvxmRC6RAhpa3RKxndhNnU2M6iNbtJwd7usQYIA==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^2.3.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "@inthepocket/itp-react-scripts": { "version": "0.48.1", "resolved": "https://registry.npmjs.org/@inthepocket/itp-react-scripts/-/itp-react-scripts-0.48.1.tgz", @@ -1338,6 +1279,12 @@ "readdirp": "^2.0.0" } }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1554,6 +1501,76 @@ "integrity": "sha512-uNUtxIZpGyuaq+5BqGGQHsL4wUlJAXRqOm6g3Y48/CWNGTLONgBibI0lh6lGxjR2HljFYUfszb+mk4WkgMntsA==", "dev": true }, + "husky": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", + "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "dev": true, + "requires": { + "cosmiconfig": "^5.0.7", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^6.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^3.0.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^4.0.1", + "run-node": "^1.0.0", + "slash": "^2.0.0" + }, + "dependencies": { + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -1717,6 +1734,15 @@ "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", "dev": true }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, "read-pkg-up": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", @@ -1804,6 +1830,12 @@ "integrity": "sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA==", "dev": true }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, "@webassemblyjs/ast": { "version": "1.7.11", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", @@ -8314,29 +8346,82 @@ "dev": true }, "husky": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", - "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.4.tgz", + "integrity": "sha512-7Rnt8aJfy+MlV28snmYK7O7vWwtOfeVxV6KhLpUFXlmx5ukQ1nQmNUB7QsAwSgdySB5X+bm7q7JIRgazqBUzKA==", "dev": true, "requires": { - "cosmiconfig": "^5.0.7", + "chalk": "^2.4.2", + "cosmiconfig": "^5.2.1", "execa": "^1.0.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", + "get-stdin": "^7.0.0", "is-ci": "^2.0.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.1.1", "run-node": "^1.0.0", - "slash": "^2.0.0" + "slash": "^3.0.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -8366,14 +8451,21 @@ } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -8392,65 +8484,131 @@ "ci-info": "^2.0.0" } }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "p-limit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", - "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "find-up": "^3.0.0" + "find-up": "^4.0.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" } }, "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + } } }, "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -10319,25 +10477,30 @@ "immediate": "~3.0.5" } }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, "lint-staged": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.4.tgz", - "integrity": "sha512-oFbbhB/VzN8B3i/sIdb9gMfngGArI6jIfxSn+WPdQb2Ni3GJeS6T4j5VriSbQfxfMuYoQlMHOoFt+lfcWV0HfA==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.2.1.tgz", + "integrity": "sha512-n0tDGR/rTCgQNwXnUf/eWIpPNddGWxC32ANTNYsj2k02iZb7Cz5ox2tytwBu+2r0zDXMEMKw7Y9OD/qsav561A==", "dev": true, "requires": { - "@iamstarkov/listr-update-renderer": "0.4.1", "chalk": "^2.3.1", "commander": "^2.14.1", - "cosmiconfig": "^5.0.2", + "cosmiconfig": "^5.2.0", "debug": "^3.1.0", "dedent": "^0.7.0", "del": "^3.0.0", "execa": "^1.0.0", - "find-parent-dir": "^0.3.0", "g-status": "^2.0.2", "is-glob": "^4.0.0", "is-windows": "^1.0.2", "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", "lodash": "^4.17.11", "log-symbols": "^2.2.0", "micromatch": "^3.1.8", @@ -10349,7 +10512,7 @@ "staged-git-files": "1.1.2", "string-argv": "^0.0.2", "stringify-object": "^3.2.2", - "yup": "^0.26.10" + "yup": "^0.27.0" }, "dependencies": { "arr-diff": { @@ -10393,6 +10556,18 @@ } } }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -10626,9 +10801,9 @@ "dev": true }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -10660,18 +10835,22 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -11637,6 +11816,12 @@ "mimic-fn": "^1.0.0" } }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -13961,9 +14146,9 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "simple-git": { - "version": "1.107.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.107.0.tgz", - "integrity": "sha512-t4OK1JRlp4ayKRfcW6owrWcRVLyHRUlhGd0uN6ZZTqfDq8a5XpcUdOKiGRNobHEuMtNqzp0vcJNvhYWwh5PsQA==", + "version": "1.124.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.124.0.tgz", + "integrity": "sha512-ks9mBoO4ODQy/xGLC8Cc+YDvj/hho/IKgPhi6h5LI/sA+YUdHc3v0DEoHzM29VmulubpGCxMJUSFmyXNsjNMEA==", "dev": true, "requires": { "debug": "^4.0.1" @@ -13979,9 +14164,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -14481,9 +14666,9 @@ "dev": true }, "synchronous-promise": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.6.tgz", - "integrity": "sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.9.tgz", + "integrity": "sha512-LO95GIW16x69LuND1nuuwM4pjgFGupg7pZ/4lU86AmchPKrhk0o2tpMU2unXRrqo81iAFe1YJ0nAGEVwsrZAgg==", "dev": true }, "table": { @@ -14862,6 +15047,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -16120,34 +16311,17 @@ } }, "yup": { - "version": "0.26.10", - "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz", - "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.27.0.tgz", + "integrity": "sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==", "dev": true, "requires": { - "@babel/runtime": "7.0.0", + "@babel/runtime": "^7.0.0", "fn-name": "~2.0.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "property-expr": "^1.5.0", - "synchronous-promise": "^2.0.5", + "synchronous-promise": "^2.0.6", "toposort": "^2.0.2" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", - "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.12.0" - } - }, - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", - "dev": true - } } } } diff --git a/package.json b/package.json index 8dcadf4..b6e7769 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hubble-scripts", "description": "Scripts repository to export design data like colors, fonts & text, and map them to design tokens.", - "version": "4.1.0", + "version": "4.2.0", "homepage": "https://hubble.inthepocket.design", "repository": "inthepocket/hubble-scripts", "author": "In The Pocket", @@ -42,8 +42,9 @@ "devDependencies": { "@inthepocket/itp-react-scripts": "^0.48.1", "eslint": "^5.13.0", + "husky": "^3.0.4", "jest": "^23.6.0", - "lint-staged": "^8.1.4", + "lint-staged": "^8.2.1", "pkg": "^4.3.7" }, "dependencies": { diff --git a/sketchtool.sh b/sketchtool.sh index 82fc1c5..d0c5c10 100755 --- a/sketchtool.sh +++ b/sketchtool.sh @@ -23,6 +23,11 @@ function check_file_input() { } function export_assets() { + if [ "$(uname)" != "Darwin" ]; then + echo "Not running on macOS" + exit 0 + fi + if [ ! -d /Applications/Sketch.app ]; then log "Doesn't seem like you have Sketch installed..." log "Please make sure Sketch is installed and at the path /Applications/Sketch.app" @@ -30,13 +35,16 @@ function export_assets() { fi if [ -f /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool ]; then - log "Exporting slices as svg & png(1x,1.5x,2x,3x,4x) to directory $2" + log "Exporting slices as SVG, PNG@(1x,1.5x,2x,3x,4x), PDF to directory $2" /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool export slices "$1" --output="$OUTPUT_DIR" \ --format="png" --scales="1, 1.5, 2, 3, 4" /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool export slices "$1" --output="$OUTPUT_DIR" \ --format="svg" + + /Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool export slices "$1" --output="$OUTPUT_DIR" \ + --format="pdf" else log "💩 sketchtool was not found" log "Please install Sketch.app and follow https://developer.sketchapp.com/guides/sketchtool/"