Skip to content

Commit

Permalink
feat: improved build command
Browse files Browse the repository at this point in the history
  • Loading branch information
mauroerta committed Jul 28, 2021
1 parent 019f4fb commit 00084bc
Show file tree
Hide file tree
Showing 18 changed files with 407 additions and 263 deletions.
2 changes: 1 addition & 1 deletion apps/cli/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/.nyc_output
/dist
/lib
/morfeo
/test/builds
/tmp
/yarn.lock
node_modules
16 changes: 9 additions & 7 deletions apps/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,25 @@ USAGE
# Commands

<!-- commands -->
* [`morfeo build path/to/theme.(ts|js|json) [--name="theme name"]`](#morfeo-build-pathtothemetsjsjson---nametheme-name)
* [`morfeo build path/to/theme`](#morfeo-build-pathtotheme)
* [`morfeo help [COMMAND]`](#morfeo-help-command)

## `morfeo build path/to/theme.(ts|js|json) [--name="theme name"]`
## `morfeo build path/to/theme`

build design tokens based on your theme
build css styles based on your themes

```
USAGE
$ morfeo build path/to/theme.(ts|js|json) [--name="theme name"]
$ morfeo build path/to/theme
OPTIONS
-h, --help show CLI help
-n, --name=name [default: default] an identifier for the passed theme, for example "light", "dark"
-b, --build=build the path where the generated css files will be placed
-c, --config=config [default: .morfeorc] the path to the configuration file
-h, --help build css styles based on your themes
-n, --name=name [default: default] an identifier for the passed theme, for example "light", "dark"
EXAMPLE
$ morfeo build path/to/theme.ts
$ morfeo build path/to/theme.ts --name="light"
```

_See code: [src/commands/build.ts](https://github.com/VLK-STUDIO/morfeo/blob/v0.0.0/src/commands/build.ts)_
Expand Down
28 changes: 20 additions & 8 deletions apps/cli/src/commands/build.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import * as path from 'path';
import { Command, flags } from '@oclif/command';
import { parseTheme } from '../utils';
import { buildTheme } from '../utils';
import { theme } from '@morfeo/web';

export default class Build extends Command {
static description = 'build design tokens based on your theme';
static description = 'build css styles based on your themes';

static examples = [`$ morfeo build path/to/theme.ts`];
static examples = [`$ morfeo build path/to/theme.ts --name="light"`];

static usage = 'build path/to/theme.(ts|js|json) [--name="theme name"]';
static usage = 'build path/to/theme';

static flags = {
help: flags.help({ char: 'h' }),
help: flags.help({ char: 'h', description: Build.description }),
name: flags.string({
char: 'n',
description:
'an identifier for the passed theme, for example "light", "dark"',
default: 'default',
}),
build: flags.string({
char: 'b',
description: 'the path where the generated css files will be placed',
required: false,
}),
config: flags.string({
char: 'c',
description: 'the path to the configuration file',
default: '.morfeorc',
required: false,
}),
};

static args = [{ name: 'theme' }];
Expand All @@ -32,16 +43,17 @@ export default class Build extends Command {

async run() {
const { args, flags } = this.parse(Build);
const { name, build, config } = flags;

const themePath = args.theme;
if (!themePath) {
this.printMissingThemeError();
}

const localTheme = require(path.resolve(themePath));
const localTheme = require(path.join(process.cwd(), themePath));

theme.set(localTheme.default);
theme.set(localTheme.default ? localTheme.default : localTheme);

parseTheme(flags.name);
buildTheme({ name, buildPath: build, configPath: config });
}
}
2 changes: 1 addition & 1 deletion apps/cli/src/constants/maps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type SliceToBeParsed = {
};

/**
* The values of these slices can't be represent as css variables
* The values of these slices can't be represented as css variables
*/
export const SLICES_TO_BE_EXCLUDED: ThemeKey[] = ['components', 'mediaQueries'];

Expand Down
1 change: 1 addition & 0 deletions apps/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { run } from '@oclif/command';
export * from './types';
24 changes: 24 additions & 0 deletions apps/cli/src/types/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type BuildConfig = {
/**
* an identifier for the passed theme, for example "light", "dark"
*/
name: string;
/**
* the path where the generated css files will be placed
* @default `morfeo`
*/
buildPath?: string;
/**
* the path to the configuration file.
* valid extensions are `js`, `ts`, `json` or `no extension`
* @default `./.morfeorc`
*/
configPath?: string;
};

export type MorfeoConfig = {
/**
* the path where the generated css files will be placed
*/
buildPath: string;
};
1 change: 1 addition & 0 deletions apps/cli/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './config';
66 changes: 66 additions & 0 deletions apps/cli/src/utils/buildTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { theme, ThemeKey } from '@morfeo/web';
import * as path from 'path';
import { SLICES_TO_BE_EXCLUDED } from '../constants';
import { getCSSClasses } from './getCSSClasses';
import { safeWrite } from './safeWrite';
import { parseSlice } from './parseSlice';
import { BuildConfig } from '../types';
import { getConfiguration } from './getConfiguration';

function getStylePaths(buildPath: string) {
const variablesPath = path.join(process.cwd(), buildPath, 'variables.css');
const stylePath = path.join(process.cwd(), buildPath, 'style.css');

return {
variablesPath,
stylePath,
};
}

function wrapWithScope(name: string, css: string) {
const parsedCss = css.replace(/\n/g, '\n\t');
return `:root, html[data-morfeo-theme="${name}"] {\n\t${parsedCss}\n}\n`;
}

export function buildTheme(config: BuildConfig) {
const { name, buildPath } = getConfiguration(config);

const currentTheme = theme.get();
const slices = Object.keys(currentTheme) as ThemeKey[];
const filtered = slices.filter(
slice => !SLICES_TO_BE_EXCLUDED.includes(slice),
);
let cssText = '';

// `breakpoints` excluded since is not possible to have variables in media queries
const { breakpoints, ...newTheme } = filtered.reduce((acc, curr) => {
const { css, object } = parseSlice(curr);
cssText += css;
return {
...acc,
[curr]: object,
};
}, currentTheme);

const { stylePath, variablesPath } = getStylePaths(buildPath as string);

safeWrite(variablesPath, wrapWithScope(name, cssText));

/**
* Setting the new theme where values of slices are css variables
*/
theme.set(newTheme);

/**
* getCSSClasses will return a css class for each component and foreach variant using
* the new theme with css variables as values
*/
const componentStyle = getCSSClasses();

safeWrite(stylePath, componentStyle);

/**
* restored the old theme
*/
theme.set(currentTheme);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { theme, getStyles, Component } from '@morfeo/web';
import * as fs from 'fs';
import * as path from 'path';

const CSS_PATH = path.join(__dirname, '../../morfeo/style.css');
function getComponentCSS(componentName: Component, variant?: string) {
let componentId = `morfeo-${componentName.toLowerCase()}`;

function appendCss(componentName: Component, variant?: string) {
const componentId = `morfeo-${componentName.toLowerCase()}${
variant ? `-${variant.toLowerCase()}` : ''
}`;
if (variant) {
componentId += `-${variant.toLowerCase()}`;
}

const { sheet } = getStyles(
{ [componentName]: { componentName, variant } },
Expand All @@ -18,24 +16,24 @@ function appendCss(componentName: Component, variant?: string) {

const componentCss = sheet.toString();

fs.appendFileSync(CSS_PATH, `\n${componentCss}\n`);
return `\n${componentCss}\n`;
}

export function makeClasses() {
export function getCSSClasses() {
const { components } = theme.get();
const componentNames = Object.keys(components) as Component[];

const importLine = `@import "./variables.css";\n`;

fs.writeFileSync(CSS_PATH, importLine);
let css = `@import "./variables.css";\n`;

componentNames.forEach(componentName => {
const { variants } = components[componentName];
const variantKeys = Object.keys(variants || {});
appendCss(componentName);
css += getComponentCSS(componentName);

variantKeys.forEach(variant => {
appendCss(componentName, variant);
css += getComponentCSS(componentName, variant);
});
});

return css;
}
29 changes: 29 additions & 0 deletions apps/cli/src/utils/getConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as fs from 'fs';
import * as path from 'path';
import { BuildConfig, MorfeoConfig } from '../types';

const MORFEO_CONFIG_FILE_EXTENSIONS = ['.js', '.ts', '.json', ''];

export function getConfiguration({
configPath,
...rest
}: Partial<BuildConfig>): BuildConfig {
const morfeoConfigPath = path.join(process.cwd(), configPath as string);
let morfeoConfig: MorfeoConfig = {} as any;
const configExists = MORFEO_CONFIG_FILE_EXTENSIONS.some(extension => {
return fs.existsSync(`${morfeoConfigPath}${extension}`);
});

if (configExists) {
const imported = require(morfeoConfigPath);
morfeoConfig = imported.default ? imported.default : imported;
}

const { buildPath } = morfeoConfig;

return {
...rest,
buildPath: rest.buildPath || buildPath,
configPath,
} as BuildConfig;
}
2 changes: 1 addition & 1 deletion apps/cli/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './parseTheme';
export * from './buildTheme';
7 changes: 4 additions & 3 deletions apps/cli/src/utils/parseSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function getValue<Key extends ThemeKey>(
export function parseSlice<Key extends ThemeKey>(sliceName: Key) {
const slice = theme.getSlice(sliceName);
const aliases = Object.keys(slice) as (keyof Theme[Key])[];
let css = ``;
let css: string[] = [];
let object = {};

aliases.forEach(curr => {
Expand All @@ -56,8 +56,9 @@ export function parseSlice<Key extends ThemeKey>(sliceName: Key) {
...object,
[curr]: value,
};
css += `\n\t${variableName}: ${cssValue};`;

css.push(`${variableName}: ${cssValue};`);
}, object);

return { css, object };
return { css: css.join('\n'), object };
}
37 changes: 0 additions & 37 deletions apps/cli/src/utils/parseTheme.ts

This file was deleted.

Loading

0 comments on commit 00084bc

Please sign in to comment.