From 476d48d1404e0fbbe209f353efcc2e96d9d9a38e Mon Sep 17 00:00:00 2001 From: mauroerta Date: Mon, 26 Jul 2021 22:41:36 +0200 Subject: [PATCH] feat: wip of morfeo cli --- .gitignore | 2 +- apps/cli/config.backup.json | 147 +++++++++++++++ apps/cli/config.json | 124 +----------- apps/cli/package.json | 10 +- apps/cli/src/commands/build.ts | 13 +- apps/cli/src/constants/index.ts | 1 + apps/cli/src/constants/maps.ts | 22 +++ apps/cli/src/utils/buildTokens.ts | 37 ++++ apps/cli/src/utils/index.ts | 2 +- apps/cli/src/utils/makeComponentClasses.ts | 37 ++++ apps/cli/src/utils/morfeoToStyleDictionary.ts | 40 ++++ apps/cli/src/utils/parseSlice.ts | 87 +++++++++ apps/cli/src/utils/parser.ts | 131 ------------- apps/cli/src/utils/rmdir.ts | 17 ++ apps/cli/test/commands/build.test.ts | 65 +++++++ apps/cli/test/mocha.opts | 5 + apps/cli/test/tsconfig.json | 9 + apps/cli/test/unit/rmdir.test.ts | 32 ++++ apps/cli/test/utils/theme.ts | 178 ++++++++++++++++++ apps/cli/tokens/color/base.json | 13 -- apps/cli/tokens/color/font.json | 9 - apps/cli/tokens/default.json | 174 +++++++++++++++++ apps/cli/tokens/size/font.json | 22 --- apps/cli/tsconfig.json | 8 +- apps/web-sandbox/src/theme.ts | 2 +- docs/src/theme/theme.js | 2 +- package.json | 2 +- packages/core/package.json | 4 +- packages/fonts/package.json | 3 +- packages/jss/package.json | 4 +- packages/spec/package.json | 4 +- packages/web/package.json | 3 +- 32 files changed, 887 insertions(+), 322 deletions(-) create mode 100644 apps/cli/config.backup.json create mode 100644 apps/cli/src/constants/index.ts create mode 100644 apps/cli/src/constants/maps.ts create mode 100644 apps/cli/src/utils/buildTokens.ts create mode 100644 apps/cli/src/utils/makeComponentClasses.ts create mode 100644 apps/cli/src/utils/morfeoToStyleDictionary.ts create mode 100644 apps/cli/src/utils/parseSlice.ts delete mode 100644 apps/cli/src/utils/parser.ts create mode 100644 apps/cli/src/utils/rmdir.ts create mode 100644 apps/cli/test/commands/build.test.ts create mode 100644 apps/cli/test/mocha.opts create mode 100644 apps/cli/test/tsconfig.json create mode 100644 apps/cli/test/unit/rmdir.test.ts create mode 100644 apps/cli/test/utils/theme.ts delete mode 100644 apps/cli/tokens/color/base.json delete mode 100644 apps/cli/tokens/color/font.json create mode 100644 apps/cli/tokens/default.json delete mode 100644 apps/cli/tokens/size/font.json diff --git a/.gitignore b/.gitignore index dc6dcebd..98acc99b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. build +commonjs __snapshots__ # dependencies diff --git a/apps/cli/config.backup.json b/apps/cli/config.backup.json new file mode 100644 index 00000000..3af1fadd --- /dev/null +++ b/apps/cli/config.backup.json @@ -0,0 +1,147 @@ +{ + "source": ["tokens/**/*.json"], + "platforms": { + "scss": { + "transformGroup": "scss", + "buildPath": "build/scss/", + "files": [ + { + "destination": "_variables.scss", + "format": "scss/variables" + } + ] + }, + "android": { + "transformGroup": "android", + "buildPath": "build/android/", + "files": [ + { + "destination": "font_dimens.xml", + "format": "android/fontDimens" + }, + { + "destination": "colors.xml", + "format": "android/colors" + } + ] + }, + "compose": { + "transformGroup": "compose", + "buildPath": "build/compose/", + "files": [ + { + "destination": "MorfeoColor.kt", + "format": "compose/object", + "className": "MorfeoColor", + "packageName": "MorfeoColor", + "filter": { + "attributes": { + "category": "color" + } + } + }, + { + "destination": "MorfeoSize.kt", + "format": "compose/object", + "className": "MorfeoSize", + "packageName": "MorfeoSize", + "type": "float", + "filter": { + "attributes": { + "category": "size" + } + } + } + ] + }, + "ios": { + "transformGroup": "ios", + "buildPath": "build/ios/", + "files": [ + { + "destination": "MorfeoColor.h", + "format": "ios/colors.h", + "className": "MorfeoColor", + "type": "MorfeoColorName", + "filter": { + "attributes": { + "category": "color" + } + } + }, + { + "destination": "MorfeoColor.m", + "format": "ios/colors.m", + "className": "MorfeoColor", + "type": "MorfeoColorName", + "filter": { + "attributes": { + "category": "color" + } + } + }, + { + "destination": "MorfeoSize.h", + "format": "ios/static.h", + "className": "MorfeoSize", + "type": "float", + "filter": { + "attributes": { + "category": "size" + } + } + }, + { + "destination": "MorfeoSize.m", + "format": "ios/static.m", + "className": "MorfeoSize", + "type": "float", + "filter": { + "attributes": { + "category": "size" + } + } + } + ] + }, + "ios-swift": { + "transformGroup": "ios-swift", + "buildPath": "build/ios-swift/", + "files": [ + { + "destination": "Morfeo.swift", + "format": "ios-swift/class.swift", + "className": "Morfeo", + "filter": {} + } + ] + }, + "ios-swift-separate-enums": { + "transformGroup": "ios-swift-separate", + "buildPath": "build/ios-swift/", + "files": [ + { + "destination": "MorfeoColor.swift", + "format": "ios-swift/enum.swift", + "className": "MorfeoColor", + "filter": { + "attributes": { + "category": "color" + } + } + }, + { + "destination": "MorfeoSize.swift", + "format": "ios-swift/enum.swift", + "className": "MorfeoSize", + "type": "float", + "filter": { + "attributes": { + "category": "size" + } + } + } + ] + } + } +} diff --git a/apps/cli/config.json b/apps/cli/config.json index 968f321d..983f9f37 100644 --- a/apps/cli/config.json +++ b/apps/cli/config.json @@ -4,126 +4,12 @@ "scss": { "transformGroup": "scss", "buildPath": "build/scss/", - "files": [{ - "destination": "_variables.scss", - "format": "scss/variables" - }] - }, - "android": { - "transformGroup": "android", - "buildPath": "build/android/", - "files": [{ - "destination": "font_dimens.xml", - "format": "android/fontDimens" - },{ - "destination": "colors.xml", - "format": "android/colors" - }] - }, - "compose": { - "transformGroup": "compose", - "buildPath": "build/compose/", - "files": [{ - "destination": "StyleDictionaryColor.kt", - "format": "compose/object", - "className": "StyleDictionaryColor", - "packageName": "StyleDictionaryColor", - "filter": { - "attributes": { - "category": "color" - } + "files": [ + { + "destination": "_variables.scss", + "format": "scss/variables" } - },{ - "destination": "StyleDictionarySize.kt", - "format": "compose/object", - "className": "StyleDictionarySize", - "packageName": "StyleDictionarySize", - "type": "float", - "filter": { - "attributes": { - "category": "size" - } - } - }] - }, - "ios": { - "transformGroup": "ios", - "buildPath": "build/ios/", - "files": [{ - "destination": "StyleDictionaryColor.h", - "format": "ios/colors.h", - "className": "StyleDictionaryColor", - "type": "StyleDictionaryColorName", - "filter": { - "attributes": { - "category": "color" - } - } - },{ - "destination": "StyleDictionaryColor.m", - "format": "ios/colors.m", - "className": "StyleDictionaryColor", - "type": "StyleDictionaryColorName", - "filter": { - "attributes": { - "category": "color" - } - } - },{ - "destination": "StyleDictionarySize.h", - "format": "ios/static.h", - "className": "StyleDictionarySize", - "type": "float", - "filter": { - "attributes": { - "category": "size" - } - } - },{ - "destination": "StyleDictionarySize.m", - "format": "ios/static.m", - "className": "StyleDictionarySize", - "type": "float", - "filter": { - "attributes": { - "category": "size" - } - } - }] - }, - "ios-swift": { - "transformGroup": "ios-swift", - "buildPath": "build/ios-swift/", - "files": [{ - "destination": "StyleDictionary.swift", - "format": "ios-swift/class.swift", - "className": "StyleDictionary", - "filter": {} - }] - }, - "ios-swift-separate-enums": { - "transformGroup": "ios-swift-separate", - "buildPath": "build/ios-swift/", - "files": [{ - "destination": "StyleDictionaryColor.swift", - "format": "ios-swift/enum.swift", - "className": "StyleDictionaryColor", - "filter": { - "attributes": { - "category": "color" - } - } - },{ - "destination": "StyleDictionarySize.swift", - "format": "ios-swift/enum.swift", - "className": "StyleDictionarySize", - "type": "float", - "filter": { - "attributes": { - "category": "size" - } - } - }] + ] } } } diff --git a/apps/cli/package.json b/apps/cli/package.json index 8ce9955a..7f07de8d 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -17,11 +17,18 @@ }, "devDependencies": { "@oclif/dev-cli": "^1.26.0", + "@oclif/test": "^1.2.8", + "@types/chai": "^4.2.21", + "@types/mocha": "^5.2.7", "@types/node": "^10.17.60", + "chai": "^4.3.4", "eslint": "^5.16.0", "eslint-config-oclif": "^3.1.0", "eslint-config-oclif-typescript": "^0.1.0", + "eslint-config-prettier": "^8.3.0", "globby": "^10.0.2", + "mocha": "^5.2.0", + "nyc": "^14.1.1", "ts-node": "^8.10.2", "typescript": "^3.9.10" }, @@ -50,9 +57,8 @@ "repository": "https://github.com/VLK-STUDIO/morfeo", "scripts": { "postpack": "rm -f oclif.manifest.json", - "posttest": "eslint . --ext .ts --config .eslintrc", "prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme", - "test": "echo NO TESTS", + "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"", "version": "oclif-dev readme && git add README.md" }, "types": "lib/index.d.ts" diff --git a/apps/cli/src/commands/build.ts b/apps/cli/src/commands/build.ts index cff46a01..41cd52db 100644 --- a/apps/cli/src/commands/build.ts +++ b/apps/cli/src/commands/build.ts @@ -1,10 +1,7 @@ import * as path from 'path'; -import * as StyleDictionary from 'style-dictionary'; import { Command, flags } from '@oclif/command'; -import { parser } from '../utils'; - -StyleDictionary.extend(path.join(__dirname, '../..', 'config.json')); -StyleDictionary.cleanAllPlatforms(); +import { morfeoToStyleDictionary } from '../utils'; +import { theme } from '@morfeo/web'; export default class Build extends Command { static description = 'build design tokens based on your theme'; @@ -41,10 +38,10 @@ export default class Build extends Command { this.printMissingThemeError(); } - const localThemes = require(path.resolve(themePath)); + const localTheme = require(path.resolve(themePath)); - const css = parser(localThemes.lightTheme, flags.name); + theme.set(localTheme.default); - this.log(css); + morfeoToStyleDictionary(flags.name); } } diff --git a/apps/cli/src/constants/index.ts b/apps/cli/src/constants/index.ts new file mode 100644 index 00000000..688b2d22 --- /dev/null +++ b/apps/cli/src/constants/index.ts @@ -0,0 +1 @@ +export * from './maps'; diff --git a/apps/cli/src/constants/maps.ts b/apps/cli/src/constants/maps.ts new file mode 100644 index 00000000..2cc3c742 --- /dev/null +++ b/apps/cli/src/constants/maps.ts @@ -0,0 +1,22 @@ +import { ThemeKey } from '@morfeo/web'; + +type SliceToBeParsed = { + name: ThemeKey; + styleProp: string; + property: string; +}; + +export const BLACK_LIST: ThemeKey[] = ['components', 'mediaQueries']; + +export const TO_BE_PARSED_SLICES_LIST: SliceToBeParsed[] = [ + { + name: 'shadows', + styleProp: 'shadow', + property: 'boxShadow', + }, + { + name: 'gradients', + styleProp: 'bgGradient', + property: 'background', + }, +]; diff --git a/apps/cli/src/utils/buildTokens.ts b/apps/cli/src/utils/buildTokens.ts new file mode 100644 index 00000000..0c3abd68 --- /dev/null +++ b/apps/cli/src/utils/buildTokens.ts @@ -0,0 +1,37 @@ +import * as StyleDictionary from 'style-dictionary'; +import * as fs from 'fs'; +import * as path from 'path'; +import { rmdir } from './rmdir'; + +const STYLE_DICTIONARY_CONFIG_PATH = path.join(__dirname, '../../config.json'); +const STYLE_DICTIONARY_BUILD_PATH = path.join(__dirname, '../../build'); +const STYLE_DICTIONARY_CONFIG = JSON.parse( + fs.readFileSync(STYLE_DICTIONARY_CONFIG_PATH, { encoding: 'utf8' }), +); + +function deleteBuildedTokens() { + console.log('old build directory removed'); + rmdir(STYLE_DICTIONARY_BUILD_PATH); +} + +export function buildTokens(themeName: string) { + deleteBuildedTokens(); + const Builder = StyleDictionary.extend(STYLE_DICTIONARY_CONFIG); + Builder.buildAllPlatforms(); + + const oldScss = fs.readFileSync( + path.join(STYLE_DICTIONARY_BUILD_PATH, 'scss', '_variables.scss'), + { encoding: 'utf8' }, + ); + const parsedScss = oldScss.split('\n').join('\n\t'); + const newScss = [ + `:root, html[data-morfeo-theme="${themeName}"] {`, + parsedScss, + `}`, + ].join('\n'); + + fs.writeFileSync( + path.join(STYLE_DICTIONARY_BUILD_PATH, 'scss', '_variables.scss'), + newScss, + ); +} diff --git a/apps/cli/src/utils/index.ts b/apps/cli/src/utils/index.ts index 75aa8b93..96820a11 100644 --- a/apps/cli/src/utils/index.ts +++ b/apps/cli/src/utils/index.ts @@ -1 +1 @@ -export * from './parser'; +export * from './morfeoToStyleDictionary'; diff --git a/apps/cli/src/utils/makeComponentClasses.ts b/apps/cli/src/utils/makeComponentClasses.ts new file mode 100644 index 00000000..8fde9dba --- /dev/null +++ b/apps/cli/src/utils/makeComponentClasses.ts @@ -0,0 +1,37 @@ +import { theme, getStyles, Component } from '@morfeo/web'; +import * as fs from 'fs'; +import * as path from 'path'; + +const SCSS_PATH = path.join(__dirname, '../../build/scss/_variables.scss'); + +function appendCss(componentName: Component, variant?: string) { + const componentId = `morfeo-${componentName.toLowerCase()}${ + variant ? `-${variant.toLowerCase()}` : '' + }`; + + const { sheet } = getStyles( + { [componentName]: { componentName, variant } }, + { + generateId: () => componentId, + }, + ); + + const componentCss = sheet.toString(); + + fs.appendFileSync(SCSS_PATH, `\n${componentCss}\n`); +} + +export function makeComponentClasses() { + const { components } = theme.get(); + const componentNames = Object.keys(components) as Component[]; + + componentNames.forEach(componentName => { + const { variants } = components[componentName]; + const variantKeys = Object.keys(variants || {}); + appendCss(componentName); + + variantKeys.forEach(variant => { + appendCss(componentName, variant); + }); + }); +} diff --git a/apps/cli/src/utils/morfeoToStyleDictionary.ts b/apps/cli/src/utils/morfeoToStyleDictionary.ts new file mode 100644 index 00000000..52e8ba96 --- /dev/null +++ b/apps/cli/src/utils/morfeoToStyleDictionary.ts @@ -0,0 +1,40 @@ +import { theme, ThemeKey, deepMerge } from '@morfeo/web'; +import * as fs from 'fs'; +import * as path from 'path'; +import { BLACK_LIST } from '../constants'; +import { parseSlice } from './parseSlice'; +import { buildTokens } from './buildTokens'; +import { rmdir } from './rmdir'; +import { makeComponentClasses } from './makeComponentClasses'; + +const TOKENS_BASE_PATH = path.join(__dirname, '../../tokens'); + +function getTokenPath(themeName: string) { + const tokenPath = path.join(TOKENS_BASE_PATH, `${themeName}.json`); + + console.log('old tokens directory removed'); + rmdir(TOKENS_BASE_PATH); + fs.mkdirSync(TOKENS_BASE_PATH); + + return tokenPath; +} + +export function morfeoToStyleDictionary(themeName: string) { + const morfeoTheme = theme.get(); + + const slices = Object.keys(morfeoTheme) as ThemeKey[]; + const filtered = slices.filter(key => !BLACK_LIST.includes(key)); + + const object = filtered.reduce( + (acc, curr) => deepMerge(acc, parseSlice(curr)), + {}, + ); + + const tokenPath = getTokenPath(themeName); + + fs.writeFileSync(tokenPath, JSON.stringify(object, undefined, 2)); + + buildTokens(themeName); + + makeComponentClasses(); +} diff --git a/apps/cli/src/utils/parseSlice.ts b/apps/cli/src/utils/parseSlice.ts new file mode 100644 index 00000000..b5875d09 --- /dev/null +++ b/apps/cli/src/utils/parseSlice.ts @@ -0,0 +1,87 @@ +import { + deepMerge, + theme, + parsers, + Theme, + ThemeKey, + BreakPoint, +} from '@morfeo/web'; +import { TO_BE_PARSED_SLICES_LIST } from '../constants'; + +function getValue( + sliceName: Key, + attribute: keyof Theme[Key], +) { + const toBeParsed = TO_BE_PARSED_SLICES_LIST.find( + config => config.name === sliceName, + ); + if (toBeParsed) { + const style = parsers.resolve({ + [toBeParsed.styleProp]: attribute, + }); + + return style[toBeParsed.property]; + } + + return theme.getValue(sliceName, attribute); +} + +function getConfig( + sliceName: Key, + attribute: keyof Theme[Key], +) { + const value = getValue(sliceName, attribute); + const attributeConfig = { + [attribute]: { + value, + comment: `value referred to morfeo's \`${sliceName}\` theme slice`, + }, + }; + + return { [sliceName]: attributeConfig }; +} + +function makeMediaQueriesSlice() { + const breakpoints = theme.getSlice('breakpoints'); + const keys = Object.keys(breakpoints) as BreakPoint[]; + + const values = keys.reduce( + (acc, curr) => { + return { + bg: { + ...acc.bg, + [curr]: 'any value', + }, + }; + }, + { bg: {} }, + ); + + const style = parsers.resolve(values); + const mediaQueries = Object.keys(style); + + return { + mediaQueries: keys.reduce( + (acc, curr, index) => ({ + ...acc, + [curr]: { + value: `"${mediaQueries[index]}"`, + comment: "value referred to morfeo's `mediaQueries` theme slice", + }, + }), + {}, + ), + }; +} + +export function parseSlice(sliceName: Key) { + const slice = theme.getSlice(sliceName); + const values = Object.keys(slice) as (keyof Theme[Key])[]; + + const object = values.reduce((acc, curr) => { + const config = getConfig(sliceName, curr); + return deepMerge(acc, config); + }, {}); + + return deepMerge(object, makeMediaQueriesSlice()); +} diff --git a/apps/cli/src/utils/parser.ts b/apps/cli/src/utils/parser.ts deleted file mode 100644 index 403c13df..00000000 --- a/apps/cli/src/utils/parser.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { - theme as themeHandler, - component as componentHandler, - parsers, - Theme, - ThemeKey, - Component, - Style, -} from '@morfeo/web'; - -function defaultParser( - prefix: string, - slice: Theme[Key], -) { - const keys = Object.keys(slice || {}) as (keyof Theme[Key])[]; - let css = ''; - const object: any = {}; - keys.forEach(alias => { - const property = `--${prefix}-${alias}`; - const value = slice[alias]; - object[alias] = `var(${property})`; - css += `\n\t${property}: ${value};`; - }); - - return { css, object }; -} - -function toKebabCase(string: string) { - const upper = - /(? acc + getStyle(style[curr]), ''); - } - - return style; -} - -function parseStyle(className: string, style: any) { - const keys = Object.keys(style); - let css = `\n.${className} {`; - css += keys.reduce((acc, curr) => { - return acc + `\n\t${toKebabCase(curr)}: ${getStyle(style[curr])};`; - }, ''); - css += `\n}`; - - return css; -} - -export function parser(theme: Theme, name: string) { - const { - components, - colors, - spacings, - sizes, - borderStyles, - borderWidths, - borders, - breakpoints, - fontSizes, - fontWeights, - fonts, - gradients, - letterSpacings, - lineHeights, - mediaQueries, - opacities, - radii, - shadows, - transitions, - zIndices, - } = theme; - - let css = `:root, html[data-morfeo-theme=${name}] {`; - const object: any = { components }; - const defaultSlices = [ - { name: 'colors', prefix: 'color', value: colors }, - { name: 'spacings', prefix: 'spacing', value: spacings }, - { name: 'sizes', prefix: 'size', value: sizes }, - { name: 'borderStyles', prefix: 'border-style', value: borderStyles }, - { name: 'borderWidths', prefix: 'border-width', value: borderWidths }, - { name: 'borders', prefix: 'border', value: borders }, - { name: 'breakpoints', prefix: 'breakpoint', value: breakpoints }, - { name: 'fontSizes', prefix: 'font-size', value: fontSizes }, - { name: 'fontWeights', prefix: 'font-weight', value: fontWeights }, - { name: 'fonts', prefix: 'font', value: fonts }, - { name: 'letterSpacings', prefix: 'letter-spacing', value: letterSpacings }, - { name: 'lineHeights', prefix: 'line-height', value: lineHeights }, - { name: 'opacities', prefix: 'opacity', value: opacities }, - { name: 'radii', prefix: 'radius', value: radii }, - // { name: 'shadows', prefix: 'shadow', value: shadows }, - { name: 'transitions', prefix: 'transition', value: transitions }, - { name: 'zIndices', prefix: 'z-index', value: zIndices }, - ]; - - defaultSlices.forEach(({ name, prefix, value }) => { - const { css: sliceCss, object: sliceObject } = defaultParser(prefix, value); - css += sliceCss; - object[name] = sliceObject; - }); - - css += '\n}'; - - themeHandler.set(object); - const componentKeys = Object.keys(components) as Component[]; - componentKeys.forEach(componentName => { - const { style } = componentHandler(componentName).get(); - const parsedStyle = parsers.resolve(style); - const variants = componentHandler(componentName).getVariants(); - const variantKeys = Object.keys(variants || {}); - css += parseStyle(`morfeo-${componentName}`, parsedStyle); - variantKeys.forEach(variant => { - const { style: variantStyle = {} } = componentHandler( - componentName, - variant as any, - ).get(); - const parsedVariantStyle = parsers.resolve(variantStyle); - css += parseStyle( - `morfeo-${componentName}-${variant}`, - parsedVariantStyle, - ); - }); - }); - - return css; -} diff --git a/apps/cli/src/utils/rmdir.ts b/apps/cli/src/utils/rmdir.ts new file mode 100644 index 00000000..0f0c9c95 --- /dev/null +++ b/apps/cli/src/utils/rmdir.ts @@ -0,0 +1,17 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +export function rmdir(dirPath: string) { + if (!fs.existsSync(dirPath)) { + return; + } + const dirContent = fs.readdirSync(dirPath, { withFileTypes: true }); + dirContent.forEach(current => { + const currentPath = path.join(dirPath, current.name); + if (current.isDirectory()) { + return rmdir(currentPath); + } + fs.unlinkSync(currentPath); + }); + fs.rmdirSync(dirPath); +} diff --git a/apps/cli/test/commands/build.test.ts b/apps/cli/test/commands/build.test.ts new file mode 100644 index 00000000..47fc47cf --- /dev/null +++ b/apps/cli/test/commands/build.test.ts @@ -0,0 +1,65 @@ +import { expect, test } from '@oclif/test'; +import * as path from 'path'; +import * as fs from 'fs'; + +const THEME_PATH = path.join(__dirname, '../utils/theme.ts'); +const BUILD_PATH = path.join(__dirname, '../../build'); +const TOKENS_PATH = path.join(__dirname, '../../tokens'); +const THEME_NAME = 'light'; + +function fileExists(themeName: string) { + const tokenPath = path.join(TOKENS_PATH, `${themeName}.json`); + return fs.existsSync(tokenPath); +} + +describe('build command', () => { + test + .command(['build', THEME_PATH]) + .it(`should create a file called default.json if no name is passed`, () => { + const exists = fileExists('default'); + + expect(exists).to.be.true; + }); + + test + .command(['build', THEME_PATH, '--name', THEME_NAME]) + .it( + `should create a file called ${THEME_NAME}.json inside tokens directory`, + () => { + const exists = fileExists(THEME_NAME); + + expect(exists).to.be.true; + }, + ); + + test + .stdout() + .stderr() + .command(['build']) + .catch(console.log) + .it('should fail if no theme path is passed', ctx => { + expect(ctx.stdout).to.contain( + 'You need to specify the path to the theme like:', + ); + }); +}); + +describe('when build and tokens folder already exists', () => { + before(() => { + const paths = [BUILD_PATH, TOKENS_PATH]; + + paths.forEach(dirPath => { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath); + } + }); + }); + + test + .stdout() + .command(['build', THEME_PATH]) + .it('should remove build and tokens folder', ctx => { + expect(ctx.stdout).to.contain('old build directory removed'); + expect(ctx.stdout).to.contain('old tokens directory removed'); + }); +}); diff --git a/apps/cli/test/mocha.opts b/apps/cli/test/mocha.opts new file mode 100644 index 00000000..7686a30e --- /dev/null +++ b/apps/cli/test/mocha.opts @@ -0,0 +1,5 @@ +--require ts-node/register +--watch-extensions ts +--recursive +--reporter spec +--timeout 15000 diff --git a/apps/cli/test/tsconfig.json b/apps/cli/test/tsconfig.json new file mode 100644 index 00000000..95898fce --- /dev/null +++ b/apps/cli/test/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig", + "compilerOptions": { + "noEmit": true + }, + "references": [ + {"path": ".."} + ] +} diff --git a/apps/cli/test/unit/rmdir.test.ts b/apps/cli/test/unit/rmdir.test.ts new file mode 100644 index 00000000..af4b4daa --- /dev/null +++ b/apps/cli/test/unit/rmdir.test.ts @@ -0,0 +1,32 @@ +import { expect } from '@oclif/test'; +import * as path from 'path'; +import * as fs from 'fs'; +import { rmdir } from '../../src/utils/rmdir'; + +const DIR_PATH = path.join(__dirname, './__FAKE_FOLDER_TEST__'); +const NOT_EXISTING_DIRECTORY = path.join( + __dirname, + './__FAKE_FOLDER_TEST__1__', +); + +describe('rmdir', () => { + beforeEach(() => { + if (fs.existsSync(DIR_PATH)) { + fs.mkdirSync(DIR_PATH); + } + }); + + afterEach(() => { + rmdir(DIR_PATH); + }); + + it('should remove an existing directory', () => { + rmdir(DIR_PATH); + expect(fs.existsSync(DIR_PATH)).to.be.false; + }); + + it('should not do anything if the directory does not exist', () => { + rmdir(NOT_EXISTING_DIRECTORY); + expect(fs.existsSync(NOT_EXISTING_DIRECTORY)).to.be.false; + }); +}); diff --git a/apps/cli/test/utils/theme.ts b/apps/cli/test/utils/theme.ts new file mode 100644 index 00000000..db61a700 --- /dev/null +++ b/apps/cli/test/utils/theme.ts @@ -0,0 +1,178 @@ +export default { + colors: { + grey: '#bdc3c7', + primary: 'white', + danger: '#e74c3c', + secondary: 'black', + success: '#2ecc71', + accent: '#3498db', + warning: '#f39c12', + transparent: 'transparent', + }, + fonts: { + regular: 'Roboto', + }, + gradients: { + primary: { + start: 0, + angle: 90, + end: 100, + colors: ['success', 'accent'], + kind: 'linear', + }, + secondary: { + start: 0, + end: 100, + angle: 0, + colors: ['accent', 'success'], + kind: 'linear', + }, + loading: { + start: 0, + end: 100, + angle: 90, + colors: ['transparent', 'grey', 'transparent'], + kind: 'linear', + }, + }, + radii: { + m: '10px', + round: '50%', + }, + spacings: { + s: '40px', + m: '100px', + }, + lineHeights: { + s: 1.7, + }, + letterSpacings: { + s: 1.6, + }, + fontSizes: { + s: '14px', + }, + sizes: { + s: '10px', + m: '100px', + xl: '200px', + }, + borderWidths: { + s: '2px', + }, + shadows: { + none: { + color: 'transparent', + offset: { width: 0, height: 0 }, + opacity: 0, + elevation: 0, + }, + soft: { + color: 'accent', + offset: { width: 0, height: 2 }, + opacity: 0.2, + radius: 4, + elevation: 2, + }, + medium: { + color: 'black', + offset: { width: 0, height: 3 }, + opacity: 0.3, + radius: 4, + elevation: 3, + }, + strong: { + color: 'black', + offset: { width: 0, height: 4 }, + opacity: 0.4, + radius: 4, + elevation: 4, + }, + }, + breakpoints: { + xs: '300px', + sm: '600px', + md: '900px', + lg: '1300px', + }, + transitions: { + light: 'all 0.5s', + }, + components: { + Box: { + tag: 'div', + style: {}, + }, + Button: { + tag: 'button', + style: { + transition: 'light', + height: 'm', + width: 'm', + bg: { + md: 'danger', + lg: 'primary', + }, + color: 'secondary', + borderRadius: 'm', + borderWidth: 's', + borderStyle: 'solid', + borderColor: 'primary', + '&:hover': { + gradient: 'secondary', + color: 'primary', + }, + }, + props: { + 'aria-label': 'button', + type: 'button', + }, + variants: { + primary: { + props: { + 'aria-label': 'primary button', + }, + style: { + bg: 'secondary', + borderColor: 'primary', + color: 'primary', + '&:hover': { + bg: 'primary', + color: 'secondary', + }, + }, + }, + round: { + style: { borderRadius: 'round' }, + }, + }, + }, + Typography: { + tag: 'p', + style: { + fontFamily: 'regular', + fontSize: 's', + lineHeight: 's', + letterSpacing: 's', + }, + variants: { + h1: { + tag: 'h1', + style: { color: 'red' }, + }, + h2: { + tag: 'h1', + style: { color: 'green' }, + }, + h3: { + tag: 'h3', + style: { color: 'blue' }, + }, + code: { + tag: 'pre', + style: { color: 'primary' }, + }, + }, + }, + }, +}; diff --git a/apps/cli/tokens/color/base.json b/apps/cli/tokens/color/base.json deleted file mode 100644 index 02a99d70..00000000 --- a/apps/cli/tokens/color/base.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "color": { - "base": { - "gray": { - "light" : { "value": "#CCCCCC" }, - "medium": { "value": "#999999" }, - "dark" : { "value": "#111111" } - }, - "red": { "value": "#FF0000" }, - "green": { "value": "#00FF00" } - } - } -} diff --git a/apps/cli/tokens/color/font.json b/apps/cli/tokens/color/font.json deleted file mode 100644 index df0b8483..00000000 --- a/apps/cli/tokens/color/font.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "color": { - "font": { - "base" : { "value": "{color.base.red.value}" }, - "secondary": { "value": "{color.base.green.value}" }, - "tertiary" : { "value": "{color.base.gray.light.value}" } - } - } -} diff --git a/apps/cli/tokens/default.json b/apps/cli/tokens/default.json new file mode 100644 index 00000000..f9c7d91a --- /dev/null +++ b/apps/cli/tokens/default.json @@ -0,0 +1,174 @@ +{ + "colors": { + "grey": { + "value": "#bdc3c7", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "primary": { + "value": "white", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "danger": { + "value": "#e74c3c", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "secondary": { + "value": "black", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "success": { + "value": "#2ecc71", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "accent": { + "value": "#3498db", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "warning": { + "value": "#f39c12", + "comment": "value referred to morfeo's `colors` theme slice" + }, + "transparent": { + "value": "transparent", + "comment": "value referred to morfeo's `colors` theme slice" + } + }, + "mediaQueries": { + "xs": { + "value": "\"@media (min-width: 300px)\"", + "comment": "value referred to morfeo's `mediaQueries` theme slice" + }, + "sm": { + "value": "\"@media (min-width: 600px)\"", + "comment": "value referred to morfeo's `mediaQueries` theme slice" + }, + "md": { + "value": "\"@media (min-width: 900px)\"", + "comment": "value referred to morfeo's `mediaQueries` theme slice" + }, + "lg": { + "value": "\"@media (min-width: 1300px)\"", + "comment": "value referred to morfeo's `mediaQueries` theme slice" + } + }, + "fonts": { + "regular": { + "value": "Roboto", + "comment": "value referred to morfeo's `fonts` theme slice" + } + }, + "gradients": { + "primary": { + "value": "linear-gradient(90deg, #2ecc71 0%, #3498db 100%)", + "comment": "value referred to morfeo's `gradients` theme slice" + }, + "secondary": { + "value": "linear-gradient(0deg, #3498db 0%, #2ecc71 100%)", + "comment": "value referred to morfeo's `gradients` theme slice" + }, + "loading": { + "value": "linear-gradient(90deg, transparent 0%, #bdc3c7 50%, transparent 100%)", + "comment": "value referred to morfeo's `gradients` theme slice" + } + }, + "radii": { + "m": { + "value": "10px", + "comment": "value referred to morfeo's `radii` theme slice" + }, + "round": { + "value": "50%", + "comment": "value referred to morfeo's `radii` theme slice" + } + }, + "spacings": { + "s": { + "value": "40px", + "comment": "value referred to morfeo's `spacings` theme slice" + }, + "m": { + "value": "100px", + "comment": "value referred to morfeo's `spacings` theme slice" + } + }, + "lineHeights": { + "s": { + "value": 1.7, + "comment": "value referred to morfeo's `lineHeights` theme slice" + } + }, + "letterSpacings": { + "s": { + "value": 1.6, + "comment": "value referred to morfeo's `letterSpacings` theme slice" + } + }, + "fontSizes": { + "s": { + "value": "14px", + "comment": "value referred to morfeo's `fontSizes` theme slice" + } + }, + "sizes": { + "s": { + "value": "10px", + "comment": "value referred to morfeo's `sizes` theme slice" + }, + "m": { + "value": "100px", + "comment": "value referred to morfeo's `sizes` theme slice" + }, + "xl": { + "value": "200px", + "comment": "value referred to morfeo's `sizes` theme slice" + } + }, + "borderWidths": { + "s": { + "value": "2px", + "comment": "value referred to morfeo's `borderWidths` theme slice" + } + }, + "shadows": { + "none": { + "value": "0px 0px 0px transparent", + "comment": "value referred to morfeo's `shadows` theme slice" + }, + "soft": { + "value": "0px 2px 4px #3498db", + "comment": "value referred to morfeo's `shadows` theme slice" + }, + "medium": { + "value": "0px 3px 4px black", + "comment": "value referred to morfeo's `shadows` theme slice" + }, + "strong": { + "value": "0px 4px 4px black", + "comment": "value referred to morfeo's `shadows` theme slice" + } + }, + "breakpoints": { + "xs": { + "value": "300px", + "comment": "value referred to morfeo's `breakpoints` theme slice" + }, + "sm": { + "value": "600px", + "comment": "value referred to morfeo's `breakpoints` theme slice" + }, + "md": { + "value": "900px", + "comment": "value referred to morfeo's `breakpoints` theme slice" + }, + "lg": { + "value": "1300px", + "comment": "value referred to morfeo's `breakpoints` theme slice" + } + }, + "transitions": { + "light": { + "value": "all 0.5s", + "comment": "value referred to morfeo's `transitions` theme slice" + } + } +} \ No newline at end of file diff --git a/apps/cli/tokens/size/font.json b/apps/cli/tokens/size/font.json deleted file mode 100644 index 24e7b803..00000000 --- a/apps/cli/tokens/size/font.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "size": { - "font": { - "small" : { - "value": "0.75", - "comment": "the small size of the font" - }, - "medium": { - "value": "1", - "comment": "the medium size of the font" - }, - "large" : { - "value": "2", - "comment": "the large size of the font" - }, - "base" : { - "value": "{size.font.medium.value}", - "comment": "the base size of the font" - } - } - } -} diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json index b4c5d768..9c2ead54 100644 --- a/apps/cli/tsconfig.json +++ b/apps/cli/tsconfig.json @@ -1,12 +1,10 @@ { + "extends": "../../tsconfig.base.json", "compilerOptions": { - "declaration": true, - "importHelpers": true, - "module": "commonjs", + "composite": true, "outDir": "lib", "rootDir": "src", - "strict": true, - "target": "es2017" + "module": "commonjs", }, "include": [ "src/**/*" diff --git a/apps/web-sandbox/src/theme.ts b/apps/web-sandbox/src/theme.ts index 0dcd7cad..e8c35d48 100644 --- a/apps/web-sandbox/src/theme.ts +++ b/apps/web-sandbox/src/theme.ts @@ -33,7 +33,7 @@ export const lightTheme = { warning: '#f39c12', transparent: 'transparent', }, - fontFamilies: { + fonts: { regular: 'Roboto', }, gradients, diff --git a/docs/src/theme/theme.js b/docs/src/theme/theme.js index ece6381f..709d240f 100644 --- a/docs/src/theme/theme.js +++ b/docs/src/theme/theme.js @@ -33,7 +33,7 @@ export const lightTheme = { warning: '#f39c12', transparent: 'transparent', }, - fontFamilies: { + fonts: { regular: 'Roboto', }, gradients, diff --git a/package.json b/package.json index 6b0f6c1c..848f35ad 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ }, "scripts": { "clean": "lerna clean --yes", - "build": "lerna run build", + "build": "lerna run build && npm run build:commonjs", "build:commonjs": "lerna run build:commonjs", "watch": "lerna run watch", "reset": "npm run clean && npm i && lerna bootstrap && npm run build", diff --git a/packages/core/package.json b/packages/core/package.json index d7bb7a93..f2dd1439 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,8 +7,8 @@ "private": false, "version": "0.1.8", "license": "MIT", - "main": "build/index.js", "module": "build/index.js", + "main": "commonjs/index.js", "types": "build/index", "typings": "build/index", "keywords": [ @@ -19,7 +19,7 @@ ], "scripts": { "build": "rimraf build && tsc", - "build:commonjs": "rimraf build && tsc --module CommonJS", + "build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs", "watch": "tsc -w" }, "dependencies": { diff --git a/packages/fonts/package.json b/packages/fonts/package.json index 723b4d7d..51b3177a 100644 --- a/packages/fonts/package.json +++ b/packages/fonts/package.json @@ -7,7 +7,7 @@ "private": false, "version": "0.1.8", "license": "MIT", - "main": "build/index.js", + "main": "commonjs/index.js", "module": "build/index.js", "types": "build/index", "typings": "build/index", @@ -21,6 +21,7 @@ ], "scripts": { "build": "rimraf build && tsc", + "build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs", "watch": "tsc -w" }, "publishConfig": { diff --git a/packages/jss/package.json b/packages/jss/package.json index de0b37ae..002f33aa 100644 --- a/packages/jss/package.json +++ b/packages/jss/package.json @@ -7,7 +7,7 @@ "private": false, "version": "0.1.8", "license": "MIT", - "main": "build/index.js", + "main": "commonjs/index.js", "module": "build/index.js", "types": "build/index", "typings": "build/index", @@ -21,7 +21,7 @@ ], "scripts": { "build": "rimraf build && tsc", - "build:commonjs": "rimraf build && tsc --module CommonJS", + "build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs", "watch": "tsc -w" }, "dependencies": { diff --git a/packages/spec/package.json b/packages/spec/package.json index a07ec632..1a67fccb 100644 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -7,7 +7,7 @@ "private": false, "version": "0.1.8", "license": "MIT", - "main": "build/index.js", + "main": "commonjs/index.js", "module": "build/index.js", "types": "build/index", "typings": "build/index", @@ -19,7 +19,7 @@ ], "scripts": { "build": "rimraf build && tsc", - "build:commonjs": "rimraf build && tsc --module CommonJS", + "build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs", "watch": "tsc -w" }, "publishConfig": { diff --git a/packages/web/package.json b/packages/web/package.json index 9317e37e..ad69cd85 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -7,7 +7,7 @@ "private": false, "version": "0.1.8", "license": "MIT", - "main": "build/index.js", + "main": "commonjs/index.js", "module": "build/index.js", "types": "build/index", "typings": "build/index", @@ -19,6 +19,7 @@ ], "scripts": { "build": "rimraf build && tsc", + "build:commonjs": "rimraf commonjs && tsc --module CommonJS --outdir commonjs", "watch": "tsc -w" }, "dependencies": {