Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: cli error and style bug #3

Merged
merged 1 commit into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ Assuming your React components are in `src/components`, let's create a basic But
font-size: 1rem;
/* ... */

[data-size='lg'] {
&[data-size='lg'] {
font-size: 1.5rem;
/* ... */
}

[data-size='sm'] {
&[data-size='sm'] {
font-size: 0.75rem;
/* ... */
}

[data-danger] {
&[data-danger] {
color: red;
/* ... */
}
Expand All @@ -62,7 +62,7 @@ mistcss src/components/Button.mist.css
Now, you can import your React component.

```tsx
import { Button } from '.components/Button.mist.css'
import { Button } from '.components/Button.mist.css.tsx'

export default function App() {
return (
Expand Down Expand Up @@ -144,7 +144,7 @@ MistCSS creates pure CSS atomic components 🌬️

## Roadmap

MistCSS is a new project, so expect breaking changes until `v1.0`.
MistCSS is a new project, so expect **breaking changes** until `v1.0`.

If you like this idea and want to help, please consider having your company [sponsor](https://github.com/typicode/mistcss) it 🙇. This project is not backed by a large company.

Expand Down
6 changes: 3 additions & 3 deletions fixtures/Button.mist.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
button:scope {
font-size: 1rem;

[data-size='lg'] {
&[data-size='lg'] {
font-size: 1.5rem;
}

[data-size='sm'] {
&[data-size='sm'] {
font-size: 0.75rem;
}

[data-danger] {
&[data-danger] {
color: red;
}
}
Expand Down
2 changes: 1 addition & 1 deletion fixtures/Button.mist.css.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Props = {

export function Button({ children, size, danger, ...props }: Props) {
return (
<button {...props} data-size={size} data-danger={danger}>
<button {...props} className="button" data-size={size} data-danger={danger}>
{children}
</button>
)
Expand Down
17 changes: 13 additions & 4 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { parseArgs } from 'node:util'
import chokidar from 'chokidar'
import { globby } from 'globby'

import { genFile } from './index.js'
import { createFile } from './index.js'

const { values, positionals } = parseArgs({
options: {
Expand All @@ -31,16 +31,25 @@ if (!fs.existsSync(fileOrDir)) {
}

if (fs.statSync(fileOrDir).isFile()) {
genFile(fileOrDir)
createFile(fileOrDir)
} else {
const cwd = fileOrDir || process.cwd()
const filenames = await globby('**/*.mist.css', { cwd })

function handleFile(filename: string) {
try {
createFile(path.join(cwd, filename))
} catch (e) {
console.error(`Error generating ${filename}`)
console.error(e)
}
}

// Watch files
if (values.watch) {
chokidar.watch('**/*.mist.css', { cwd }).on('change', genFile)
chokidar.watch('**/*.mist.css', { cwd }).on('change', handleFile)
}

// Re-generate all files
filenames.forEach((f) => genFile(path.join(cwd, f)))
filenames.forEach(handleFile)
}
3 changes: 3 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void test('parseInput', () => {
const input: string = mistCss
const actual: ParsedInput = parseInput(input)
const expected: ParsedInput = {
className: 'button',
tag: 'button',
data: {
size: ['lg', 'sm'],
Expand All @@ -21,6 +22,8 @@ void test('parseInput', () => {
assert.deepStrictEqual(actual, expected)
})

void test.todo('parseInput with empty input', () => {})

void test('render', () => {
const name = 'Button'
const parsedInput: ParsedInput = parseInput(mistCss)
Expand Down
18 changes: 14 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,32 @@ import fs from 'node:fs'
import path from 'node:path'

export interface ParsedInput {
className: string
tag: string
data: Record<string, string[] | boolean>
}

const classNameRegex = /@scope\s*\(\s*\.(?<className>\w+)\s*\)/
const tagRegex = /(?<tag>\w+):scope/
const enumDataAttributeRegex =
/\[\s*data-(?<attribute>.*?)\s*=\s*["']?(?<value>.*?)["']?\s*\]/g
const booleanDataAttributeRegex = /\[\s*data-(?<attribute>.\w*)\s*\]/g

export function parseInput(input: string): ParsedInput {
const result: ParsedInput = { tag: '', data: {} }
const result: ParsedInput = { className: '', tag: '', data: {} }

// Parse class name
const className = classNameRegex.exec(input)?.groups?.['className']
if (className === undefined) {
throw new Error('Could not parse class name')
}
result.className = className

// Parse tag
const tag = tagRegex.exec(input)?.groups?.['tag']
if (tag === undefined) {
throw new Error('Could not parse tag')
}

result.tag = tag

// Parse enum data attributes
Expand Down Expand Up @@ -80,7 +88,9 @@ export function ${name}({ children, ${Object.keys(parsedInput.data).join(
', ',
)}, ...props }: Props) {
return (
<${parsedInput.tag} {...props} ${Object.keys(parsedInput.data)
<${parsedInput.tag} {...props} className="${parsedInput.className}" ${Object.keys(
parsedInput.data,
)
.map((key) => `data-${key}={${key}}`)
.join(' ')}>
{children}
Expand All @@ -90,7 +100,7 @@ export function ${name}({ children, ${Object.keys(parsedInput.data).join(
`
}

export function genFile(filename: string) {
export function createFile(filename: string) {
let data = fs.readFileSync(filename, 'utf8')
const parsedInput = parseInput(data)
const name = path.basename(filename, '.mist.css')
Expand Down
Loading