├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── LICENSE.md
├── README.md
├── bin
└── cli.js
├── docs
└── lab-json.md
├── examples
├── lab.json
└── theme.json
├── lib
├── createIndex.js
├── index.js
└── templates
│ ├── composite-react.js
│ ├── composite-vue.js
│ ├── cxs.js
│ ├── emotion.js
│ ├── fela.js
│ ├── glamorous.js
│ ├── index.js
│ ├── styledComponents.js
│ ├── util.js
│ └── vue.js
├── package.json
└── test
├── fixture.json
├── modules.js
├── snapshots
├── modules.js.md
├── modules.js.snap
├── templates.js.md
├── templates.js.snap
├── vue.js.md
└── vue.js.snap
├── templates.js
└── vue.js
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | .nyc_output
3 | coverage
4 | coverage.lcov
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | examples
2 | docs
3 | coverage
4 | .nyc_output
5 | test
6 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 8.9
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | # The MIT License (MIT)
3 | Copyright (c) 2017 Compositor, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # lab-cli
3 |
4 | Command line utilities and exporting module for [Compositor Lab][lab]
5 |
6 | [![Build Status][build-badge]][build]
7 |
8 | [build-badge]: https://img.shields.io/travis/c8r/lab-cli/master.svg?style=flat-square
9 | [build]: https://travis-ci.org/c8r/lab-cli
10 |
11 | ```sh
12 | npm install @compositor/lab
13 | ```
14 |
15 | ## CLI Usage
16 |
17 | Compile `lab.json` to React components:
18 |
19 | ```sh
20 | lab --out-dir dist/
21 | ```
22 |
23 | Watch for changes:
24 |
25 | ```sh
26 | lab --out-dir dist/ --watch
27 | ```
28 |
29 | ### Lab Packages
30 |
31 | Lab projects can be published in a way that allows them to be installed and imported into other Lab projects from the app.
32 |
33 | Export `index.js`, `lab.json`, and `theme.json` for packaging Lab projects:
34 |
35 | ```sh
36 | lab --pkg --out-dir dist/
37 | ```
38 |
39 | ### CLI Options
40 |
41 | ```
42 | -d --out-dir Output directory
43 | -w --watch Watch for changes
44 | --pkg Include index.js, lab.json, and theme.json in output
45 | ```
46 |
47 | ## Node Usage
48 |
49 | The Node API is used by the Lab app to export lab components to React and other formats.
50 |
51 | `lab(config, [options])`
52 |
53 | Returns an array of objects for writing to files.
54 |
55 | ```js
56 | const fs = require('fs')
57 | const path = require('path')
58 | const lab = require('@compositor/lab')
59 | const config = require('./lab.json')
60 |
61 | const modules = lab(config)
62 |
63 | modules.forEach(mod => {
64 | const filename = path.join(__dirname, 'dist', mod.name + '.js')
65 | fs.writeFile(filename, mod.module, err => {
66 | if (err) console.log(err)
67 | })
68 | })
69 | ```
70 |
71 | ### Options
72 |
73 | #### `library`
74 |
75 | A string key to choose an output mode, one of the following:
76 |
77 | - [`styled-components`][sc]
78 | - [`glamorous`][glamorous]
79 | - [`emotion`][emotion]
80 | - [`fela`][fela]
81 | - [`cxs`][cxs]
82 | - [`vue`][vue] (alpha)
83 |
84 | #### `harmony`
85 |
86 | Boolean to export the template without transpiling to ES5 syntax.
87 |
88 | ## Templates
89 |
90 | Currently this module uses templates to output to different formats.
91 | These templates can be found in [`lib/templates/`](https://github.com/c8r/lab-cli/tree/master/lib/templates).
92 | Using an AST for output with tools like Babel is also possible,
93 | but templates were used in an attempt to make it easier to contribute to this project.
94 |
95 | ## lab.json Data Structure
96 |
97 | See [`docs/lab-json.md`](docs/lab-json.md)
98 |
99 | ## Roadmap
100 |
101 | - Vue.js export (currently in alpha)
102 | - Atomic CSS export
103 | - Support for using third party CSS libraries
104 |
105 | [Made by Compositor](https://compositor.io)
106 | |
107 | [MIT License](LICENSE.md)
108 |
109 | [lab]: https://compositor.io/lab/
110 | [sc]: https://styled-components.com
111 | [glamorous]: https://github.com/paypal/glamorous
112 | [emotion]: https://github.com/emotion-js/emotion
113 | [fela]: http://fela.js.org
114 | [cxs]: https://github.com/jxnblk/cxs
115 | [vue]: https://vuejs.org
116 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 | const fs = require('fs')
3 | const path = require('path')
4 | const meow = require('meow')
5 | const createModules = require('../lib')
6 | const writeFile = require('write-file-atomic')
7 | const chokidar = require('chokidar')
8 | const findUp = require('find-up')
9 | const chalk = require('chalk')
10 | const ora = require('ora')
11 |
12 | const pkg = require('../package.json')
13 | require('update-notifier')({ pkg }).notify()
14 |
15 | const cli = meow(`
16 | Usage
17 | $ lab --out-dir src/
18 | $ lab d src/ --watch
19 |
20 | Options
21 | -d --out-dir Output directory
22 | -w --watch Watch for changes
23 | -l --library Override library defined in lab.json
24 | --pkg Include index.js, lab.json, and theme.json in output
25 | `, {
26 | alias: {
27 | d: 'outDir',
28 | w: 'watch',
29 | l: 'library'
30 | }
31 | })
32 |
33 | const [ file ] = cli.input
34 |
35 | const badge = chalk.black.bgCyan(' L A B ')
36 | console.log(badge, chalk.cyan('@compositor/lab'))
37 |
38 | const spinner = ora().start()
39 | const filepath = file
40 | ? path.join(process.cwd(), file)
41 | : findUp.sync('lab.json')
42 |
43 | if (!filepath || !fs.existsSync(filepath)) {
44 | spinner.fail('no lab.json file found')
45 | process.exit(1)
46 | }
47 |
48 | if (!cli.flags.outDir) {
49 | spinner.fail('no output directory specified')
50 | process.exit(1)
51 | }
52 |
53 | const config = require(filepath)
54 |
55 | const length = Array.isArray(config.components)
56 | ? config.components.length
57 | : 0
58 |
59 | if (length) {
60 | spinner.succeed(length + ' components found')
61 | } else {
62 | spinner.fail('no components found in lab.json')
63 | process.exit(0)
64 | }
65 |
66 | const write = (file, content) => {
67 | writeFile(file, content, err => {
68 | if (err) {
69 | spinner.fail(err)
70 | process.exit(1)
71 | }
72 | })
73 | }
74 |
75 | let cache = []
76 |
77 | const filterChanges = component => {
78 | const cached = cache.find(c => c.name === component.name)
79 | if (!cached) return true
80 | const a = JSON.stringify(cached)
81 | const b = JSON.stringify(component)
82 | return a !== b
83 | }
84 |
85 | const parseConfig = (config, options) => {
86 | const changes = config.components
87 | .filter(filterChanges)
88 | .map(c => c.name)
89 |
90 | if (options.pkg) {
91 | changes.push('index')
92 | changes.push('lab')
93 | changes.push('theme')
94 | }
95 |
96 | const modules = createModules(config, Object.assign({}, config, options))
97 | modules
98 | .filter(m => changes.includes(m.name))
99 | .forEach(mod => {
100 | const filename = path.join(cli.flags.outDir, mod.name + '.js')
101 | write(filename, mod.module)
102 | spinner.succeed(filename + ' written')
103 | })
104 |
105 | // copy theme.json and lab.json to output dir
106 | if (options.pkg) copyJSON()
107 | cache = config.components
108 | }
109 |
110 | const copyJSON = () => {
111 | const themeFile = findUp.sync('theme.json')
112 | const theme = themeFile ? require(themeFile) : null
113 | const labOutPath = path.join(cli.flags.outDir, 'lab.json')
114 | const themeOutPath = path.join(cli.flags.outDir, 'theme.json')
115 | write(labOutPath, JSON.stringify(config))
116 | write(themeOutPath, JSON.stringify(theme))
117 | }
118 |
119 | if (!fs.existsSync(cli.flags.outDir)) {
120 | fs.mkdirSync(cli.flags.outDir)
121 | }
122 |
123 | parseConfig(config, cli.flags)
124 |
125 | if (cli.flags.watch) {
126 | const watcher = chokidar.watch(filepath)
127 | spinner.info('watching for changes')
128 |
129 | watcher.on('change', file => {
130 | spinner.start('updating...')
131 | delete require.cache[require.resolve(file)]
132 | const next = require(file)
133 | parseConfig(next, cli.flags)
134 | spinner.succeed('updated')
135 | })
136 | } else {
137 | spinner.succeed('done')
138 | }
139 |
--------------------------------------------------------------------------------
/docs/lab-json.md:
--------------------------------------------------------------------------------
1 |
2 | # lab.json
3 |
4 | These properties are used in the `lab.json` format to create style component primitives.
5 |
6 | - `name` (string) unique name for the component, must be Capitalized and a valid JavaScript variable name
7 | - `type` (string) HTML or SVG tag name or another component name to use as an extension
8 | - `style` (object) plain JavaScript object for static CSS styles
9 | - `props` (object) default props to be passed to the component
10 | - `system` (array) array of strings that reference style functions from [styled-system][styled-system]
11 | - `examples` (array) array of JSX strings for use in documentation and testing
12 | - `description` (string) human readable description of the component
13 | - `keywords` (array) array of taxonomic strings for categorization
14 |
15 | [styled-system]: https://github.com/jxnblk/styled-system
16 |
--------------------------------------------------------------------------------
/examples/lab.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lab-cli",
3 | "library": "styled-components",
4 | "harmony": true,
5 | "components": [
6 | {
7 | "name": "Button",
8 | "type": "button",
9 | "props": {
10 | "fontSize": 1,
11 | "px": 4,
12 | "py": 2,
13 | "color": "white",
14 | "bg": "blue"
15 | },
16 | "style": {
17 | "display": "inline-block",
18 | "fontFamily": "inherit",
19 | "borderWidth": 0,
20 | "borderRadius": "4px",
21 | "appearance": "none"
22 | },
23 | "examples": [
24 | "Hello "
25 | ],
26 | "system": []
27 | },
28 | {
29 | "name": "Heading",
30 | "type": "h2",
31 | "props": {
32 | "fontSize": 5,
33 | "m": 0,
34 | "color": "blue"
35 | },
36 | "style": {
37 | "fontWeight": "bold",
38 | "lineHeight": 1.25
39 | },
40 | "examples": [
41 | "Hello "
42 | ],
43 | "system": []
44 | },
45 | {
46 | "name": "Box",
47 | "type": "div",
48 | "props": {},
49 | "style": {},
50 | "examples": [
51 | "Hello "
52 | ]
53 | },
54 | {
55 | "name": "Header",
56 | "imports": [
57 | "Box",
58 | "Heading"
59 | ],
60 | "jsx": "{props.heading} ",
61 | "examples": [
62 | ""
63 | ]
64 | }
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/examples/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "fonts": [],
3 | "space": [
4 | 0,
5 | 4,
6 | 8,
7 | 16,
8 | 32,
9 | 64,
10 | 128,
11 | 256
12 | ],
13 | "fontSizes": [
14 | 12,
15 | 14,
16 | 16,
17 | 20,
18 | 24,
19 | 32,
20 | 48,
21 | 64,
22 | 72,
23 | 96
24 | ],
25 | "colors": {
26 | "black": "#000",
27 | "blue": "#07c"
28 | }
29 | }
--------------------------------------------------------------------------------
/lib/createIndex.js:
--------------------------------------------------------------------------------
1 | module.exports = components =>
2 | ['lab', 'theme', ...components.map(conf => conf.name)]
3 | .map(name => `export { default as ${name} } from './${name}'`)
4 | .join('\n')
5 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | const { format } = require('prettier')
2 | const { transform } = require('babel-core')
3 | const createIndex = require('./createIndex')
4 | const templates = require('./templates')
5 | const compositeReact = require('./templates/composite-react')
6 | const compositeVue = require('./templates/composite-vue')
7 | const {
8 | stringifyObject,
9 | getExtensionImport,
10 | getComp,
11 | getSystemFuncs,
12 | getSystemExpressions
13 | } = require('./templates/util')
14 |
15 | const compile = code =>
16 | transform(code, {
17 | presets: [
18 | require('babel-preset-env'),
19 | require('babel-preset-stage-0'),
20 | require('babel-preset-react')
21 | ]
22 | }).code
23 |
24 | const parse = (config) => {
25 | const {
26 | style = {},
27 | props = {},
28 | system = [],
29 | type = 'div'
30 | } = config
31 | return Object.assign({}, config, {
32 | style,
33 | props,
34 | systemFunctions: getSystemFuncs(system),
35 | systemExpressions: getSystemExpressions(system),
36 | extensionImport: getExtensionImport(type),
37 | type: getComp(type),
38 | styleString: stringifyObject(style),
39 | propsString: stringifyObject(props)
40 | })
41 | }
42 |
43 | const composite = (parsed, library) =>
44 | library === 'vue' ? compositeVue(parsed) : compositeReact(parsed)
45 |
46 | module.exports = (config, options = {}) => {
47 | const components = Array.isArray(config) ? config : config.components
48 | const {
49 | library = 'styled-components',
50 | harmony
51 | } = options
52 |
53 | const template = options.template || templates[library] || templates['styled-components']
54 |
55 | const index = {
56 | name: 'index',
57 | module: harmony ? createIndex(components) : compile(createIndex(components))
58 | }
59 |
60 | const mods = components.map(conf => {
61 | const parsed = parse(conf)
62 |
63 | const code = isComposite(parsed) ? composite(parsed, library) : template(parsed)
64 |
65 | const mod = harmony
66 | ? format(code, {
67 | semi: false,
68 | singleQuote: true
69 | })
70 | : compile(code)
71 |
72 | return {
73 | name: conf.name,
74 | module: mod
75 | }
76 | })
77 |
78 | return [index, ...mods]
79 | }
80 |
81 | const isComposite = comp => comp.imports && comp.jsx
82 |
--------------------------------------------------------------------------------
/lib/templates/composite-react.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | jsx,
4 | imports = []
5 | }) => `import React from 'react'
6 | ${imports.map(name => `import ${name} from './${name}'`).join('\n')}
7 |
8 | const ${name} = props => (
9 | ${jsx}
10 | )
11 |
12 | export default ${name}`
13 |
--------------------------------------------------------------------------------
/lib/templates/composite-vue.js:
--------------------------------------------------------------------------------
1 | const uniq = require('lodash.uniq')
2 | const flatten = require('lodash.flatten')
3 | const getProps = require('@compositor/get-jsx-props')
4 |
5 | module.exports = ({
6 | name,
7 | jsx,
8 | imports = [],
9 | examples = []
10 | }) => {
11 | const props = uniq(flatten(examples.map(getProps)).map(s => s.prop))
12 |
13 | return `
14 | ${imports.map(name => `import ${name} from './${name}'`).join('\n')}
15 |
16 | export default {
17 | name: '${name}',
18 | props: ${JSON.stringify(props)},
19 | render (h) {
20 | return (
21 | ${jsx.replace(/props/g, 'this')}
22 | )
23 | }
24 | }
25 | `
26 | }
27 |
--------------------------------------------------------------------------------
/lib/templates/cxs.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | systemFunctions,
4 | extensionImport,
5 | type,
6 | styleString,
7 | propsString
8 | }) => `import styled from 'cxs/component'
9 | import {
10 | space,
11 | fontSize,
12 | width,
13 | color,
14 | ${systemFunctions}
15 | } from 'styled-system'
16 | ${extensionImport}
17 |
18 | const ${name} = styled(${type})(props => (${styleString}),
19 | space,
20 | fontSize,
21 | width,
22 | color,
23 | ${systemFunctions}
24 | )
25 |
26 | ${name}.defaultProps = ${propsString}
27 |
28 | export default ${name}`
29 |
--------------------------------------------------------------------------------
/lib/templates/emotion.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | type,
4 | styleString,
5 | propsString,
6 | systemFunctions,
7 | extensionImport
8 | }) => `import styled from 'react-emotion'
9 | import { withTheme } from 'theming'
10 | import {
11 | space,
12 | fontSize,
13 | width,
14 | color,
15 | ${systemFunctions}
16 | } from 'styled-system'
17 | ${extensionImport}
18 |
19 | const ${name} = withTheme(styled(${type})(props => (${styleString}),
20 | space,
21 | fontSize,
22 | width,
23 | color,
24 | ${systemFunctions}
25 | ))
26 |
27 | ${name}.defaultProps = ${propsString}
28 |
29 | export default ${name}`
30 |
--------------------------------------------------------------------------------
/lib/templates/fela.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | type,
4 | propsString,
5 | styleString,
6 | system = [],
7 | systemFunctions,
8 | extensionImport
9 | }) => `import { createComponent } from 'react-fela'
10 | import {
11 | space,
12 | fontSize,
13 | width,
14 | color,
15 | ${systemFunctions}
16 | } from 'styled-system'
17 | ${extensionImport}
18 |
19 | const ${name} = createComponent(props => Object.assign(${styleString},
20 | space(props),
21 | fontSize(props),
22 | width(props),
23 | color(props),
24 | ${system.map(fn => `${fn}(props)`).join(',\nss')}
25 | ), ${type})
26 |
27 | ${name}.defaultProps = ${propsString}
28 |
29 | export default ${name}`
30 |
--------------------------------------------------------------------------------
/lib/templates/glamorous.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | type,
4 | propsString,
5 | styleString,
6 | systemFunctions,
7 | extensionImport
8 | }) => `import styled from 'glamorous'
9 | import {
10 | space,
11 | fontSize,
12 | width,
13 | color,
14 | ${systemFunctions}
15 | } from 'styled-system'
16 | ${extensionImport}
17 |
18 | const ${name} = styled(${type})(props => (${styleString}),
19 | space,
20 | fontSize,
21 | width,
22 | color,
23 | ${systemFunctions}
24 | )
25 |
26 | ${name}.defaultProps = ${propsString}
27 |
28 | export default ${name}`
29 |
--------------------------------------------------------------------------------
/lib/templates/index.js:
--------------------------------------------------------------------------------
1 | const compositeReact = require('./composite-react')
2 | const compositeVue = require('./composite-vue')
3 | const styledComponents = require('./styledComponents')
4 | const glamorous = require('./glamorous')
5 | const emotion = require('./emotion')
6 | const cxs = require('./cxs')
7 | const fela = require('./fela')
8 | const vue = require('./vue')
9 |
10 | module.exports = {
11 | // React
12 | compositeReact,
13 | 'styled-components': styledComponents,
14 | glamorous,
15 | emotion,
16 | cxs,
17 | fela,
18 |
19 | // Vue
20 | compositeVue,
21 | vue
22 | }
23 |
--------------------------------------------------------------------------------
/lib/templates/styledComponents.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | name,
3 | type,
4 | styleString,
5 | propsString,
6 | systemFunctions,
7 | extensionImport
8 | }) => `import styled from 'styled-components'
9 | import {
10 | space,
11 | fontSize,
12 | width,
13 | color,
14 | ${systemFunctions}
15 | } from 'styled-system'
16 | ${extensionImport}
17 |
18 | const ${name} = styled(${type})([], props => (${styleString}),
19 | space,
20 | fontSize,
21 | width,
22 | color,
23 | ${systemFunctions}
24 | )
25 |
26 | ${name}.defaultProps = ${propsString}
27 |
28 | export default ${name}`
29 |
--------------------------------------------------------------------------------
/lib/templates/util.js:
--------------------------------------------------------------------------------
1 | const _stringifyObject = require('stringify-object')
2 |
3 | const SREG = /\$\{.*\}/
4 | const transform = (obj, prop, original) => {
5 | const val = obj[prop]
6 | if (SREG.test(val)) {
7 | return original
8 | .replace(/^'/, '`')
9 | .replace(/'$/, '`')
10 | .replace(/\\'/g, `'`)
11 | }
12 | return original
13 | }
14 |
15 | const stringifyOptions = {
16 | indent: ' ',
17 | transform
18 | }
19 |
20 | const stringifyObject = obj => _stringifyObject(obj, stringifyOptions)
21 |
22 | const CREG = /^[A-Z]/
23 | const getExtensionImport = type =>
24 | CREG.test(type) ? `import ${type} from './${type}'\n` : ''
25 |
26 | const getComp = type => (CREG.test(type) ? type : "'" + type + "'")
27 | const getSystemFuncs = funcs => funcs.join(',\n')
28 | const getSystemExpressions = funcs => funcs.map(f => '${' + f + '}').join('\n')
29 |
30 | const EXPRESSION_REG = /^\${(.*)}$/
31 | const isTemplateExpression = str => EXPRESSION_REG.test(str)
32 |
33 | module.exports = {
34 | stringifyObject,
35 | getExtensionImport,
36 | getComp,
37 | getSystemFuncs,
38 | getSystemExpressions,
39 | isTemplateExpression
40 | }
41 |
--------------------------------------------------------------------------------
/lib/templates/vue.js:
--------------------------------------------------------------------------------
1 | const {
2 | isTemplateExpression
3 | } = require('./util')
4 |
5 | module.exports = ({
6 | name,
7 | systemFunctions,
8 | systemExpressions = '',
9 | extensionImport,
10 | type,
11 | style,
12 | props
13 | }) => `import styled from 'vue-styled-components'
14 | import system from 'vue-styled-system'
15 |
16 | import {
17 | space,
18 | fontSize,
19 | width,
20 | color,
21 | ${systemFunctions}
22 | } from 'styled-system'
23 |
24 | import theme from './theme.json'
25 | ${extensionImport}
26 | export default styled(${type}, system({
27 | ${formatProps(props)}
28 | theme: { default: () => theme }
29 | }))\`
30 | ${formatStyle(style)}
31 | \${space}
32 | \${fontSize}
33 | \${width}
34 | \${color}
35 | ${systemExpressions}
36 | \`
37 | `
38 |
39 | const formatProps = props =>
40 | Object
41 | .keys(props)
42 | .reduce((acc, key) =>
43 | acc.concat(`${key}: { default: ${formatValue(props[key])} },`)
44 | , [])
45 | .join('\n')
46 |
47 | const formatValue = value => {
48 | switch(typeof value) {
49 | case 'string':
50 | return isTemplateExpression(value) ? value : `'${value}'`
51 | case 'object':
52 | return `() => (${JSON.stringify(value, null, 2)})`
53 | default:
54 | return value
55 | }
56 | }
57 |
58 | const formatStyle = style =>
59 | Object.keys(style).reduce((acc, key) => {
60 | const val = style[key]
61 | const parsedVal = typeof val === 'string' ? val.replace(/\${\s*/g, '${ props => ') : val
62 | return acc.concat(` ${key}: ${formatValue(parsedVal)}`)
63 | } , []).join(',\n')
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@compositor/lab",
3 | "version": "1.0.0-37",
4 | "description": "CLI utilities for Compositor Lab",
5 | "main": "lib/index.js",
6 | "bin": {
7 | "lab": "bin/cli.js"
8 | },
9 | "scripts": {
10 | "test": "nyc ava",
11 | "cover": "nyc report --reporter=html --reporter=lcov",
12 | "build": "./bin/cli.js examples/lab.json --pkg -d examples/dist"
13 | },
14 | "keywords": [
15 | "compositor",
16 | "lab",
17 | "components",
18 | "design",
19 | "system"
20 | ],
21 | "author": "Brent Jackson",
22 | "license": "MIT",
23 | "dependencies": {
24 | "@compositor/get-jsx-props": "0.0.4",
25 | "babel-core": "^6.26.0",
26 | "babel-preset-env": "^1.6.1",
27 | "babel-preset-react": "^6.24.1",
28 | "babel-preset-stage-0": "^6.24.1",
29 | "chalk": "^2.1.0",
30 | "chokidar": "^1.7.0",
31 | "find-up": "^2.1.0",
32 | "indent": "0.0.2",
33 | "lodash.flatten": "^4.4.0",
34 | "lodash.uniq": "^4.5.0",
35 | "meow": "^3.7.0",
36 | "ora": "^1.3.0",
37 | "prettier": "^1.7.4",
38 | "react": "^16.0.0",
39 | "stringify-object": "^3.2.1",
40 | "update-notifier": "^2.2.0",
41 | "write-file-atomic": "^2.3.0"
42 | },
43 | "devDependencies": {
44 | "ava": "^0.22.0",
45 | "nyc": "^11.2.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/test/fixture.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mono",
3 | "library": "glamorous",
4 | "components": [
5 | {
6 | "name": "Avatar",
7 | "type": "img",
8 | "props": {
9 | "src": "https://pbs.twimg.com/profile_images/854537128994275328/nVZX1MEh_400x400.jpg",
10 | "size": "64px",
11 | "borderWidth": 2,
12 | "borderRadius": 9999,
13 | "px": 1,
14 | "py": 1,
15 | "borderColor": "gray1",
16 | "bg": "transparent",
17 | "color": "transparent"
18 | },
19 | "style": {
20 | "height": "${props.size? props.size: '48px'}",
21 | "width": "${props.size? props.size: '48px'}"
22 | },
23 | "examples": [
24 | " ",
25 | " ",
26 | " ",
27 | " ",
28 | " ",
29 | " ",
30 | " ",
31 | " ",
32 | " ",
33 | " "
34 | ],
35 | "system": [
36 | "borderWidth",
37 | "borderRadius",
38 | "borderColor"
39 | ]
40 | },
41 | {
42 | "name": "Button",
43 | "type": "button",
44 | "props": {
45 | "fontSize": 1,
46 | "px": 4,
47 | "py": 2,
48 | "mr": 2,
49 | "color": "white",
50 | "bg": "blue"
51 | },
52 | "style": {
53 | "display": "inline-block",
54 | "fontFamily": "inherit",
55 | "borderWidth": 0,
56 | "borderRadius": "4px",
57 | "appearance": "none"
58 | },
59 | "examples": [
60 | "Confirm ",
61 | "Save ",
62 | "Hello "
63 | ],
64 | "system": []
65 | },
66 | {
67 | "name": "ButtonOutline",
68 | "type": "button",
69 | "props": {
70 | "fontSize": 1,
71 | "px": 4,
72 | "py": 2,
73 | "color": "blue",
74 | "bg": "transparent",
75 | "borderWidth": 2,
76 | "borderColor": "currentColor"
77 | },
78 | "style": {
79 | "display": "inline-block",
80 | "fontFamily": "inherit",
81 | "borderRadius": "4px",
82 | "appearance": "none",
83 | "boxSizing": "border-box"
84 | },
85 | "examples": [
86 | "Hello "
87 | ],
88 | "system": [
89 | "borderWidth",
90 | "borderColor"
91 | ]
92 | },
93 | {
94 | "name": "Link",
95 | "type": "a",
96 | "props": {
97 | "color": "inherit",
98 | "hover": {
99 | "opacity": 0.66,
100 | "transition": "opacity .25s ease-in"
101 | }
102 | },
103 | "style": {
104 | "textAlign": "${props.center? 'center': 'left'}",
105 | "textDecoration": "${props.underline? 'underline': 'none'}",
106 | "opacity": 1,
107 | "transition": "opacity .3s ease-in",
108 | "display": "inline-block"
109 | },
110 | "examples": [
111 | " Read our docs",
112 | " Read our docs"
113 | ],
114 | "system": [
115 | "hover"
116 | ]
117 | },
118 | {
119 | "name": "LinkBox",
120 | "type": "a",
121 | "props": {
122 | "color": "black",
123 | "fontSize": 2,
124 | "borderWidth": 1,
125 | "borderColor": "black",
126 | "px": 2,
127 | "py": 1
128 | },
129 | "style": {
130 | "textDecoration": "none"
131 | },
132 | "examples": [
133 | "1 "
134 | ],
135 | "system": [
136 | "borderWidth",
137 | "borderColor"
138 | ]
139 | },
140 | {
141 | "name": "Img",
142 | "type": "img",
143 | "props": {},
144 | "style": {
145 | "display": "block",
146 | "maxWidth": "100%",
147 | "width": "100%"
148 | },
149 | "examples": [
150 | " ",
151 | " ",
152 | " ",
153 | " "
154 | ],
155 | "system": []
156 | },
157 | {
158 | "name": "Hr",
159 | "type": "hr",
160 | "props": {
161 | "bg": "transparent",
162 | "color": "black",
163 | "pl": 0,
164 | "pr": 0,
165 | "pb": 0,
166 | "borderRadius": 0,
167 | "borderWidth": 1,
168 | "borderTop": true
169 | },
170 | "style": {
171 | "height": 0
172 | },
173 | "examples": [
174 | "
"
175 | ],
176 | "system": [
177 | "borderRadius",
178 | "borderWidth"
179 | ]
180 | },
181 | {
182 | "name": "Text",
183 | "type": "div",
184 | "props": {},
185 | "style": {},
186 | "examples": [
187 | "Hello "
188 | ]
189 | },
190 | {
191 | "name": "Heading",
192 | "type": "h2",
193 | "props": {
194 | "fontSize": 4,
195 | "m": 0,
196 | "fontWeight": "600"
197 | },
198 | "style": {},
199 | "examples": [
200 | "Hello "
201 | ],
202 | "system": [
203 | "fontWeight",
204 | "borderColor",
205 | "borderWidth"
206 | ]
207 | },
208 | {
209 | "name": "P",
210 | "type": "p",
211 | "props": {},
212 | "style": {
213 | "maxWidth": "${props.wide? '34em': '28em'}",
214 | "lineHeight": "1.5"
215 | },
216 | "examples": [
217 | "\rIMMACULATE typography is certainly the most brittle of all the arts. To create a whole from many petrified, dis- connected and given parts, to make this whole appear alive and of a piece — only sculpture in stone approaches the unyielding stiffness of perfect typography. For most people, even impeccable typography does not hold any particular aesthetic appeal. In its inaccessibility, it resembles great\rmusic. Under the best of circumstances, it is gratefully , accepted. To remain nameless and without specific appre- ciation, yet to have been of service to a valuable work and to the small number of visually sensitive readers — this, as a rule, is the only compensation for the long, and indeed never- ending, indenture of the typographer.
",
218 | "\rA very short example of a paragraph.
"
219 | ],
220 | "system": []
221 | },
222 | {
223 | "name": "H1",
224 | "type": "h1",
225 | "props": {
226 | "fontWeight": "600"
227 | },
228 | "style": {
229 | "textAlign": "${props.center? 'center': 'left'}"
230 | },
231 | "examples": [
232 | "Heading Number 1 ",
233 | "Heading Number 1 "
234 | ],
235 | "system": [
236 | "fontWeight"
237 | ]
238 | },
239 | {
240 | "name": "H2",
241 | "type": "h2",
242 | "props": {
243 | "fontWeight": "600"
244 | },
245 | "style": {
246 | "textAlign": "${props.center? 'center': 'left'}"
247 | },
248 | "examples": [
249 | "Heading Number 2 ",
250 | "Centered Heading Number 2 "
251 | ],
252 | "system": [
253 | "fontWeight"
254 | ]
255 | },
256 | {
257 | "name": "H3",
258 | "type": "h3",
259 | "props": {
260 | "fontWeight": "600"
261 | },
262 | "style": {
263 | "textAlign": "${props.center? 'center': 'left'}"
264 | },
265 | "examples": [
266 | "Heading Number 3 "
267 | ],
268 | "system": [
269 | "fontWeight"
270 | ]
271 | },
272 | {
273 | "name": "H4",
274 | "type": "h4",
275 | "props": {
276 | "fontWeight": "600"
277 | },
278 | "style": {
279 | "textAlign": "${props.center? 'center': 'left'}"
280 | },
281 | "examples": [
282 | "Heading Number 4 "
283 | ],
284 | "system": [
285 | "fontWeight"
286 | ]
287 | },
288 | {
289 | "name": "Div",
290 | "type": "div",
291 | "props": {},
292 | "style": {},
293 | "examples": [
294 | "A generic div component that now has the super powers of styled-system.
",
295 | "A generic div component that now has the super powers of styled-system.
",
296 | "A generic div component that now has the super powers of styled-system.
"
297 | ],
298 | "system": []
299 | },
300 | {
301 | "name": "Container",
302 | "type": "div",
303 | "props": {
304 | "mx": "auto"
305 | },
306 | "style": {
307 | "maxWidth": "64em",
308 | "boxSizing": "border-box"
309 | },
310 | "examples": [
311 | "A container for centering your page content. "
312 | ],
313 | "system": []
314 | },
315 | {
316 | "name": "Input",
317 | "type": "input",
318 | "props": {
319 | "m": 0,
320 | "w": 1,
321 | "px": 2,
322 | "py": 2,
323 | "color": "inherit",
324 | "bg": "transparent",
325 | "borderColor": "gray4",
326 | "borderWidth": 1,
327 | "fontSize": null,
328 | "focus": {
329 | "outline": 0
330 | },
331 | "borderRadius": 2
332 | },
333 | "style": {
334 | "display": "block",
335 | "fontFamily": "inherit",
336 | "fontSize": "inherit"
337 | },
338 | "examples": [
339 | " "
340 | ],
341 | "system": [
342 | "borderColor",
343 | "borderWidth",
344 | "focus",
345 | "borderRadius"
346 | ]
347 | },
348 | {
349 | "name": "Label",
350 | "type": "label",
351 | "props": {
352 | "fontSize": 1,
353 | "fontWeight": "600"
354 | },
355 | "style": {
356 | "display": "block"
357 | },
358 | "examples": [
359 | "Hello "
360 | ],
361 | "system": [
362 | "fontWeight"
363 | ]
364 | },
365 | {
366 | "name": "TextInput",
367 | "imports": [
368 | "Label",
369 | "Div",
370 | "Input",
371 | "P"
372 | ],
373 | "jsx": "\n
\n {props.text &&\n
\n {props.text}\n
\n }\n
\n
",
374 | "examples": [
375 | " ",
376 | " ",
377 | " "
378 | ],
379 | "system": []
380 | },
381 | {
382 | "name": "Ul",
383 | "type": "ul",
384 | "props": {
385 | "m": 0,
386 | "p": 0,
387 | "borderColor": "transparent",
388 | "borderWidth": 1
389 | },
390 | "style": {
391 | "listStyleType": "none"
392 | },
393 | "examples": [
394 | ""
395 | ],
396 | "system": [
397 | "borderColor",
398 | "borderWidth"
399 | ]
400 | },
401 | {
402 | "name": "Li",
403 | "type": "li",
404 | "props": {
405 | "borderWidth": 1,
406 | "borderColor": "transparent"
407 | },
408 | "style": {},
409 | "examples": [
410 | "Hello "
411 | ],
412 | "system": [
413 | "borderWidth",
414 | "borderColor"
415 | ]
416 | }
417 | ]
418 | }
--------------------------------------------------------------------------------
/test/modules.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import createModules from '../lib'
3 |
4 | const config = [
5 | {
6 | name: 'Box',
7 | type: 'div',
8 | props: {},
9 | style: {}
10 | },
11 | {
12 | name: 'Text',
13 | type: 'p',
14 | props: {
15 | m: 0
16 | },
17 | style: {}
18 | },
19 | {
20 | name: 'Hello',
21 | imports: ['Box', 'Text'],
22 | jsx: ' '
23 | },
24 | {
25 | name: 'Beep',
26 | type: 'Box',
27 | props: {
28 | p: 3,
29 | bg: 'tomato'
30 | },
31 | style: {}
32 | },
33 | {
34 | name: 'Flex',
35 | type: 'Box',
36 | props: {},
37 | style: {
38 | display: 'flex'
39 | },
40 | system: ['alignItems', 'justifyContent', 'flexDirection', 'flexWrap']
41 | }
42 | ]
43 |
44 | test('returns an array of objects', t => {
45 | const mods = createModules(config)
46 | t.true(Array.isArray(mods))
47 | const [a, b, c, d, e, f] = mods
48 | t.is(typeof a, 'object')
49 | t.is(typeof b, 'object')
50 | t.is(typeof c, 'object')
51 | t.is(typeof d, 'object')
52 | t.is(typeof e, 'object')
53 | t.is(typeof f, 'object')
54 | t.is(a.name, 'index')
55 | t.is(b.name, 'Box')
56 | t.is(c.name, 'Text')
57 | t.is(d.name, 'Hello')
58 | t.is(e.name, 'Beep')
59 | t.is(f.name, 'Flex')
60 | t.is(typeof a.module, 'string')
61 | t.is(typeof b.module, 'string')
62 | t.is(typeof c.module, 'string')
63 | t.is(typeof d.module, 'string')
64 | t.is(typeof e.module, 'string')
65 | t.is(typeof f.module, 'string')
66 | t.snapshot(a)
67 | t.snapshot(b)
68 | t.snapshot(c)
69 | t.snapshot(d)
70 | t.snapshot(e)
71 | t.snapshot(f)
72 | })
73 |
74 | test('accepts a library option', t => {
75 | const mods = createModules(config, {
76 | library: 'glamorous'
77 | })
78 | const [a, b] = mods
79 | t.is(typeof a, 'object')
80 | t.is(typeof b, 'object')
81 | t.snapshot(a)
82 | t.snapshot(b)
83 | })
84 |
85 | test('accepts a custom template option', t => {
86 | const template = () => `module.exports = 'hello'`
87 | const [ a, b ] = createModules(config, {
88 | harmony: true,
89 | template
90 | })
91 | t.is(b.module.trim(), `module.exports = 'hello'`)
92 | })
93 |
--------------------------------------------------------------------------------
/test/snapshots/modules.js.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/modules.js`
2 |
3 | The actual snapshot is saved in `modules.js.snap`.
4 |
5 | Generated by [AVA](https://ava.li).
6 |
7 | ## accepts a library option
8 |
9 | > Snapshot 1
10 |
11 | {
12 | module: `'use strict';␊
13 | ␊
14 | Object.defineProperty(exports, "__esModule", {␊
15 | value: true␊
16 | });␊
17 | ␊
18 | var _lab = require('./lab');␊
19 | ␊
20 | Object.defineProperty(exports, 'lab', {␊
21 | enumerable: true,␊
22 | get: function get() {␊
23 | return _interopRequireDefault(_lab).default;␊
24 | }␊
25 | });␊
26 | ␊
27 | var _theme = require('./theme');␊
28 | ␊
29 | Object.defineProperty(exports, 'theme', {␊
30 | enumerable: true,␊
31 | get: function get() {␊
32 | return _interopRequireDefault(_theme).default;␊
33 | }␊
34 | });␊
35 | ␊
36 | var _Box = require('./Box');␊
37 | ␊
38 | Object.defineProperty(exports, 'Box', {␊
39 | enumerable: true,␊
40 | get: function get() {␊
41 | return _interopRequireDefault(_Box).default;␊
42 | }␊
43 | });␊
44 | ␊
45 | var _Text = require('./Text');␊
46 | ␊
47 | Object.defineProperty(exports, 'Text', {␊
48 | enumerable: true,␊
49 | get: function get() {␊
50 | return _interopRequireDefault(_Text).default;␊
51 | }␊
52 | });␊
53 | ␊
54 | var _Hello = require('./Hello');␊
55 | ␊
56 | Object.defineProperty(exports, 'Hello', {␊
57 | enumerable: true,␊
58 | get: function get() {␊
59 | return _interopRequireDefault(_Hello).default;␊
60 | }␊
61 | });␊
62 | ␊
63 | var _Beep = require('./Beep');␊
64 | ␊
65 | Object.defineProperty(exports, 'Beep', {␊
66 | enumerable: true,␊
67 | get: function get() {␊
68 | return _interopRequireDefault(_Beep).default;␊
69 | }␊
70 | });␊
71 | ␊
72 | var _Flex = require('./Flex');␊
73 | ␊
74 | Object.defineProperty(exports, 'Flex', {␊
75 | enumerable: true,␊
76 | get: function get() {␊
77 | return _interopRequireDefault(_Flex).default;␊
78 | }␊
79 | });␊
80 | ␊
81 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }`,
82 | name: 'index',
83 | }
84 |
85 | > Snapshot 2
86 |
87 | {
88 | module: `'use strict';␊
89 | ␊
90 | Object.defineProperty(exports, "__esModule", {␊
91 | value: true␊
92 | });␊
93 | ␊
94 | var _glamorous = require('glamorous');␊
95 | ␊
96 | var _glamorous2 = _interopRequireDefault(_glamorous);␊
97 | ␊
98 | var _styledSystem = require('styled-system');␊
99 | ␊
100 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
101 | ␊
102 | var Box = (0, _glamorous2.default)('div')(function (props) {␊
103 | return {};␊
104 | }, _styledSystem.space, _styledSystem.fontSize, _styledSystem.width, _styledSystem.color);␊
105 | ␊
106 | Box.defaultProps = {};␊
107 | ␊
108 | exports.default = Box;`,
109 | name: 'Box',
110 | }
111 |
112 | ## returns an array of objects
113 |
114 | > Snapshot 1
115 |
116 | {
117 | module: `'use strict';␊
118 | ␊
119 | Object.defineProperty(exports, "__esModule", {␊
120 | value: true␊
121 | });␊
122 | ␊
123 | var _lab = require('./lab');␊
124 | ␊
125 | Object.defineProperty(exports, 'lab', {␊
126 | enumerable: true,␊
127 | get: function get() {␊
128 | return _interopRequireDefault(_lab).default;␊
129 | }␊
130 | });␊
131 | ␊
132 | var _theme = require('./theme');␊
133 | ␊
134 | Object.defineProperty(exports, 'theme', {␊
135 | enumerable: true,␊
136 | get: function get() {␊
137 | return _interopRequireDefault(_theme).default;␊
138 | }␊
139 | });␊
140 | ␊
141 | var _Box = require('./Box');␊
142 | ␊
143 | Object.defineProperty(exports, 'Box', {␊
144 | enumerable: true,␊
145 | get: function get() {␊
146 | return _interopRequireDefault(_Box).default;␊
147 | }␊
148 | });␊
149 | ␊
150 | var _Text = require('./Text');␊
151 | ␊
152 | Object.defineProperty(exports, 'Text', {␊
153 | enumerable: true,␊
154 | get: function get() {␊
155 | return _interopRequireDefault(_Text).default;␊
156 | }␊
157 | });␊
158 | ␊
159 | var _Hello = require('./Hello');␊
160 | ␊
161 | Object.defineProperty(exports, 'Hello', {␊
162 | enumerable: true,␊
163 | get: function get() {␊
164 | return _interopRequireDefault(_Hello).default;␊
165 | }␊
166 | });␊
167 | ␊
168 | var _Beep = require('./Beep');␊
169 | ␊
170 | Object.defineProperty(exports, 'Beep', {␊
171 | enumerable: true,␊
172 | get: function get() {␊
173 | return _interopRequireDefault(_Beep).default;␊
174 | }␊
175 | });␊
176 | ␊
177 | var _Flex = require('./Flex');␊
178 | ␊
179 | Object.defineProperty(exports, 'Flex', {␊
180 | enumerable: true,␊
181 | get: function get() {␊
182 | return _interopRequireDefault(_Flex).default;␊
183 | }␊
184 | });␊
185 | ␊
186 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }`,
187 | name: 'index',
188 | }
189 |
190 | > Snapshot 2
191 |
192 | {
193 | module: `'use strict';␊
194 | ␊
195 | Object.defineProperty(exports, "__esModule", {␊
196 | value: true␊
197 | });␊
198 | ␊
199 | var _styledComponents = require('styled-components');␊
200 | ␊
201 | var _styledComponents2 = _interopRequireDefault(_styledComponents);␊
202 | ␊
203 | var _styledSystem = require('styled-system');␊
204 | ␊
205 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
206 | ␊
207 | var Box = (0, _styledComponents2.default)('div')([], function (props) {␊
208 | return {};␊
209 | }, _styledSystem.space, _styledSystem.fontSize, _styledSystem.width, _styledSystem.color);␊
210 | ␊
211 | Box.defaultProps = {};␊
212 | ␊
213 | exports.default = Box;`,
214 | name: 'Box',
215 | }
216 |
217 | > Snapshot 3
218 |
219 | {
220 | module: `'use strict';␊
221 | ␊
222 | Object.defineProperty(exports, "__esModule", {␊
223 | value: true␊
224 | });␊
225 | ␊
226 | var _styledComponents = require('styled-components');␊
227 | ␊
228 | var _styledComponents2 = _interopRequireDefault(_styledComponents);␊
229 | ␊
230 | var _styledSystem = require('styled-system');␊
231 | ␊
232 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
233 | ␊
234 | var Text = (0, _styledComponents2.default)('p')([], function (props) {␊
235 | return {};␊
236 | }, _styledSystem.space, _styledSystem.fontSize, _styledSystem.width, _styledSystem.color);␊
237 | ␊
238 | Text.defaultProps = {␊
239 | m: 0␊
240 | };␊
241 | ␊
242 | exports.default = Text;`,
243 | name: 'Text',
244 | }
245 |
246 | > Snapshot 4
247 |
248 | {
249 | module: `'use strict';␊
250 | ␊
251 | Object.defineProperty(exports, "__esModule", {␊
252 | value: true␊
253 | });␊
254 | ␊
255 | var _react = require('react');␊
256 | ␊
257 | var _react2 = _interopRequireDefault(_react);␊
258 | ␊
259 | var _Box = require('./Box');␊
260 | ␊
261 | var _Box2 = _interopRequireDefault(_Box);␊
262 | ␊
263 | var _Text = require('./Text');␊
264 | ␊
265 | var _Text2 = _interopRequireDefault(_Text);␊
266 | ␊
267 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
268 | ␊
269 | var Hello = function Hello(props) {␊
270 | return _react2.default.createElement(␊
271 | _Box2.default,␊
272 | null,␊
273 | _react2.default.createElement(_Text2.default, null)␊
274 | );␊
275 | };␊
276 | ␊
277 | exports.default = Hello;`,
278 | name: 'Hello',
279 | }
280 |
281 | > Snapshot 5
282 |
283 | {
284 | module: `'use strict';␊
285 | ␊
286 | Object.defineProperty(exports, "__esModule", {␊
287 | value: true␊
288 | });␊
289 | ␊
290 | var _styledComponents = require('styled-components');␊
291 | ␊
292 | var _styledComponents2 = _interopRequireDefault(_styledComponents);␊
293 | ␊
294 | var _styledSystem = require('styled-system');␊
295 | ␊
296 | var _Box = require('./Box');␊
297 | ␊
298 | var _Box2 = _interopRequireDefault(_Box);␊
299 | ␊
300 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
301 | ␊
302 | var Beep = (0, _styledComponents2.default)(_Box2.default)([], function (props) {␊
303 | return {};␊
304 | }, _styledSystem.space, _styledSystem.fontSize, _styledSystem.width, _styledSystem.color);␊
305 | ␊
306 | Beep.defaultProps = {␊
307 | p: 3,␊
308 | bg: 'tomato'␊
309 | };␊
310 | ␊
311 | exports.default = Beep;`,
312 | name: 'Beep',
313 | }
314 |
315 | > Snapshot 6
316 |
317 | {
318 | module: `'use strict';␊
319 | ␊
320 | Object.defineProperty(exports, "__esModule", {␊
321 | value: true␊
322 | });␊
323 | ␊
324 | var _styledComponents = require('styled-components');␊
325 | ␊
326 | var _styledComponents2 = _interopRequireDefault(_styledComponents);␊
327 | ␊
328 | var _styledSystem = require('styled-system');␊
329 | ␊
330 | var _Box = require('./Box');␊
331 | ␊
332 | var _Box2 = _interopRequireDefault(_Box);␊
333 | ␊
334 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }␊
335 | ␊
336 | var Flex = (0, _styledComponents2.default)(_Box2.default)([], function (props) {␊
337 | return {␊
338 | display: 'flex'␊
339 | };␊
340 | }, _styledSystem.space, _styledSystem.fontSize, _styledSystem.width, _styledSystem.color, _styledSystem.alignItems, _styledSystem.justifyContent, _styledSystem.flexDirection, _styledSystem.flexWrap);␊
341 | ␊
342 | Flex.defaultProps = {};␊
343 | ␊
344 | exports.default = Flex;`,
345 | name: 'Flex',
346 | }
347 |
--------------------------------------------------------------------------------
/test/snapshots/modules.js.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c8r/lab-cli/557bc57835fae30cee5465a6ac10633c628560aa/test/snapshots/modules.js.snap
--------------------------------------------------------------------------------
/test/snapshots/templates.js.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/templates.js`
2 |
3 | The actual snapshot is saved in `templates.js.snap`.
4 |
5 | Generated by [AVA](https://ava.li).
6 |
7 | ## composite has defaults
8 |
9 | > Snapshot 1
10 |
11 | `import React from 'react'␊
12 | ␊
13 | ␊
14 | const Hello = props => (␊
15 | undefined␊
16 | )␊
17 | ␊
18 | export default Hello`
19 |
20 | ## composite imports required components
21 |
22 | > Snapshot 1
23 |
24 | `import React from 'react'␊
25 | import Box from './Box'␊
26 | import Text from './Text'␊
27 | ␊
28 | const Hello = props => (␊
29 | {props.children} ␊
30 | )␊
31 | ␊
32 | export default Hello`
33 |
34 | ## composite returns a string
35 |
36 | > Snapshot 1
37 |
38 | `import React from 'react'␊
39 | import Box from './Box'␊
40 | import Text from './Text'␊
41 | ␊
42 | const Hello = props => (␊
43 | {props.children} ␊
44 | )␊
45 | ␊
46 | export default Hello`
47 |
48 | ## cxs imports required components
49 |
50 | > Snapshot 1
51 |
52 | `import styled from 'cxs/component'␊
53 | import {␊
54 | space,␊
55 | fontSize,␊
56 | width,␊
57 | color,␊
58 | ␊
59 | } from 'styled-system'␊
60 | import Div from './Div'␊
61 | ␊
62 | const Box = styled(Div)(props => ({}),␊
63 | space,␊
64 | fontSize,␊
65 | width,␊
66 | color,␊
67 | ␊
68 | )␊
69 | ␊
70 | Box.defaultProps = {}␊
71 | ␊
72 | export default Box`
73 |
74 | ## cxs returns a string
75 |
76 | > Snapshot 1
77 |
78 | `import styled from 'cxs/component'␊
79 | import {␊
80 | space,␊
81 | fontSize,␊
82 | width,␊
83 | color,␊
84 | ␊
85 | } from 'styled-system'␊
86 | ␊
87 | ␊
88 | const Hello = styled(h2)(props => ((props, theme) => ({␊
89 | fontFamily: 'inherit',␊
90 | color: props.theme('colors.blue')␊
91 | })),␊
92 | space,␊
93 | fontSize,␊
94 | width,␊
95 | color,␊
96 | ␊
97 | )␊
98 | ␊
99 | Hello.defaultProps = {␊
100 | p: 2␊
101 | }␊
102 | ␊
103 | export default Hello`
104 |
105 | ## emotion imports required components
106 |
107 | > Snapshot 1
108 |
109 | `import styled from 'react-emotion'␊
110 | import { withTheme } from 'theming'␊
111 | import {␊
112 | space,␊
113 | fontSize,␊
114 | width,␊
115 | color,␊
116 | ␊
117 | } from 'styled-system'␊
118 | import Div from './Div'␊
119 | ␊
120 | const Box = withTheme(styled(Div)(props => ({}),␊
121 | space,␊
122 | fontSize,␊
123 | width,␊
124 | color,␊
125 | ␊
126 | ))␊
127 | ␊
128 | Box.defaultProps = {}␊
129 | ␊
130 | export default Box`
131 |
132 | ## emotion returns a string
133 |
134 | > Snapshot 1
135 |
136 | `import styled from 'react-emotion'␊
137 | import { withTheme } from 'theming'␊
138 | import {␊
139 | space,␊
140 | fontSize,␊
141 | width,␊
142 | color,␊
143 | ␊
144 | } from 'styled-system'␊
145 | ␊
146 | ␊
147 | const Hello = withTheme(styled(h2)(props => ((props, theme) => ({␊
148 | fontFamily: 'inherit',␊
149 | color: props.theme('colors.blue')␊
150 | })),␊
151 | space,␊
152 | fontSize,␊
153 | width,␊
154 | color,␊
155 | ␊
156 | ))␊
157 | ␊
158 | Hello.defaultProps = {␊
159 | p: 2␊
160 | }␊
161 | ␊
162 | export default Hello`
163 |
164 | ## fela handles styled-system functions
165 |
166 | > Snapshot 1
167 |
168 | `import { createComponent } from 'react-fela'␊
169 | import {␊
170 | space,␊
171 | fontSize,␊
172 | width,␊
173 | color,␊
174 | textAlign,␊
175 | } from 'styled-system'␊
176 | ␊
177 | ␊
178 | const Hello = createComponent(props => Object.assign({},␊
179 | space(props),␊
180 | fontSize(props),␊
181 | width(props),␊
182 | color(props),␊
183 | textAlign(props)␊
184 | ), h2)␊
185 | ␊
186 | Hello.defaultProps = {}␊
187 | ␊
188 | export default Hello`
189 |
190 | ## fela imports required components
191 |
192 | > Snapshot 1
193 |
194 | `import { createComponent } from 'react-fela'␊
195 | import {␊
196 | space,␊
197 | fontSize,␊
198 | width,␊
199 | color,␊
200 | ␊
201 | } from 'styled-system'␊
202 | import Div from './Div'␊
203 | ␊
204 | const Box = createComponent(props => Object.assign({},␊
205 | space(props),␊
206 | fontSize(props),␊
207 | width(props),␊
208 | color(props),␊
209 | ␊
210 | ), Div)␊
211 | ␊
212 | Box.defaultProps = {}␊
213 | ␊
214 | export default Box`
215 |
216 | ## fela returns a string
217 |
218 | > Snapshot 1
219 |
220 | `import { createComponent } from 'react-fela'␊
221 | import {␊
222 | space,␊
223 | fontSize,␊
224 | width,␊
225 | color,␊
226 | ␊
227 | } from 'styled-system'␊
228 | ␊
229 | ␊
230 | const Hello = createComponent(props => Object.assign((props, theme) => ({␊
231 | fontFamily: 'inherit',␊
232 | color: props.theme('colors.blue')␊
233 | }),␊
234 | space(props),␊
235 | fontSize(props),␊
236 | width(props),␊
237 | color(props),␊
238 | ␊
239 | ), h2)␊
240 | ␊
241 | Hello.defaultProps = {␊
242 | p: 2␊
243 | }␊
244 | ␊
245 | export default Hello`
246 |
247 | ## glamorous imports required components
248 |
249 | > Snapshot 1
250 |
251 | `import styled from 'glamorous'␊
252 | import {␊
253 | space,␊
254 | fontSize,␊
255 | width,␊
256 | color,␊
257 | ␊
258 | } from 'styled-system'␊
259 | import Div from './Div'␊
260 | ␊
261 | const Box = styled(Div)(props => ({}),␊
262 | space,␊
263 | fontSize,␊
264 | width,␊
265 | color,␊
266 | ␊
267 | )␊
268 | ␊
269 | Box.defaultProps = {}␊
270 | ␊
271 | export default Box`
272 |
273 | ## glamorous returns a string
274 |
275 | > Snapshot 1
276 |
277 | `import styled from 'glamorous'␊
278 | import {␊
279 | space,␊
280 | fontSize,␊
281 | width,␊
282 | color,␊
283 | ␊
284 | } from 'styled-system'␊
285 | ␊
286 | ␊
287 | const Hello = styled(h2)(props => ((props, theme) => ({␊
288 | fontFamily: 'inherit',␊
289 | color: props.theme('colors.blue')␊
290 | })),␊
291 | space,␊
292 | fontSize,␊
293 | width,␊
294 | color,␊
295 | ␊
296 | )␊
297 | ␊
298 | Hello.defaultProps = {␊
299 | p: 2␊
300 | }␊
301 | ␊
302 | export default Hello`
303 |
304 | ## styled-components imports required components
305 |
306 | > Snapshot 1
307 |
308 | `import styled from 'styled-components'␊
309 | import {␊
310 | space,␊
311 | fontSize,␊
312 | width,␊
313 | color,␊
314 | ␊
315 | } from 'styled-system'␊
316 | import Div from './Div'␊
317 | ␊
318 | const Box = styled(Div)([], props => ({}),␊
319 | space,␊
320 | fontSize,␊
321 | width,␊
322 | color,␊
323 | ␊
324 | )␊
325 | ␊
326 | Box.defaultProps = {}␊
327 | ␊
328 | export default Box`
329 |
330 | ## styled-components returns a string
331 |
332 | > Snapshot 1
333 |
334 | `import styled from 'styled-components'␊
335 | import {␊
336 | space,␊
337 | fontSize,␊
338 | width,␊
339 | color,␊
340 | ␊
341 | } from 'styled-system'␊
342 | ␊
343 | ␊
344 | const Hello = styled(h2)([], props => ((props, theme) => ({␊
345 | fontFamily: 'inherit',␊
346 | color: props.theme('colors.blue')␊
347 | })),␊
348 | space,␊
349 | fontSize,␊
350 | width,␊
351 | color,␊
352 | ␊
353 | )␊
354 | ␊
355 | Hello.defaultProps = {␊
356 | p: 2␊
357 | }␊
358 | ␊
359 | export default Hello`
360 |
--------------------------------------------------------------------------------
/test/snapshots/templates.js.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c8r/lab-cli/557bc57835fae30cee5465a6ac10633c628560aa/test/snapshots/templates.js.snap
--------------------------------------------------------------------------------
/test/snapshots/vue.js.md:
--------------------------------------------------------------------------------
1 | # Snapshot report for `test/vue.js`
2 |
3 | The actual snapshot is saved in `vue.js.snap`.
4 |
5 | Generated by [AVA](https://ava.li).
6 |
7 | ## vue handles an entire complex library
8 |
9 | > Snapshot 1
10 |
11 | [
12 | {
13 | module: `export { default as lab } from './lab'␊
14 | export { default as theme } from './theme'␊
15 | export { default as Avatar } from './Avatar'␊
16 | export { default as Button } from './Button'␊
17 | export { default as ButtonOutline } from './ButtonOutline'␊
18 | export { default as Link } from './Link'␊
19 | export { default as LinkBox } from './LinkBox'␊
20 | export { default as Img } from './Img'␊
21 | export { default as Hr } from './Hr'␊
22 | export { default as Text } from './Text'␊
23 | export { default as Heading } from './Heading'␊
24 | export { default as P } from './P'␊
25 | export { default as H1 } from './H1'␊
26 | export { default as H2 } from './H2'␊
27 | export { default as H3 } from './H3'␊
28 | export { default as H4 } from './H4'␊
29 | export { default as Div } from './Div'␊
30 | export { default as Container } from './Container'␊
31 | export { default as Input } from './Input'␊
32 | export { default as Label } from './Label'␊
33 | export { default as TextInput } from './TextInput'␊
34 | export { default as Ul } from './Ul'␊
35 | export { default as Li } from './Li'`,
36 | name: 'index',
37 | },
38 | {
39 | module: `import styled from 'vue-styled-components'␊
40 | import system from 'vue-styled-system'␊
41 | ␊
42 | import {␊
43 | space,␊
44 | fontSize,␊
45 | width,␊
46 | color,␊
47 | borderWidth,␊
48 | borderRadius,␊
49 | borderColor␊
50 | } from 'styled-system'␊
51 | ␊
52 | import theme from './theme.json'␊
53 | ␊
54 | export default styled(␊
55 | 'img',␊
56 | system({␊
57 | src: {␊
58 | default:␊
59 | 'https://pbs.twimg.com/profile_images/854537128994275328/nVZX1MEh_400x400.jpg'␊
60 | },␊
61 | size: { default: '64px' },␊
62 | borderWidth: { default: 2 },␊
63 | borderRadius: { default: 9999 },␊
64 | px: { default: 1 },␊
65 | py: { default: 1 },␊
66 | borderColor: { default: 'gray1' },␊
67 | bg: { default: 'transparent' },␊
68 | color: { default: 'transparent' },␊
69 | theme: { default: () => theme }␊
70 | })␊
71 | )`␊
72 | height: ${props => (props.size ? props.size : '48px')},␊
73 | width: ${props => (props.size ? props.size : '48px')}␊
74 | ${space}␊
75 | ${fontSize}␊
76 | ${width}␊
77 | ${color}␊
78 | ${borderWidth}␊
79 | ${borderRadius}␊
80 | ${borderColor}␊
81 | `␊
82 | `,
83 | name: 'Avatar',
84 | },
85 | {
86 | module: `import styled from 'vue-styled-components'␊
87 | import system from 'vue-styled-system'␊
88 | ␊
89 | import { space, fontSize, width, color } from 'styled-system'␊
90 | ␊
91 | import theme from './theme.json'␊
92 | ␊
93 | export default styled(␊
94 | 'button',␊
95 | system({␊
96 | fontSize: { default: 1 },␊
97 | px: { default: 4 },␊
98 | py: { default: 2 },␊
99 | mr: { default: 2 },␊
100 | color: { default: 'white' },␊
101 | bg: { default: 'blue' },␊
102 | theme: { default: () => theme }␊
103 | })␊
104 | )`␊
105 | display: 'inline-block',␊
106 | fontFamily: 'inherit',␊
107 | borderWidth: 0,␊
108 | borderRadius: '4px',␊
109 | appearance: 'none'␊
110 | ${space}␊
111 | ${fontSize}␊
112 | ${width}␊
113 | ${color}␊
114 | ␊
115 | `␊
116 | `,
117 | name: 'Button',
118 | },
119 | {
120 | module: `import styled from 'vue-styled-components'␊
121 | import system from 'vue-styled-system'␊
122 | ␊
123 | import {␊
124 | space,␊
125 | fontSize,␊
126 | width,␊
127 | color,␊
128 | borderWidth,␊
129 | borderColor␊
130 | } from 'styled-system'␊
131 | ␊
132 | import theme from './theme.json'␊
133 | ␊
134 | export default styled(␊
135 | 'button',␊
136 | system({␊
137 | fontSize: { default: 1 },␊
138 | px: { default: 4 },␊
139 | py: { default: 2 },␊
140 | color: { default: 'blue' },␊
141 | bg: { default: 'transparent' },␊
142 | borderWidth: { default: 2 },␊
143 | borderColor: { default: 'currentColor' },␊
144 | theme: { default: () => theme }␊
145 | })␊
146 | )`␊
147 | display: 'inline-block',␊
148 | fontFamily: 'inherit',␊
149 | borderRadius: '4px',␊
150 | appearance: 'none',␊
151 | boxSizing: 'border-box'␊
152 | ${space}␊
153 | ${fontSize}␊
154 | ${width}␊
155 | ${color}␊
156 | ${borderWidth}␊
157 | ${borderColor}␊
158 | `␊
159 | `,
160 | name: 'ButtonOutline',
161 | },
162 | {
163 | module: `import styled from 'vue-styled-components'␊
164 | import system from 'vue-styled-system'␊
165 | ␊
166 | import { space, fontSize, width, color, hover } from 'styled-system'␊
167 | ␊
168 | import theme from './theme.json'␊
169 | ␊
170 | export default styled(␊
171 | 'a',␊
172 | system({␊
173 | color: { default: 'inherit' },␊
174 | hover: {␊
175 | default: () => ({␊
176 | opacity: 0.66,␊
177 | transition: 'opacity .25s ease-in'␊
178 | })␊
179 | },␊
180 | theme: { default: () => theme }␊
181 | })␊
182 | )`␊
183 | textAlign: ${props => (props.center ? 'center' : 'left')},␊
184 | textDecoration: ${props => (props.underline ? 'underline' : 'none')},␊
185 | opacity: 1,␊
186 | transition: 'opacity .3s ease-in',␊
187 | display: 'inline-block'␊
188 | ${space}␊
189 | ${fontSize}␊
190 | ${width}␊
191 | ${color}␊
192 | ${hover}␊
193 | `␊
194 | `,
195 | name: 'Link',
196 | },
197 | {
198 | module: `import styled from 'vue-styled-components'␊
199 | import system from 'vue-styled-system'␊
200 | ␊
201 | import {␊
202 | space,␊
203 | fontSize,␊
204 | width,␊
205 | color,␊
206 | borderWidth,␊
207 | borderColor␊
208 | } from 'styled-system'␊
209 | ␊
210 | import theme from './theme.json'␊
211 | ␊
212 | export default styled(␊
213 | 'a',␊
214 | system({␊
215 | color: { default: 'black' },␊
216 | fontSize: { default: 2 },␊
217 | borderWidth: { default: 1 },␊
218 | borderColor: { default: 'black' },␊
219 | px: { default: 2 },␊
220 | py: { default: 1 },␊
221 | theme: { default: () => theme }␊
222 | })␊
223 | )`␊
224 | textdecoration: 'none' ${space} ${fontSize} ${width} ${color} ${borderWidth}␊
225 | ${borderColor};␊
226 | `␊
227 | `,
228 | name: 'LinkBox',
229 | },
230 | {
231 | module: `import styled from 'vue-styled-components'␊
232 | import system from 'vue-styled-system'␊
233 | ␊
234 | import { space, fontSize, width, color } from 'styled-system'␊
235 | ␊
236 | import theme from './theme.json'␊
237 | ␊
238 | export default styled(␊
239 | 'img',␊
240 | system({␊
241 | theme: { default: () => theme }␊
242 | })␊
243 | )`␊
244 | display: 'block',␊
245 | maxWidth: '100%',␊
246 | width: '100%'␊
247 | ${space}␊
248 | ${fontSize}␊
249 | ${width}␊
250 | ${color}␊
251 | ␊
252 | `␊
253 | `,
254 | name: 'Img',
255 | },
256 | {
257 | module: `import styled from 'vue-styled-components'␊
258 | import system from 'vue-styled-system'␊
259 | ␊
260 | import {␊
261 | space,␊
262 | fontSize,␊
263 | width,␊
264 | color,␊
265 | borderRadius,␊
266 | borderWidth␊
267 | } from 'styled-system'␊
268 | ␊
269 | import theme from './theme.json'␊
270 | ␊
271 | export default styled(␊
272 | 'hr',␊
273 | system({␊
274 | bg: { default: 'transparent' },␊
275 | color: { default: 'black' },␊
276 | pl: { default: 0 },␊
277 | pr: { default: 0 },␊
278 | pb: { default: 0 },␊
279 | borderRadius: { default: 0 },␊
280 | borderWidth: { default: 1 },␊
281 | borderTop: { default: true },␊
282 | theme: { default: () => theme }␊
283 | })␊
284 | )`␊
285 | height: 0 ${space} ${fontSize} ${width} ${color} ${borderRadius}␊
286 | ${borderWidth};␊
287 | `␊
288 | `,
289 | name: 'Hr',
290 | },
291 | {
292 | module: `import styled from 'vue-styled-components'␊
293 | import system from 'vue-styled-system'␊
294 | ␊
295 | import { space, fontSize, width, color } from 'styled-system'␊
296 | ␊
297 | import theme from './theme.json'␊
298 | ␊
299 | export default styled(␊
300 | 'div',␊
301 | system({␊
302 | theme: { default: () => theme }␊
303 | })␊
304 | )`␊
305 | ${space} ${fontSize} ${width} ${color};␊
306 | `␊
307 | `,
308 | name: 'Text',
309 | },
310 | {
311 | module: `import styled from 'vue-styled-components'␊
312 | import system from 'vue-styled-system'␊
313 | ␊
314 | import {␊
315 | space,␊
316 | fontSize,␊
317 | width,␊
318 | color,␊
319 | fontWeight,␊
320 | borderColor,␊
321 | borderWidth␊
322 | } from 'styled-system'␊
323 | ␊
324 | import theme from './theme.json'␊
325 | ␊
326 | export default styled(␊
327 | 'h2',␊
328 | system({␊
329 | fontSize: { default: 4 },␊
330 | m: { default: 0 },␊
331 | fontWeight: { default: '600' },␊
332 | theme: { default: () => theme }␊
333 | })␊
334 | )`␊
335 | ${space} ${fontSize} ${width} ${color} ${fontWeight} ${borderColor} ${borderWidth};␊
336 | `␊
337 | `,
338 | name: 'Heading',
339 | },
340 | {
341 | module: `import styled from 'vue-styled-components'␊
342 | import system from 'vue-styled-system'␊
343 | ␊
344 | import { space, fontSize, width, color } from 'styled-system'␊
345 | ␊
346 | import theme from './theme.json'␊
347 | ␊
348 | export default styled(␊
349 | 'p',␊
350 | system({␊
351 | theme: { default: () => theme }␊
352 | })␊
353 | )`␊
354 | maxWidth: ${props => (props.wide ? '34em' : '28em')},␊
355 | lineHeight: '1.5'␊
356 | ${space}␊
357 | ${fontSize}␊
358 | ${width}␊
359 | ${color}␊
360 | ␊
361 | `␊
362 | `,
363 | name: 'P',
364 | },
365 | {
366 | module: `import styled from 'vue-styled-components'␊
367 | import system from 'vue-styled-system'␊
368 | ␊
369 | import { space, fontSize, width, color, fontWeight } from 'styled-system'␊
370 | ␊
371 | import theme from './theme.json'␊
372 | ␊
373 | export default styled(␊
374 | 'h1',␊
375 | system({␊
376 | fontWeight: { default: '600' },␊
377 | theme: { default: () => theme }␊
378 | })␊
379 | )`␊
380 | textalign: ${props => (props.center ? 'center' : 'left')} ${space} ${fontSize}␊
381 | ${width} ${color} ${fontWeight};␊
382 | `␊
383 | `,
384 | name: 'H1',
385 | },
386 | {
387 | module: `import styled from 'vue-styled-components'␊
388 | import system from 'vue-styled-system'␊
389 | ␊
390 | import { space, fontSize, width, color, fontWeight } from 'styled-system'␊
391 | ␊
392 | import theme from './theme.json'␊
393 | ␊
394 | export default styled(␊
395 | 'h2',␊
396 | system({␊
397 | fontWeight: { default: '600' },␊
398 | theme: { default: () => theme }␊
399 | })␊
400 | )`␊
401 | textalign: ${props => (props.center ? 'center' : 'left')} ${space} ${fontSize}␊
402 | ${width} ${color} ${fontWeight};␊
403 | `␊
404 | `,
405 | name: 'H2',
406 | },
407 | {
408 | module: `import styled from 'vue-styled-components'␊
409 | import system from 'vue-styled-system'␊
410 | ␊
411 | import { space, fontSize, width, color, fontWeight } from 'styled-system'␊
412 | ␊
413 | import theme from './theme.json'␊
414 | ␊
415 | export default styled(␊
416 | 'h3',␊
417 | system({␊
418 | fontWeight: { default: '600' },␊
419 | theme: { default: () => theme }␊
420 | })␊
421 | )`␊
422 | textalign: ${props => (props.center ? 'center' : 'left')} ${space} ${fontSize}␊
423 | ${width} ${color} ${fontWeight};␊
424 | `␊
425 | `,
426 | name: 'H3',
427 | },
428 | {
429 | module: `import styled from 'vue-styled-components'␊
430 | import system from 'vue-styled-system'␊
431 | ␊
432 | import { space, fontSize, width, color, fontWeight } from 'styled-system'␊
433 | ␊
434 | import theme from './theme.json'␊
435 | ␊
436 | export default styled(␊
437 | 'h4',␊
438 | system({␊
439 | fontWeight: { default: '600' },␊
440 | theme: { default: () => theme }␊
441 | })␊
442 | )`␊
443 | textalign: ${props => (props.center ? 'center' : 'left')} ${space} ${fontSize}␊
444 | ${width} ${color} ${fontWeight};␊
445 | `␊
446 | `,
447 | name: 'H4',
448 | },
449 | {
450 | module: `import styled from 'vue-styled-components'␊
451 | import system from 'vue-styled-system'␊
452 | ␊
453 | import { space, fontSize, width, color } from 'styled-system'␊
454 | ␊
455 | import theme from './theme.json'␊
456 | ␊
457 | export default styled(␊
458 | 'div',␊
459 | system({␊
460 | theme: { default: () => theme }␊
461 | })␊
462 | )`␊
463 | ${space} ${fontSize} ${width} ${color};␊
464 | `␊
465 | `,
466 | name: 'Div',
467 | },
468 | {
469 | module: `import styled from 'vue-styled-components'␊
470 | import system from 'vue-styled-system'␊
471 | ␊
472 | import { space, fontSize, width, color } from 'styled-system'␊
473 | ␊
474 | import theme from './theme.json'␊
475 | ␊
476 | export default styled(␊
477 | 'div',␊
478 | system({␊
479 | mx: { default: 'auto' },␊
480 | theme: { default: () => theme }␊
481 | })␊
482 | )`␊
483 | maxWidth: '64em',␊
484 | boxSizing: 'border-box'␊
485 | ${space}␊
486 | ${fontSize}␊
487 | ${width}␊
488 | ${color}␊
489 | ␊
490 | `␊
491 | `,
492 | name: 'Container',
493 | },
494 | {
495 | module: `import styled from 'vue-styled-components'␊
496 | import system from 'vue-styled-system'␊
497 | ␊
498 | import {␊
499 | space,␊
500 | fontSize,␊
501 | width,␊
502 | color,␊
503 | borderColor,␊
504 | borderWidth,␊
505 | focus,␊
506 | borderRadius␊
507 | } from 'styled-system'␊
508 | ␊
509 | import theme from './theme.json'␊
510 | ␊
511 | export default styled(␊
512 | 'input',␊
513 | system({␊
514 | m: { default: 0 },␊
515 | w: { default: 1 },␊
516 | px: { default: 2 },␊
517 | py: { default: 2 },␊
518 | color: { default: 'inherit' },␊
519 | bg: { default: 'transparent' },␊
520 | borderColor: { default: 'gray4' },␊
521 | borderWidth: { default: 1 },␊
522 | fontSize: { default: () => null },␊
523 | focus: {␊
524 | default: () => ({␊
525 | outline: 0␊
526 | })␊
527 | },␊
528 | borderRadius: { default: 2 },␊
529 | theme: { default: () => theme }␊
530 | })␊
531 | )`␊
532 | display: 'block',␊
533 | fontFamily: 'inherit',␊
534 | fontSize: 'inherit'␊
535 | ${space}␊
536 | ${fontSize}␊
537 | ${width}␊
538 | ${color}␊
539 | ${borderColor}␊
540 | ${borderWidth}␊
541 | ${focus}␊
542 | ${borderRadius}␊
543 | `␊
544 | `,
545 | name: 'Input',
546 | },
547 | {
548 | module: `import styled from 'vue-styled-components'␊
549 | import system from 'vue-styled-system'␊
550 | ␊
551 | import { space, fontSize, width, color, fontWeight } from 'styled-system'␊
552 | ␊
553 | import theme from './theme.json'␊
554 | ␊
555 | export default styled(␊
556 | 'label',␊
557 | system({␊
558 | fontSize: { default: 1 },␊
559 | fontWeight: { default: '600' },␊
560 | theme: { default: () => theme }␊
561 | })␊
562 | )`␊
563 | display: 'block' ${space} ${fontSize} ${width} ${color} ${fontWeight};␊
564 | `␊
565 | `,
566 | name: 'Label',
567 | },
568 | {
569 | module: `import Label from './Label'␊
570 | import Div from './Div'␊
571 | import Input from './Input'␊
572 | import P from './P'␊
573 | ␊
574 | export default {␊
575 | name: 'TextInput',␊
576 | props: ['mb', 'label', 'text'],␊
577 | render(h) {␊
578 | return (␊
579 | ␊
580 |
␊
581 | {this.text && (␊
582 |
␊
583 | {this.text}␊
584 |
␊
585 | )}␊
586 |
␊
587 |
␊
588 | )␊
589 | }␊
590 | }␊
591 | `,
592 | name: 'TextInput',
593 | },
594 | {
595 | module: `import styled from 'vue-styled-components'␊
596 | import system from 'vue-styled-system'␊
597 | ␊
598 | import {␊
599 | space,␊
600 | fontSize,␊
601 | width,␊
602 | color,␊
603 | borderColor,␊
604 | borderWidth␊
605 | } from 'styled-system'␊
606 | ␊
607 | import theme from './theme.json'␊
608 | ␊
609 | export default styled(␊
610 | 'ul',␊
611 | system({␊
612 | m: { default: 0 },␊
613 | p: { default: 0 },␊
614 | borderColor: { default: 'transparent' },␊
615 | borderWidth: { default: 1 },␊
616 | theme: { default: () => theme }␊
617 | })␊
618 | )`␊
619 | liststyletype: 'none' ${space} ${fontSize} ${width} ${color} ${borderColor}␊
620 | ${borderWidth};␊
621 | `␊
622 | `,
623 | name: 'Ul',
624 | },
625 | {
626 | module: `import styled from 'vue-styled-components'␊
627 | import system from 'vue-styled-system'␊
628 | ␊
629 | import {␊
630 | space,␊
631 | fontSize,␊
632 | width,␊
633 | color,␊
634 | borderWidth,␊
635 | borderColor␊
636 | } from 'styled-system'␊
637 | ␊
638 | import theme from './theme.json'␊
639 | ␊
640 | export default styled(␊
641 | 'li',␊
642 | system({␊
643 | borderWidth: { default: 1 },␊
644 | borderColor: { default: 'transparent' },␊
645 | theme: { default: () => theme }␊
646 | })␊
647 | )`␊
648 | ${space} ${fontSize} ${width} ${color} ${borderWidth} ${borderColor};␊
649 | `␊
650 | `,
651 | name: 'Li',
652 | },
653 | ]
654 |
655 | ## vue returns a code string for extended components
656 |
657 | > Snapshot 1
658 |
659 | `import styled from 'vue-styled-components'␊
660 | import system from 'vue-styled-system'␊
661 | ␊
662 | import {␊
663 | space,␊
664 | fontSize,␊
665 | width,␊
666 | color,␊
667 | ␊
668 | } from 'styled-system'␊
669 | ␊
670 | import theme from './theme.json'␊
671 | import Div from './Div'␊
672 | export default styled(Div, system({␊
673 | p: { default: 3 },␊
674 | theme: { default: () => theme }␊
675 | }))`␊
676 | ␊
677 | ${space}␊
678 | ${fontSize}␊
679 | ${width}␊
680 | ${color}␊
681 | ␊
682 | `␊
683 | `
684 |
--------------------------------------------------------------------------------
/test/snapshots/vue.js.snap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/c8r/lab-cli/557bc57835fae30cee5465a6ac10633c628560aa/test/snapshots/vue.js.snap
--------------------------------------------------------------------------------
/test/templates.js:
--------------------------------------------------------------------------------
1 | import test from 'ava'
2 | import templates from '../lib/templates'
3 |
4 | const config = {
5 | name: 'Hello',
6 | type: 'h2',
7 | extensionImport: '',
8 | systemFunctions: '',
9 | propsString: `{
10 | p: 2
11 | }`,
12 | styleString: `(props, theme) => ({
13 | fontFamily: 'inherit',
14 | color: props.theme('colors.blue')
15 | })`
16 | }
17 |
18 | const compConfig = {
19 | name: 'Box',
20 | type: 'Div',
21 | propsString: '{}',
22 | styleString: '{}',
23 | extensionImport: `import Div from './Div'`,
24 | systemFunctions: ''
25 | }
26 |
27 | test('styled-components returns a string', t => {
28 | const a = templates['styled-components'](config)
29 | t.is(typeof a, 'string')
30 | t.snapshot(a)
31 | })
32 |
33 | test('styled-components imports required components', t => {
34 | const a = templates['styled-components'](compConfig)
35 | t.is(typeof a, 'string')
36 | t.regex(a, /import\sDiv\sfrom/)
37 | t.snapshot(a)
38 | })
39 |
40 | test('glamorous returns a string', t => {
41 | const a = templates.glamorous(config)
42 | t.is(typeof a, 'string')
43 | t.snapshot(a)
44 | })
45 |
46 | test('glamorous imports required components', t => {
47 | const a = templates.glamorous(compConfig)
48 | t.is(typeof a, 'string')
49 | t.regex(a, /import\sDiv\sfrom/)
50 | t.snapshot(a)
51 | })
52 |
53 | test('emotion returns a string', t => {
54 | const a = templates.emotion(config)
55 | t.is(typeof a, 'string')
56 | t.snapshot(a)
57 | })
58 |
59 | test('emotion imports required components', t => {
60 | const a = templates.emotion(compConfig)
61 | t.is(typeof a, 'string')
62 | t.regex(a, /import\sDiv\sfrom/)
63 | t.snapshot(a)
64 | })
65 |
66 | test('fela returns a string', t => {
67 | const a = templates.fela(config)
68 | t.is(typeof a, 'string')
69 | t.snapshot(a)
70 | })
71 |
72 | test('fela handles styled-system functions', t => {
73 | const a = templates.fela({
74 | name: 'Hello',
75 | type: 'h2',
76 | extensionImport: '',
77 | systemFunctions: 'textAlign,',
78 | system: ['textAlign'],
79 | propsString: '{}',
80 | styleString: '{}'
81 | })
82 | t.is(typeof a, 'string')
83 | t.snapshot(a)
84 | })
85 |
86 | test('fela imports required components', t => {
87 | const a = templates.fela(compConfig)
88 | t.is(typeof a, 'string')
89 | t.regex(a, /import\sDiv\sfrom/)
90 | t.snapshot(a)
91 | })
92 |
93 | test('cxs returns a string', t => {
94 | const a = templates.cxs(config)
95 | t.is(typeof a, 'string')
96 | t.snapshot(a)
97 | })
98 |
99 | test('cxs imports required components', t => {
100 | const a = templates.cxs(compConfig)
101 | t.is(typeof a, 'string')
102 | t.regex(a, /import\sDiv\sfrom/)
103 | t.snapshot(a)
104 | })
105 |
106 | const macro = {
107 | name: 'Hello',
108 | imports: ['Box', 'Text'],
109 | jsx: '{props.children} '
110 | }
111 |
112 | test('composite returns a string', t => {
113 | const a = templates.compositeReact(macro)
114 | t.is(typeof a, 'string')
115 | t.snapshot(a)
116 | })
117 |
118 | test('composite imports required components', t => {
119 | const a = templates.compositeReact(macro)
120 | t.is(typeof a, 'string')
121 | t.regex(a, /import\sBox\sfrom/)
122 | t.regex(a, /import\sText\sfrom/)
123 | t.snapshot(a)
124 | })
125 |
126 | test('composite has defaults', t => {
127 | const a = templates.compositeReact({ name: 'Hello' })
128 | t.snapshot(a)
129 | })
130 |
--------------------------------------------------------------------------------
/test/vue.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import test from 'ava'
3 | import { vue } from '../lib/templates'
4 | import createModules from '../lib'
5 | import fixture from './fixture.json'
6 |
7 | const config = {
8 | name: 'Hello',
9 | type: 'h2',
10 | systemFunctions: '',
11 | extensionImport: '',
12 | props: {
13 | p: 2,
14 | color: 'black'
15 | },
16 | style: {
17 | textDecoration: 'underline'
18 | }
19 | }
20 |
21 | const extConfig = {
22 | name: 'Box',
23 | type: 'Div',
24 | props: {
25 | p: 3
26 | },
27 | style: {},
28 | extensionImport: `import Div from './Div'`,
29 | systemFunctions: ''
30 | }
31 |
32 | test('vue returns a code string for extended components', t => {
33 | const result = vue(extConfig)
34 |
35 | t.is(typeof result, 'string')
36 | t.snapshot(result)
37 | })
38 |
39 | test('vue handles an entire complex library', t => {
40 | const result = createModules(fixture, {
41 | library: 'vue',
42 | harmony: true
43 | })
44 |
45 | t.snapshot(result)
46 | })
47 |
--------------------------------------------------------------------------------