Skip to content

Commit

Permalink
feat: compose command wip #40
Browse files Browse the repository at this point in the history
  • Loading branch information
mauroerta committed Sep 20, 2021
1 parent 2c3b774 commit d83a154
Show file tree
Hide file tree
Showing 14 changed files with 540 additions and 178 deletions.
5 changes: 4 additions & 1 deletion docs/docs/Features/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ description: Features > CLI
If you don't need to generate styles `run time` or you don't want to use `javascript` at all, but you still want to benefit the morfeo eco-system and a centralized theme,
the `morfeo CLI` is what you need!

Morfeo CLI has (for now) only one command called `build`, with this command you can generate CSS based on a theme.
Morfeo CLI has 2 commands:

- `build` to generate CSS based on your themes
- `compose` to create a theme from multiple `.morfeo.ts` files

## Example

Expand Down
79 changes: 62 additions & 17 deletions packages/cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@oclif/config": "^1.17.0",
"@oclif/plugin-help": "^3.2.2",
"change-case": "^4.1.2",
"chokidar": "^3.5.2",
"glob": "^7.1.7",
"tslib": "^1.14.1"
},
"devDependencies": {
Expand Down
65 changes: 65 additions & 0 deletions packages/cli/src/commands/compose.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Command, flags } from '@oclif/command';
import * as glob from 'glob';
import * as path from 'path';
import {
watchFiles,
composeSlice,
updateThemes,
getConfiguration,
} from '../utils';

export default class Compose extends Command {
static description = 'compose morfeo style files into a single theme';

static examples = [`$ morfeo compose`, `$ morfeo compose --watch`];

static usage = 'build';

static flags = {
help: flags.help({ char: 'h', description: Compose.description }),
watch: flags.boolean({
char: 'w',
description: 'watch file changes',
default: false,
required: false,
}),
config: flags.string({
char: 'c',
description: 'the path to the configuration file',
default: '.morfeorc',
required: false,
}),
};

static args = [];

async run() {
const { flags } = this.parse(Compose);
const { config } = flags;
const { themes } = getConfiguration(config);

const files = glob
.sync('**/*.morfeo.{ts,js}', {})
.map(file => path.join(process.cwd(), file));

if (files.length === 0) {
this.error('No *.morfeo.{ts|js} files found');
}

const compose = (list: string[]) => {
console.clear();
console.log(` - ${list.join(',\n - ')}`);
const mergedThemes = composeSlice(themes || {}, list);
updateThemes(themes || {}, mergedThemes);
console.log(`\n\n\n\n^ + C to exit`);
};

if (flags.watch) {
watchFiles(files, (file: string) => {
compose([file]);
});
}

compose(files);
}
}
73 changes: 73 additions & 0 deletions packages/cli/src/utils/composeSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Theme, ThemeKey } from '@morfeo/web';
import * as path from 'path';

function resolvePath(filePath: string) {
return path.join(process.cwd(), filePath);
}

const themeKeys: ThemeKey[] = [
'sizes',
'radii',
'colors',
'borders',
'shadows',
'zIndices',
'spacings',
'opacities',
'fontSizes',
'transitions',
'breakpoints',
'lineHeights',
'fontWeights',
'borderWidths',
'borderStyles',
'mediaQueries',
'letterSpacings',
];

export function composeSlice(themes: Record<string, string>, files: string[]) {
const objects = files.map(file => {
delete require.cache[file];
const [defaultName] = path.basename(file).split('.') as ThemeKey[];
const {
default: value,
theme,
sliceName = defaultName,
componentName = defaultName,
} = require(file);

if (themeKeys.includes(defaultName) || themeKeys.includes(sliceName)) {
return { value, theme, sliceName };
}

return { value, theme, componentName };
});

const themeNames = Object.keys(themes);
let themeObjects = themeNames.reduce((acc, themeName) => {
const required = require(resolvePath(themes[themeName]));
const currentTheme = required.default ? required.default : required;

return {
...acc,
[themeName]: currentTheme,
};
}, {});

objects.forEach(({ value, theme, sliceName, componentName }) => {
const filteredThemeNames = theme ? [theme] : themeNames;

filteredThemeNames.forEach(themeName => {
themeObjects[themeName] = {
...themeObjects[themeName],
...(sliceName ? { [sliceName]: value } : {}),
components: {
...themeObjects[themeName].components,
...(componentName ? { [componentName]: value } : {}),
},
};
});
});

return themeObjects as Record<string, Theme>;
}
4 changes: 4 additions & 0 deletions packages/cli/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from './watchFiles';
export * from './buildTheme';
export * from './updateThemes';
export * from './composeSlice';
export * from './getConfiguration';
31 changes: 31 additions & 0 deletions packages/cli/src/utils/updateThemes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Theme } from '@morfeo/web';
import * as fs from 'fs';
import * as path from 'path';

export function updateThemes<Key extends string>(
themes: Record<Key, string>,
themeObjects: Record<Key, Theme>,
) {
const themeNames = Object.keys(themes) as Key[];

function makeThemeFile(themePath: string, themeObject: Theme) {
const stringified = JSON.stringify(themeObject, undefined, 2);
const ext = path.extname(themePath);
if (ext.includes('json')) {
return stringified;
}

if (ext.includes('js')) {
return `module.exports = ${stringified}`;
}

return `export default ${stringified}`;
}

themeNames.forEach(themeName => {
fs.writeFileSync(
path.join(process.cwd(), themes[themeName]),
makeThemeFile(themes[themeName], themeObjects[themeName]),
);
});
}
Loading

0 comments on commit d83a154

Please sign in to comment.